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