1 /* 2 * Copyright 2010, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <NetworkInterface.h> 8 9 #include <errno.h> 10 #include <net/if.h> 11 #include <sys/sockio.h> 12 13 #include <AutoDeleter.h> 14 #include <Messenger.h> 15 #include <NetServer.h> 16 #include <RouteSupport.h> 17 18 static int 19 family_from_interface_address(const BNetworkInterfaceAddress& address) 20 { 21 if (address.Address().Family() != AF_UNSPEC) 22 return address.Address().Family(); 23 if (address.Mask().Family() != AF_UNSPEC) 24 return address.Mask().Family(); 25 if (address.Destination().Family() != AF_UNSPEC) 26 return address.Destination().Family(); 27 28 return AF_INET; 29 } 30 31 32 static int 33 family_from_route(const route_entry& route) 34 { 35 if (route.destination != NULL && route.destination->sa_family != AF_UNSPEC) 36 return route.destination->sa_family; 37 if (route.mask != NULL && route.mask->sa_family != AF_UNSPEC) 38 return route.mask->sa_family; 39 if (route.gateway != NULL && route.gateway->sa_family != AF_UNSPEC) 40 return route.gateway->sa_family; 41 if (route.source != NULL && route.source->sa_family != AF_UNSPEC) 42 return route.source->sa_family; 43 44 return AF_UNSPEC; 45 } 46 47 48 static status_t 49 do_ifaliasreq(const char* name, int32 option, BNetworkInterfaceAddress& address, 50 bool readBack = false) 51 { 52 int family = AF_INET; 53 if (!readBack) 54 family = family_from_interface_address(address); 55 56 int socket = ::socket(family, SOCK_DGRAM, 0); 57 if (socket < 0) 58 return errno; 59 60 FileDescriptorCloser closer(socket); 61 62 ifaliasreq request; 63 strlcpy(request.ifra_name, name, IF_NAMESIZE); 64 request.ifra_index = address.Index(); 65 request.ifra_flags = address.Flags(); 66 67 memcpy(&request.ifra_addr, &address.Address().SockAddr(), 68 address.Address().Length()); 69 memcpy(&request.ifra_mask, &address.Mask().SockAddr(), 70 address.Mask().Length()); 71 memcpy(&request.ifra_broadaddr, &address.Broadcast().SockAddr(), 72 address.Broadcast().Length()); 73 74 if (ioctl(socket, option, &request, sizeof(struct ifaliasreq)) < 0) 75 return errno; 76 77 if (readBack) { 78 address.SetFlags(request.ifra_flags); 79 address.Address().SetTo(request.ifra_addr); 80 address.Mask().SetTo(request.ifra_mask); 81 address.Broadcast().SetTo(request.ifra_broadaddr); 82 } 83 84 return B_OK; 85 } 86 87 88 static status_t 89 do_ifaliasreq(const char* name, int32 option, 90 const BNetworkInterfaceAddress& address) 91 { 92 return do_ifaliasreq(name, option, 93 const_cast<BNetworkInterfaceAddress&>(address)); 94 } 95 96 97 template<typename T> status_t 98 do_request(int family, T& request, const char* name, int option) 99 { 100 int socket = ::socket(family, SOCK_DGRAM, 0); 101 if (socket < 0) 102 return errno; 103 104 FileDescriptorCloser closer(socket); 105 106 strlcpy(((struct ifreq&)request).ifr_name, name, IF_NAMESIZE); 107 108 if (ioctl(socket, option, &request, sizeof(T)) < 0) 109 return errno; 110 111 return B_OK; 112 } 113 114 115 // #pragma mark - 116 117 118 BNetworkInterfaceAddress::BNetworkInterfaceAddress() 119 : 120 fIndex(-1), 121 fFlags(0) 122 { 123 } 124 125 126 BNetworkInterfaceAddress::~BNetworkInterfaceAddress() 127 { 128 } 129 130 131 status_t 132 BNetworkInterfaceAddress::SetTo(const BNetworkInterface& interface, int32 index) 133 { 134 fIndex = index; 135 return do_ifaliasreq(interface.Name(), B_SOCKET_GET_ALIAS, *this, true); 136 } 137 138 139 void 140 BNetworkInterfaceAddress::SetAddress(const BNetworkAddress& address) 141 { 142 fAddress = address; 143 } 144 145 146 void 147 BNetworkInterfaceAddress::SetMask(const BNetworkAddress& mask) 148 { 149 fMask = mask; 150 } 151 152 153 void 154 BNetworkInterfaceAddress::SetBroadcast(const BNetworkAddress& broadcast) 155 { 156 fBroadcast = broadcast; 157 } 158 159 160 void 161 BNetworkInterfaceAddress::SetDestination(const BNetworkAddress& destination) 162 { 163 fBroadcast = destination; 164 } 165 166 167 void 168 BNetworkInterfaceAddress::SetFlags(uint32 flags) 169 { 170 fFlags = flags; 171 } 172 173 174 // #pragma mark - 175 176 177 BNetworkInterface::BNetworkInterface() 178 { 179 Unset(); 180 } 181 182 183 BNetworkInterface::BNetworkInterface(const char* name) 184 { 185 SetTo(name); 186 } 187 188 189 BNetworkInterface::BNetworkInterface(uint32 index) 190 { 191 SetTo(index); 192 } 193 194 195 BNetworkInterface::~BNetworkInterface() 196 { 197 } 198 199 200 void 201 BNetworkInterface::Unset() 202 { 203 fName[0] = '\0'; 204 } 205 206 207 void 208 BNetworkInterface::SetTo(const char* name) 209 { 210 strlcpy(fName, name, IF_NAMESIZE); 211 } 212 213 214 status_t 215 BNetworkInterface::SetTo(uint32 index) 216 { 217 ifreq request; 218 request.ifr_index = index; 219 220 status_t status = do_request(AF_INET, request, "", SIOCGIFNAME); 221 if (status != B_OK) 222 return status; 223 224 strlcpy(fName, request.ifr_name, IF_NAMESIZE); 225 return B_OK; 226 } 227 228 229 bool 230 BNetworkInterface::Exists() const 231 { 232 ifreq request; 233 return do_request(AF_INET, request, Name(), SIOCGIFINDEX) == B_OK; 234 } 235 236 237 const char* 238 BNetworkInterface::Name() const 239 { 240 return fName; 241 } 242 243 244 uint32 245 BNetworkInterface::Index() const 246 { 247 ifreq request; 248 if (do_request(AF_INET, request, Name(), SIOCGIFINDEX) != B_OK) 249 return 0; 250 251 return request.ifr_index; 252 } 253 254 255 uint32 256 BNetworkInterface::Flags() const 257 { 258 ifreq request; 259 if (do_request(AF_INET, request, Name(), SIOCGIFFLAGS) != B_OK) 260 return 0; 261 262 return request.ifr_flags; 263 } 264 265 266 uint32 267 BNetworkInterface::MTU() const 268 { 269 ifreq request; 270 if (do_request(AF_INET, request, Name(), SIOCGIFMTU) != B_OK) 271 return 0; 272 273 return request.ifr_mtu; 274 } 275 276 277 int32 278 BNetworkInterface::Media() const 279 { 280 ifmediareq request; 281 request.ifm_count = 0; 282 request.ifm_ulist = NULL; 283 284 if (do_request(AF_INET, request, Name(), SIOCGIFMEDIA) != B_OK) 285 return -1; 286 287 return request.ifm_current; 288 } 289 290 291 uint32 292 BNetworkInterface::Metric() const 293 { 294 ifreq request; 295 if (do_request(AF_INET, request, Name(), SIOCGIFMETRIC) != B_OK) 296 return 0; 297 298 return request.ifr_metric; 299 } 300 301 302 uint32 303 BNetworkInterface::Type() const 304 { 305 ifreq request; 306 if (do_request(AF_INET, request, Name(), SIOCGIFTYPE) != B_OK) 307 return 0; 308 309 return request.ifr_type; 310 } 311 312 313 status_t 314 BNetworkInterface::GetStats(ifreq_stats& stats) 315 { 316 ifreq request; 317 status_t status = do_request(AF_INET, request, Name(), SIOCGIFSTATS); 318 if (status != B_OK) 319 return status; 320 321 memcpy(&stats, &request.ifr_stats, sizeof(ifreq_stats)); 322 return B_OK; 323 } 324 325 326 bool 327 BNetworkInterface::HasLink() const 328 { 329 return (Flags() & IFF_LINK) != 0; 330 } 331 332 333 status_t 334 BNetworkInterface::SetFlags(uint32 flags) 335 { 336 ifreq request; 337 request.ifr_flags = flags; 338 return do_request(AF_INET, request, Name(), SIOCSIFFLAGS); 339 } 340 341 342 status_t 343 BNetworkInterface::SetMTU(uint32 mtu) 344 { 345 ifreq request; 346 request.ifr_mtu = mtu; 347 return do_request(AF_INET, request, Name(), SIOCSIFMTU); 348 } 349 350 351 status_t 352 BNetworkInterface::SetMedia(int32 media) 353 { 354 ifreq request; 355 request.ifr_media = media; 356 return do_request(AF_INET, request, Name(), SIOCSIFMEDIA); 357 } 358 359 360 status_t 361 BNetworkInterface::SetMetric(uint32 metric) 362 { 363 ifreq request; 364 request.ifr_metric = metric; 365 return do_request(AF_INET, request, Name(), SIOCSIFMETRIC); 366 } 367 368 369 int32 370 BNetworkInterface::CountAddresses() const 371 { 372 ifreq request; 373 if (do_request(AF_INET, request, Name(), B_SOCKET_COUNT_ALIASES) != B_OK) 374 return 0; 375 376 return request.ifr_count; 377 } 378 379 380 status_t 381 BNetworkInterface::GetAddressAt(int32 index, BNetworkInterfaceAddress& address) 382 { 383 return address.SetTo(*this, index); 384 } 385 386 387 int32 388 BNetworkInterface::FindAddress(const BNetworkAddress& address) 389 { 390 int socket = ::socket(address.Family(), SOCK_DGRAM, 0); 391 if (socket < 0) 392 return -1; 393 394 FileDescriptorCloser closer(socket); 395 396 ifaliasreq request; 397 memset(&request, 0, sizeof(ifaliasreq)); 398 399 strlcpy(request.ifra_name, Name(), IF_NAMESIZE); 400 request.ifra_index = -1; 401 memcpy(&request.ifra_addr, &address.SockAddr(), address.Length()); 402 403 if (ioctl(socket, B_SOCKET_GET_ALIAS, &request, sizeof(struct ifaliasreq)) 404 < 0) { 405 return -1; 406 } 407 408 return request.ifra_index; 409 } 410 411 412 int32 413 BNetworkInterface::FindFirstAddress(int family) 414 { 415 int socket = ::socket(family, SOCK_DGRAM, 0); 416 if (socket < 0) 417 return -1; 418 419 FileDescriptorCloser closer(socket); 420 421 ifaliasreq request; 422 memset(&request, 0, sizeof(ifaliasreq)); 423 424 strlcpy(request.ifra_name, Name(), IF_NAMESIZE); 425 request.ifra_index = -1; 426 request.ifra_addr.ss_family = AF_UNSPEC; 427 428 if (ioctl(socket, B_SOCKET_GET_ALIAS, &request, sizeof(struct ifaliasreq)) 429 < 0) { 430 return -1; 431 } 432 433 return request.ifra_index; 434 } 435 436 437 status_t 438 BNetworkInterface::AddAddress(const BNetworkInterfaceAddress& address) 439 { 440 return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address); 441 } 442 443 444 status_t 445 BNetworkInterface::AddAddress(const BNetworkAddress& local) 446 { 447 BNetworkInterfaceAddress address; 448 address.SetAddress(local); 449 450 return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address); 451 } 452 453 454 status_t 455 BNetworkInterface::SetAddress(const BNetworkInterfaceAddress& address) 456 { 457 return do_ifaliasreq(Name(), B_SOCKET_SET_ALIAS, address); 458 } 459 460 461 status_t 462 BNetworkInterface::RemoveAddress(const BNetworkInterfaceAddress& address) 463 { 464 ifreq request; 465 memcpy(&request.ifr_addr, &address.Address().SockAddr(), 466 address.Address().Length()); 467 468 return do_request(family_from_interface_address(address), request, Name(), 469 B_SOCKET_REMOVE_ALIAS); 470 } 471 472 473 status_t 474 BNetworkInterface::RemoveAddress(const BNetworkAddress& address) 475 { 476 ifreq request; 477 memcpy(&request.ifr_addr, &address.SockAddr(), address.Length()); 478 479 return do_request(address.Family(), request, Name(), B_SOCKET_REMOVE_ALIAS); 480 } 481 482 483 status_t 484 BNetworkInterface::RemoveAddressAt(int32 index) 485 { 486 BNetworkInterfaceAddress address; 487 status_t status = GetAddressAt(index, address); 488 if (status != B_OK) 489 return status; 490 491 return RemoveAddress(address); 492 } 493 494 495 status_t 496 BNetworkInterface::GetHardwareAddress(BNetworkAddress& address) 497 { 498 int socket = ::socket(AF_LINK, SOCK_DGRAM, 0); 499 if (socket < 0) 500 return errno; 501 502 FileDescriptorCloser closer(socket); 503 504 ifreq request; 505 strlcpy(request.ifr_name, Name(), IF_NAMESIZE); 506 507 if (ioctl(socket, SIOCGIFADDR, &request, sizeof(struct ifreq)) < 0) 508 return errno; 509 510 address.SetTo(request.ifr_addr); 511 return B_OK; 512 } 513 514 515 status_t 516 BNetworkInterface::AddRoute(const route_entry& route) 517 { 518 int family = family_from_route(route); 519 if (family == AF_UNSPEC) 520 return B_BAD_VALUE; 521 522 ifreq request; 523 request.ifr_route = route; 524 return do_request(family, request, Name(), SIOCADDRT); 525 } 526 527 528 status_t 529 BNetworkInterface::AddDefaultRoute(const BNetworkAddress& gateway) 530 { 531 route_entry route; 532 memset(&route, 0, sizeof(route_entry)); 533 route.flags = RTF_STATIC | RTF_DEFAULT | RTF_GATEWAY; 534 route.gateway = const_cast<sockaddr*>(&gateway.SockAddr()); 535 536 return AddRoute(route); 537 } 538 539 540 status_t 541 BNetworkInterface::RemoveRoute(const route_entry& route) 542 { 543 int family = family_from_route(route); 544 if (family == AF_UNSPEC) 545 return B_BAD_VALUE; 546 547 return RemoveRoute(family, route); 548 } 549 550 551 status_t 552 BNetworkInterface::RemoveRoute(int family, const route_entry& route) 553 { 554 ifreq request; 555 request.ifr_route = route; 556 return do_request(family, request, Name(), SIOCDELRT); 557 } 558 559 560 status_t 561 BNetworkInterface::RemoveDefaultRoute(int family) 562 { 563 route_entry route; 564 memset(&route, 0, sizeof(route_entry)); 565 route.flags = RTF_STATIC | RTF_DEFAULT; 566 567 return RemoveRoute(family, route); 568 } 569 570 571 status_t 572 BNetworkInterface::GetRoutes(int family, BObjectList<route_entry>& routes) const 573 { 574 return BPrivate::get_routes(Name(), family, routes); 575 } 576 577 578 status_t 579 BNetworkInterface::GetDefaultRoute(int family, BNetworkAddress& gateway) const 580 { 581 BObjectList<route_entry> routes(1, true); 582 status_t status = GetRoutes(family, routes); 583 if (status != B_OK) 584 return status; 585 586 for (int32 i = routes.CountItems() - 1; i >= 0; i--) { 587 route_entry* entry = routes.ItemAt(i); 588 if (entry->flags & RTF_DEFAULT) { 589 gateway.SetTo(*entry->gateway); 590 break; 591 } 592 } 593 594 return B_OK; 595 } 596 597 598 status_t 599 BNetworkInterface::AutoConfigure(int family) 600 { 601 BMessage message(kMsgConfigureInterface); 602 message.AddString("device", Name()); 603 604 BMessage address; 605 address.AddInt32("family", family); 606 address.AddBool("auto_config", true); 607 message.AddMessage("address", &address); 608 609 BMessenger networkServer(kNetServerSignature); 610 BMessage reply; 611 status_t status = networkServer.SendMessage(&message, &reply); 612 if (status == B_OK) 613 reply.FindInt32("status", &status); 614 615 return status; 616 } 617