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 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 return request.ifra_index; 408 } 409 410 411 int32 412 BNetworkInterface::FindFirstAddress(int family) 413 { 414 int socket = ::socket(family, SOCK_DGRAM, 0); 415 if (socket < 0) 416 return -1; 417 418 FileDescriptorCloser closer(socket); 419 420 ifaliasreq request; 421 memset(&request, 0, sizeof(ifaliasreq)); 422 423 strlcpy(request.ifra_name, Name(), IF_NAMESIZE); 424 request.ifra_index = -1; 425 request.ifra_addr.ss_family = AF_UNSPEC; 426 427 if (ioctl(socket, B_SOCKET_GET_ALIAS, &request, sizeof(struct ifaliasreq)) 428 < 0) 429 return -1; 430 431 return request.ifra_index; 432 } 433 434 435 status_t 436 BNetworkInterface::AddAddress(const BNetworkInterfaceAddress& address) 437 { 438 return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address); 439 } 440 441 442 status_t 443 BNetworkInterface::AddAddress(const BNetworkAddress& local) 444 { 445 BNetworkInterfaceAddress address; 446 address.SetAddress(local); 447 448 return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address); 449 } 450 451 452 status_t 453 BNetworkInterface::SetAddress(const BNetworkInterfaceAddress& address) 454 { 455 return do_ifaliasreq(Name(), B_SOCKET_SET_ALIAS, address); 456 } 457 458 459 status_t 460 BNetworkInterface::RemoveAddress(const BNetworkInterfaceAddress& address) 461 { 462 ifreq request; 463 memcpy(&request.ifr_addr, &address.Address().SockAddr(), 464 address.Address().Length()); 465 466 return do_request(family_from_interface_address(address), request, Name(), 467 B_SOCKET_REMOVE_ALIAS); 468 } 469 470 471 status_t 472 BNetworkInterface::RemoveAddress(const BNetworkAddress& address) 473 { 474 ifreq request; 475 memcpy(&request.ifr_addr, &address.SockAddr(), address.Length()); 476 477 return do_request(address.Family(), request, Name(), B_SOCKET_REMOVE_ALIAS); 478 } 479 480 481 status_t 482 BNetworkInterface::RemoveAddressAt(int32 index) 483 { 484 BNetworkInterfaceAddress address; 485 status_t status = GetAddressAt(index, address); 486 if (status != B_OK) 487 return status; 488 489 return RemoveAddress(address); 490 } 491 492 493 status_t 494 BNetworkInterface::GetHardwareAddress(BNetworkAddress& address) 495 { 496 int socket = ::socket(AF_LINK, SOCK_DGRAM, 0); 497 if (socket < 0) 498 return errno; 499 500 FileDescriptorCloser closer(socket); 501 502 ifreq request; 503 strlcpy(request.ifr_name, Name(), IF_NAMESIZE); 504 505 if (ioctl(socket, SIOCGIFADDR, &request, sizeof(struct ifreq)) < 0) 506 return errno; 507 508 address.SetTo(request.ifr_addr); 509 return B_OK; 510 } 511 512 513 status_t 514 BNetworkInterface::AddRoute(const route_entry& route) 515 { 516 int family = family_from_route(route); 517 if (family == AF_UNSPEC) 518 return B_BAD_VALUE; 519 520 ifreq request; 521 request.ifr_route = route; 522 return do_request(family, request, Name(), SIOCADDRT); 523 } 524 525 526 status_t 527 BNetworkInterface::AddDefaultRoute(const BNetworkAddress& gateway) 528 { 529 route_entry route; 530 memset(&route, 0, sizeof(route_entry)); 531 route.flags = RTF_STATIC | RTF_DEFAULT | RTF_GATEWAY; 532 route.gateway = const_cast<sockaddr*>(&gateway.SockAddr()); 533 534 return AddRoute(route); 535 } 536 537 538 status_t 539 BNetworkInterface::RemoveRoute(const route_entry& route) 540 { 541 int family = family_from_route(route); 542 if (family == AF_UNSPEC) 543 return B_BAD_VALUE; 544 545 return RemoveRoute(family, route); 546 } 547 548 549 status_t 550 BNetworkInterface::RemoveRoute(int family, const route_entry& route) 551 { 552 ifreq request; 553 request.ifr_route = route; 554 return do_request(family, request, Name(), SIOCDELRT); 555 } 556 557 558 status_t 559 BNetworkInterface::RemoveDefaultRoute(int family) 560 { 561 route_entry route; 562 memset(&route, 0, sizeof(route_entry)); 563 route.flags = RTF_STATIC | RTF_DEFAULT; 564 565 return RemoveRoute(family, route); 566 } 567 568 569 status_t 570 BNetworkInterface::AutoConfigure(int family) 571 { 572 BMessage message(kMsgConfigureInterface); 573 message.AddString("device", Name()); 574 575 BMessage address; 576 address.AddInt32("family", family); 577 address.AddBool("auto_config", true); 578 message.AddMessage("address", &address); 579 580 BMessenger networkServer(kNetServerSignature); 581 BMessage reply; 582 status_t status = networkServer.SendMessage(&message, &reply); 583 if (status == B_OK) 584 reply.FindInt32("status", &status); 585 586 return status; 587 } 588