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