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