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 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 268 uint32 269 BNetworkInterface::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 279 uint32 280 BNetworkInterface::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 290 status_t 291 BNetworkInterface::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 303 bool 304 BNetworkInterface::HasLink() const 305 { 306 return (Flags() & IFF_LINK) != 0; 307 } 308 309 310 status_t 311 BNetworkInterface::SetFlags(uint32 flags) 312 { 313 ifreq request; 314 request.ifr_flags = flags; 315 return do_request(AF_INET, request, Name(), SIOCSIFFLAGS); 316 } 317 318 319 status_t 320 BNetworkInterface::SetMTU(uint32 mtu) 321 { 322 ifreq request; 323 request.ifr_mtu = mtu; 324 return do_request(AF_INET, request, Name(), SIOCSIFMTU); 325 } 326 327 328 status_t 329 BNetworkInterface::SetMedia(int32 media) 330 { 331 ifreq request; 332 request.ifr_media = media; 333 return do_request(AF_INET, request, Name(), SIOCSIFMEDIA); 334 } 335 336 337 status_t 338 BNetworkInterface::SetMetric(uint32 metric) 339 { 340 ifreq request; 341 request.ifr_metric = metric; 342 return do_request(AF_INET, request, Name(), SIOCSIFMETRIC); 343 } 344 345 346 int32 347 BNetworkInterface::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 357 status_t 358 BNetworkInterface::GetAddressAt(int32 index, BNetworkInterfaceAddress& address) 359 { 360 return address.SetTo(*this, index); 361 } 362 363 364 int32 365 BNetworkInterface::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 387 int32 388 BNetworkInterface::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 410 status_t 411 BNetworkInterface::AddAddress(const BNetworkInterfaceAddress& address) 412 { 413 return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address); 414 } 415 416 417 status_t 418 BNetworkInterface::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 427 status_t 428 BNetworkInterface::SetAddress(const BNetworkInterfaceAddress& address) 429 { 430 return do_ifaliasreq(Name(), B_SOCKET_SET_ALIAS, address); 431 } 432 433 434 status_t 435 BNetworkInterface::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 446 status_t 447 BNetworkInterface::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 456 status_t 457 BNetworkInterface::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 468 status_t 469 BNetworkInterface::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 486 status_t 487 BNetworkInterface::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 499 status_t 500 BNetworkInterface::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 512 status_t 513 BNetworkInterface::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 523 status_t 524 BNetworkInterface::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 532 status_t 533 BNetworkInterface::RemoveDefaultRoute(int family) 534 { 535 BNetworkRoute route; 536 route.SetFlags(RTF_STATIC | RTF_DEFAULT); 537 return RemoveRoute(family, route); 538 } 539 540 541 status_t 542 BNetworkInterface::GetRoutes(int family, 543 BObjectList<BNetworkRoute>& routes) const 544 { 545 return BNetworkRoute::GetRoutes(family, Name(), routes); 546 } 547 548 549 status_t 550 BNetworkInterface::GetDefaultRoute(int family, BNetworkRoute& route) const 551 { 552 return BNetworkRoute::GetDefaultRoute(family, Name(), route); 553 } 554 555 556 status_t 557 BNetworkInterface::GetDefaultGateway(int family, BNetworkAddress& gateway) const 558 { 559 return BNetworkRoute::GetDefaultGateway(family, Name(), gateway); 560 } 561 562 563 status_t 564 BNetworkInterface::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