1 /* 2 * Copyright 2006-2011, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "interfaces.h" 11 12 #include <net/if_dl.h> 13 #include <new> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <sys/sockio.h> 18 19 #include <KernelExport.h> 20 21 #include <net_device.h> 22 #include <NetUtilities.h> 23 24 #include "device_interfaces.h" 25 #include "domains.h" 26 #include "stack_private.h" 27 #include "utility.h" 28 29 30 //#define TRACE_INTERFACES 31 #ifdef TRACE_INTERFACES 32 # define TRACE(x...) dprintf(STACK_DEBUG_PREFIX x) 33 #else 34 # define TRACE(x...) ; 35 #endif 36 37 38 struct AddressHashDefinition { 39 typedef const sockaddr* KeyType; 40 typedef InterfaceAddress ValueType; 41 42 AddressHashDefinition() 43 { 44 } 45 46 size_t HashKey(const KeyType& key) const 47 { 48 net_domain* domain = get_domain(key->sa_family); 49 if (domain == NULL) 50 return 0; 51 52 return domain->address_module->hash_address(key, false); 53 } 54 55 size_t Hash(InterfaceAddress* address) const 56 { 57 return address->domain->address_module->hash_address(address->local, 58 false); 59 } 60 61 bool Compare(const KeyType& key, InterfaceAddress* address) const 62 { 63 if (address->local == NULL) 64 return key->sa_family == AF_UNSPEC; 65 66 if (address->local->sa_family != key->sa_family) 67 return false; 68 69 return address->domain->address_module->equal_addresses(key, 70 address->local); 71 } 72 73 InterfaceAddress*& GetLink(InterfaceAddress* address) const 74 { 75 return address->HashTableLink(); 76 } 77 }; 78 79 typedef BOpenHashTable<AddressHashDefinition, true, false> AddressTable; 80 81 82 static mutex sLock; 83 static InterfaceList sInterfaces; 84 static mutex sHashLock; 85 static AddressTable sAddressTable; 86 static uint32 sInterfaceIndex; 87 88 89 #if 0 90 //! For debugging purposes only 91 void 92 dump_interface_refs(void) 93 { 94 MutexLocker locker(sLock); 95 96 InterfaceList::Iterator iterator = sInterfaces.GetIterator(); 97 while (Interface* interface = iterator.Next()) { 98 dprintf("%p: %s, %ld\n", interface, interface->name, 99 interface->CountReferences()); 100 } 101 } 102 #endif 103 104 105 #if ENABLE_DEBUGGER_COMMANDS 106 107 108 static int 109 dump_interface(int argc, char** argv) 110 { 111 if (argc != 2) { 112 kprintf("usage: %s [name|address]\n", argv[0]); 113 return 0; 114 } 115 116 Interface* interface = NULL; 117 118 InterfaceList::Iterator iterator = sInterfaces.GetIterator(); 119 while ((interface = iterator.Next()) != NULL) { 120 if (!strcmp(argv[1], interface->name)) 121 break; 122 } 123 124 if (interface == NULL) 125 interface = (Interface*)parse_expression(argv[1]); 126 127 interface->Dump(); 128 129 return 0; 130 } 131 132 133 static int 134 dump_interfaces(int argc, char** argv) 135 { 136 InterfaceList::Iterator iterator = sInterfaces.GetIterator(); 137 while (Interface* interface = iterator.Next()) { 138 kprintf("%p %s\n", interface, interface->name); 139 } 140 return 0; 141 } 142 143 144 static int 145 dump_local(int argc, char** argv) 146 { 147 AddressTable::Iterator iterator = sAddressTable.GetIterator(); 148 size_t i = 0; 149 while (InterfaceAddress* address = iterator.Next()) { 150 address->Dump(++i); 151 dprintf(" hash: %lu\n", 152 address->domain->address_module->hash_address(address->local, 153 false)); 154 } 155 return 0; 156 } 157 158 159 static int 160 dump_route(int argc, char** argv) 161 { 162 if (argc != 2) { 163 kprintf("usage: %s [address]\n", argv[0]); 164 return 0; 165 } 166 167 net_route* route = (net_route*)parse_expression(argv[1]); 168 kprintf("destination: %p\n", route->destination); 169 kprintf("mask: %p\n", route->mask); 170 kprintf("gateway: %p\n", route->gateway); 171 kprintf("flags: %" B_PRIx32 "\n", route->flags); 172 kprintf("mtu: %" B_PRIu32 "\n", route->mtu); 173 kprintf("interface address: %p\n", route->interface_address); 174 175 if (route->interface_address != NULL) { 176 ((InterfaceAddress*)route->interface_address)->Dump(); 177 } 178 179 return 0; 180 } 181 182 183 #endif // ENABLE_DEBUGGER_COMMANDS 184 185 186 InterfaceAddress::InterfaceAddress() 187 { 188 _Init(NULL, NULL); 189 } 190 191 192 InterfaceAddress::InterfaceAddress(net_interface* netInterface, 193 net_domain* netDomain) 194 { 195 _Init(netInterface, netDomain); 196 } 197 198 199 InterfaceAddress::~InterfaceAddress() 200 { 201 TRACE("InterfaceAddress %p: destructor\n", this); 202 203 if (interface != NULL && (flags & IFAF_DIRECT_ADDRESS) == 0) 204 ((Interface*)interface)->ReleaseReference(); 205 } 206 207 208 status_t 209 InterfaceAddress::SetTo(const ifaliasreq& request) 210 { 211 status_t status = SetLocal((const sockaddr*)&request.ifra_addr); 212 if (status == B_OK) 213 status = SetDestination((const sockaddr*)&request.ifra_broadaddr); 214 if (status == B_OK) 215 status = SetMask((const sockaddr*)&request.ifra_mask); 216 217 return status; 218 } 219 220 221 status_t 222 InterfaceAddress::SetLocal(const sockaddr* to) 223 { 224 return Set(&local, to); 225 } 226 227 228 status_t 229 InterfaceAddress::SetDestination(const sockaddr* to) 230 { 231 return Set(&destination, to); 232 } 233 234 235 status_t 236 InterfaceAddress::SetMask(const sockaddr* to) 237 { 238 return Set(&mask, to); 239 } 240 241 242 sockaddr** 243 InterfaceAddress::AddressFor(int32 option) 244 { 245 switch (option) { 246 case SIOCSIFADDR: 247 case SIOCGIFADDR: 248 case SIOCDIFADDR: 249 return &local; 250 251 case SIOCSIFNETMASK: 252 case SIOCGIFNETMASK: 253 return &mask; 254 255 case SIOCSIFBRDADDR: 256 case SIOCSIFDSTADDR: 257 case SIOCGIFBRDADDR: 258 case SIOCGIFDSTADDR: 259 return &destination; 260 261 default: 262 return NULL; 263 } 264 } 265 266 267 /*! Adds the default routes that every interface address needs, ie. the local 268 host route, and one for the subnet (if set). 269 */ 270 void 271 InterfaceAddress::AddDefaultRoutes(int32 option) 272 { 273 net_route route; 274 route.destination = local; 275 route.gateway = NULL; 276 route.interface_address = this; 277 278 if (mask != NULL && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) { 279 route.mask = mask; 280 route.flags = 0; 281 add_route(domain, &route); 282 } 283 284 if (option == SIOCSIFADDR) { 285 route.mask = NULL; 286 route.flags = RTF_LOCAL | RTF_HOST; 287 add_route(domain, &route); 288 } 289 } 290 291 292 /*! Removes the default routes as set by AddDefaultRoutes() again. */ 293 void 294 InterfaceAddress::RemoveDefaultRoutes(int32 option) 295 { 296 net_route route; 297 route.destination = local; 298 route.gateway = NULL; 299 route.interface_address = this; 300 301 if (mask != NULL && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) { 302 route.mask = mask; 303 route.flags = 0; 304 remove_route(domain, &route); 305 } 306 307 if (option == SIOCSIFADDR) { 308 route.mask = NULL; 309 route.flags = RTF_LOCAL | RTF_HOST; 310 remove_route(domain, &route); 311 } 312 } 313 314 315 bool 316 InterfaceAddress::LocalIsDefined() const 317 { 318 return local != NULL && local->sa_family != AF_UNSPEC; 319 } 320 321 322 #if ENABLE_DEBUGGER_COMMANDS 323 324 325 void 326 InterfaceAddress::Dump(size_t index, bool hideInterface) 327 { 328 if (index) 329 kprintf("%2zu. ", index); 330 else 331 kprintf(" "); 332 333 if (!hideInterface) { 334 kprintf("interface: %p (%s)\n ", interface, 335 interface != NULL ? interface->name : "-"); 336 } 337 338 kprintf("domain: %p (family %u)\n", domain, 339 domain != NULL ? domain->family : AF_UNSPEC); 340 341 char buffer[64]; 342 if (local != NULL && domain != NULL) { 343 domain->address_module->print_address_buffer(local, buffer, 344 sizeof(buffer), false); 345 } else 346 strcpy(buffer, "-"); 347 kprintf(" local: %s\n", buffer); 348 349 if (mask != NULL && domain != NULL) { 350 domain->address_module->print_address_buffer(mask, buffer, 351 sizeof(buffer), false); 352 } else 353 strcpy(buffer, "-"); 354 kprintf(" mask: %s\n", buffer); 355 356 if (destination != NULL && domain != NULL) { 357 domain->address_module->print_address_buffer(destination, buffer, 358 sizeof(buffer), false); 359 } else 360 strcpy(buffer, "-"); 361 kprintf(" destination: %s\n", buffer); 362 363 kprintf(" ref count: %" B_PRId32 "\n", CountReferences()); 364 } 365 366 367 #endif // ENABLE_DEBUGGER_COMMANDS 368 369 370 /*static*/ status_t 371 InterfaceAddress::Set(sockaddr** _address, const sockaddr* to) 372 { 373 sockaddr* address = *_address; 374 375 if (to == NULL || to->sa_family == AF_UNSPEC) { 376 // Clear address 377 free(address); 378 *_address = NULL; 379 return B_OK; 380 } 381 382 // Set address 383 384 size_t size = max_c(to->sa_len, sizeof(sockaddr)); 385 if (size > sizeof(sockaddr_storage)) 386 size = sizeof(sockaddr_storage); 387 388 address = Prepare(_address, size); 389 if (address == NULL) 390 return B_NO_MEMORY; 391 392 memcpy(address, to, size); 393 address->sa_len = size; 394 395 return B_OK; 396 } 397 398 399 /*! Makes sure that the sockaddr object pointed to by \a _address is large 400 enough to hold \a size bytes. 401 \a _address may point to NULL when calling this method. 402 */ 403 /*static*/ sockaddr* 404 InterfaceAddress::Prepare(sockaddr** _address, size_t size) 405 { 406 size = max_c(size, sizeof(sockaddr)); 407 if (size > sizeof(sockaddr_storage)) 408 size = sizeof(sockaddr_storage); 409 410 sockaddr* address = *_address; 411 412 if (address == NULL || size > address->sa_len) { 413 address = (sockaddr*)realloc(address, size); 414 if (address == NULL) 415 return NULL; 416 } 417 418 address->sa_len = size; 419 420 *_address = address; 421 return address; 422 } 423 424 425 void 426 InterfaceAddress::_Init(net_interface* netInterface, net_domain* netDomain) 427 { 428 TRACE("InterfaceAddress %p: init interface %p, domain %p\n", this, 429 netInterface, netDomain); 430 431 interface = netInterface; 432 domain = netDomain; 433 local = NULL; 434 destination = NULL; 435 mask = NULL; 436 flags = 0; 437 438 if (interface != NULL) 439 ((Interface*)interface)->AcquireReference(); 440 } 441 442 443 // #pragma mark - 444 445 446 Interface::Interface(const char* interfaceName, 447 net_device_interface* deviceInterface) 448 { 449 TRACE("Interface %p: new \"%s\", device interface %p\n", this, 450 interfaceName, deviceInterface); 451 452 int written = strlcpy(name, interfaceName, IF_NAMESIZE); 453 memset(name + written, 0, IF_NAMESIZE - written); 454 // Clear remaining space 455 456 device = deviceInterface->device; 457 458 index = ++sInterfaceIndex; 459 flags = 0; 460 type = 0; 461 mtu = deviceInterface->device->mtu; 462 metric = 0; 463 464 fDeviceInterface = acquire_device_interface(deviceInterface); 465 466 recursive_lock_init(&fLock, name); 467 468 // Grab a reference to the networking stack, to make sure it won't be 469 // unloaded as long as an interface exists 470 module_info* module; 471 get_module(gNetStackInterfaceModule.info.name, &module); 472 } 473 474 475 Interface::~Interface() 476 { 477 TRACE("Interface %p: destructor\n", this); 478 479 put_device_interface(fDeviceInterface); 480 481 // Uninitialize the domain datalink protocols 482 483 DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator(); 484 while (domain_datalink* datalink = iterator.Next()) { 485 put_domain_datalink_protocols(this, datalink->domain); 486 } 487 488 // Free domain datalink objects 489 490 domain_datalink* next = fDatalinkTable.Clear(true); 491 while (next != NULL) { 492 domain_datalink* datalink = next; 493 next = next->hash_link; 494 495 delete datalink; 496 } 497 498 recursive_lock_destroy(&fLock); 499 500 // Release reference of the stack - at this point, our stack may be unloaded 501 // if no other interfaces or sockets are left 502 put_module(gNetStackInterfaceModule.info.name); 503 } 504 505 506 /*! Returns a reference to the first InterfaceAddress that is from the same 507 as the specified \a family. 508 */ 509 InterfaceAddress* 510 Interface::FirstForFamily(int family) 511 { 512 RecursiveLocker locker(fLock); 513 514 InterfaceAddress* address = _FirstForFamily(family); 515 if (address != NULL) { 516 address->AcquireReference(); 517 return address; 518 } 519 520 return NULL; 521 } 522 523 524 /*! Returns a reference to the first unconfigured address of this interface 525 for the specified \a family. 526 */ 527 InterfaceAddress* 528 Interface::FirstUnconfiguredForFamily(int family) 529 { 530 RecursiveLocker locker(fLock); 531 532 AddressList::Iterator iterator = fAddresses.GetIterator(); 533 while (InterfaceAddress* address = iterator.Next()) { 534 if (address->domain->family == family 535 && (address->local == NULL 536 // TODO: this has to be solved differently!! 537 || (flags & IFF_CONFIGURING) != 0)) { 538 address->AcquireReference(); 539 return address; 540 } 541 } 542 543 return NULL; 544 } 545 546 547 /*! Returns a reference to the InterfaceAddress that has the specified 548 \a destination address. 549 */ 550 InterfaceAddress* 551 Interface::AddressForDestination(net_domain* domain, 552 const sockaddr* destination) 553 { 554 RecursiveLocker locker(fLock); 555 556 if ((device->flags & IFF_BROADCAST) == 0) { 557 // The device does not support broadcasting 558 return NULL; 559 } 560 561 AddressList::Iterator iterator = fAddresses.GetIterator(); 562 while (InterfaceAddress* address = iterator.Next()) { 563 if (address->domain == domain 564 && address->destination != NULL 565 && domain->address_module->equal_addresses(address->destination, 566 destination)) { 567 address->AcquireReference(); 568 return address; 569 } 570 } 571 572 return NULL; 573 } 574 575 576 /*! Returns a reference to the InterfaceAddress that has the specified 577 \a local address. 578 */ 579 InterfaceAddress* 580 Interface::AddressForLocal(net_domain* domain, const sockaddr* local) 581 { 582 RecursiveLocker locker(fLock); 583 584 AddressList::Iterator iterator = fAddresses.GetIterator(); 585 while (InterfaceAddress* address = iterator.Next()) { 586 if (address->domain == domain 587 && address->local != NULL 588 && domain->address_module->equal_addresses(address->local, local)) { 589 address->AcquireReference(); 590 return address; 591 } 592 } 593 594 return NULL; 595 } 596 597 598 status_t 599 Interface::AddAddress(InterfaceAddress* address) 600 { 601 net_domain* domain = address->domain; 602 if (domain == NULL) 603 return B_BAD_VALUE; 604 605 RecursiveLocker locker(fLock); 606 fAddresses.Add(address); 607 locker.Unlock(); 608 609 if (address->LocalIsDefined()) { 610 MutexLocker hashLocker(sHashLock); 611 sAddressTable.Insert(address); 612 } 613 return B_OK; 614 } 615 616 617 void 618 Interface::RemoveAddress(InterfaceAddress* address) 619 { 620 net_domain* domain = address->domain; 621 if (domain == NULL) 622 return; 623 624 RecursiveLocker locker(fLock); 625 626 fAddresses.Remove(address); 627 address->GetDoublyLinkedListLink()->next = NULL; 628 629 locker.Unlock(); 630 631 if (address->LocalIsDefined()) { 632 MutexLocker hashLocker(sHashLock); 633 sAddressTable.Remove(address); 634 } 635 } 636 637 638 bool 639 Interface::GetNextAddress(InterfaceAddress** _address) 640 { 641 RecursiveLocker locker(fLock); 642 643 InterfaceAddress* address = *_address; 644 if (address == NULL) { 645 // get first address 646 address = fAddresses.First(); 647 } else { 648 // get next, if possible 649 InterfaceAddress* next = fAddresses.GetNext(address); 650 address->ReleaseReference(); 651 address = next; 652 } 653 654 *_address = address; 655 656 if (address == NULL) 657 return false; 658 659 address->AcquireReference(); 660 return true; 661 } 662 663 664 InterfaceAddress* 665 Interface::AddressAt(size_t index) 666 { 667 RecursiveLocker locker(fLock); 668 669 AddressList::Iterator iterator = fAddresses.GetIterator(); 670 size_t i = 0; 671 672 while (InterfaceAddress* address = iterator.Next()) { 673 if (i++ == index) { 674 address->AcquireReference(); 675 return address; 676 } 677 } 678 679 return NULL; 680 } 681 682 683 int32 684 Interface::IndexOfAddress(InterfaceAddress* address) 685 { 686 if (address == NULL) 687 return -1; 688 689 RecursiveLocker locker(fLock); 690 691 AddressList::Iterator iterator = fAddresses.GetIterator(); 692 int32 index = 0; 693 694 while (iterator.HasNext()) { 695 if (address == iterator.Next()) 696 return index; 697 698 index++; 699 } 700 701 return -1; 702 } 703 704 705 size_t 706 Interface::CountAddresses() 707 { 708 RecursiveLocker locker(fLock); 709 return fAddresses.Count(); 710 } 711 712 713 void 714 Interface::RemoveAddresses() 715 { 716 RecursiveLocker locker(fLock); 717 718 while (InterfaceAddress* address = fAddresses.RemoveHead()) { 719 locker.Unlock(); 720 721 if (address->LocalIsDefined()) { 722 MutexLocker hashLocker(sHashLock); 723 sAddressTable.Remove(address); 724 } 725 address->ReleaseReference(); 726 727 locker.Lock(); 728 } 729 } 730 731 732 /*! This is called in order to call the correct methods of the datalink 733 protocols, ie. it will translate address changes to 734 net_datalink_protocol::change_address(), and IFF_UP changes to 735 net_datalink_protocol::interface_up(), and interface_down(). 736 737 Everything else is passed unchanged to net_datalink_protocol::control(). 738 */ 739 status_t 740 Interface::Control(net_domain* domain, int32 option, ifreq& request, 741 ifreq* userRequest, size_t length) 742 { 743 switch (option) { 744 case SIOCSIFFLAGS: 745 { 746 if (length != sizeof(ifreq)) 747 return B_BAD_VALUE; 748 749 uint32 requestFlags = request.ifr_flags; 750 uint32 oldFlags = flags; 751 status_t status = B_OK; 752 753 request.ifr_flags &= ~(IFF_UP | IFF_LINK | IFF_BROADCAST); 754 755 if ((requestFlags & IFF_UP) != (flags & IFF_UP)) { 756 if ((requestFlags & IFF_UP) != 0) 757 status = _SetUp(); 758 else 759 SetDown(); 760 } 761 762 if (status == B_OK) { 763 // TODO: maybe allow deleting IFF_BROADCAST on the interface 764 // level? 765 flags &= IFF_UP | IFF_LINK | IFF_BROADCAST; 766 flags |= request.ifr_flags; 767 } 768 769 if (oldFlags != flags) { 770 TRACE("Interface %p: flags changed from %" B_PRIx32 " to %" 771 B_PRIx32 "\n", this, oldFlags, flags); 772 notify_interface_changed(this, oldFlags, flags); 773 } 774 775 return status; 776 } 777 778 case B_SOCKET_SET_ALIAS: 779 { 780 if (length != sizeof(ifaliasreq)) 781 return B_BAD_VALUE; 782 783 RecursiveLocker locker(fLock); 784 785 ifaliasreq aliasRequest; 786 if (user_memcpy(&aliasRequest, userRequest, sizeof(ifaliasreq)) 787 != B_OK) 788 return B_BAD_ADDRESS; 789 790 InterfaceAddress* address = NULL; 791 if (aliasRequest.ifra_index < 0) { 792 if (!domain->address_module->is_empty_address( 793 (const sockaddr*)&aliasRequest.ifra_addr, false)) { 794 // Find first address that matches the local address 795 address = AddressForLocal(domain, 796 (const sockaddr*)&aliasRequest.ifra_addr); 797 } 798 if (address == NULL) { 799 // Find first address for family 800 address = FirstForFamily(domain->family); 801 } 802 if (address == NULL) { 803 // Create new on the fly 804 address = new(std::nothrow) InterfaceAddress(this, domain); 805 if (address == NULL) 806 return B_NO_MEMORY; 807 808 status_t status = AddAddress(address); 809 if (status != B_OK) { 810 delete address; 811 return status; 812 } 813 814 // Note, even if setting the address failed, the empty 815 // address added here will still be added to the interface. 816 address->AcquireReference(); 817 } 818 } else 819 address = AddressAt(aliasRequest.ifra_index); 820 821 if (address == NULL) 822 return B_BAD_VALUE; 823 824 status_t status = B_OK; 825 826 if (!domain->address_module->equal_addresses( 827 (sockaddr*)&aliasRequest.ifra_addr, address->local)) { 828 status = _ChangeAddress(locker, address, SIOCSIFADDR, 829 address->local, (sockaddr*)&aliasRequest.ifra_addr); 830 } 831 832 if (status == B_OK && !domain->address_module->equal_addresses( 833 (sockaddr*)&aliasRequest.ifra_mask, address->mask) 834 && !domain->address_module->is_empty_address( 835 (sockaddr*)&aliasRequest.ifra_mask, false)) { 836 status = _ChangeAddress(locker, address, SIOCSIFNETMASK, 837 address->mask, (sockaddr*)&aliasRequest.ifra_mask); 838 } 839 840 if (status == B_OK && !domain->address_module->equal_addresses( 841 (sockaddr*)&aliasRequest.ifra_destination, 842 address->destination) 843 && !domain->address_module->is_empty_address( 844 (sockaddr*)&aliasRequest.ifra_destination, false)) { 845 status = _ChangeAddress(locker, address, 846 (domain->address_module->flags 847 & NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS) != 0 848 ? SIOCSIFBRDADDR : SIOCSIFDSTADDR, 849 address->destination, 850 (sockaddr*)&aliasRequest.ifra_destination); 851 } 852 853 address->ReleaseReference(); 854 return status; 855 } 856 857 case SIOCSIFADDR: 858 case SIOCSIFNETMASK: 859 case SIOCSIFBRDADDR: 860 case SIOCSIFDSTADDR: 861 case SIOCDIFADDR: 862 { 863 if (length != sizeof(ifreq)) 864 return B_BAD_VALUE; 865 866 RecursiveLocker locker(fLock); 867 868 InterfaceAddress* address = NULL; 869 sockaddr_storage newAddress; 870 871 size_t size = max_c(request.ifr_addr.sa_len, sizeof(sockaddr)); 872 if (size > sizeof(sockaddr_storage)) 873 size = sizeof(sockaddr_storage); 874 875 if (user_memcpy(&newAddress, &userRequest->ifr_addr, size) != B_OK) 876 return B_BAD_ADDRESS; 877 878 if (option == SIOCDIFADDR) { 879 // Find referring address - we can't use the hash, as another 880 // interface might use the same address. 881 AddressList::Iterator iterator = fAddresses.GetIterator(); 882 while ((address = iterator.Next()) != NULL) { 883 if (address->domain == domain 884 && domain->address_module->equal_addresses( 885 address->local, (sockaddr*)&newAddress)) 886 break; 887 } 888 889 if (address == NULL) 890 return B_BAD_VALUE; 891 } else { 892 // Just use the first address for this family 893 address = _FirstForFamily(domain->family); 894 if (address == NULL) { 895 // Create new on the fly 896 address = new(std::nothrow) InterfaceAddress(this, domain); 897 if (address == NULL) 898 return B_NO_MEMORY; 899 900 status_t status = AddAddress(address); 901 if (status != B_OK) { 902 delete address; 903 return status; 904 } 905 906 // Note, even if setting the address failed, the empty 907 // address added here will still be added to the interface. 908 } 909 } 910 911 return _ChangeAddress(locker, address, option, 912 *address->AddressFor(option), 913 option != SIOCDIFADDR ? (sockaddr*)&newAddress : NULL); 914 } 915 916 default: 917 // pass the request into the datalink protocol stack 918 domain_datalink* datalink = DomainDatalink(domain->family); 919 if (datalink->first_info != NULL) { 920 return datalink->first_info->control( 921 datalink->first_protocol, option, userRequest, length); 922 } 923 break; 924 } 925 926 return B_BAD_VALUE; 927 } 928 929 930 void 931 Interface::SetDown() 932 { 933 if ((flags & IFF_UP) == 0) 934 return; 935 936 RecursiveLocker locker(fLock); 937 938 DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator(); 939 while (domain_datalink* datalink = iterator.Next()) { 940 datalink->first_info->interface_down(datalink->first_protocol); 941 } 942 943 flags &= ~IFF_UP; 944 } 945 946 947 /*! Called when a device lost its IFF_UP status. We will invalidate all 948 interface routes here. 949 */ 950 void 951 Interface::WentDown() 952 { 953 TRACE("Interface %p: went down\n", this); 954 955 RecursiveLocker locker(fLock); 956 957 AddressList::Iterator iterator = fAddresses.GetIterator(); 958 while (InterfaceAddress* address = iterator.Next()) { 959 if (address->domain != NULL) 960 invalidate_routes(address->domain, this); 961 } 962 } 963 964 965 status_t 966 Interface::CreateDomainDatalinkIfNeeded(net_domain* domain) 967 { 968 RecursiveLocker locker(fLock); 969 970 if (fDatalinkTable.Lookup(domain->family) != NULL) 971 return B_OK; 972 973 TRACE("Interface %p: create domain datalink for domain %p\n", this, domain); 974 975 domain_datalink* datalink = new(std::nothrow) domain_datalink; 976 if (datalink == NULL) 977 return B_NO_MEMORY; 978 979 datalink->first_protocol = NULL; 980 datalink->first_info = NULL; 981 datalink->domain = domain; 982 983 // setup direct route for bound devices 984 datalink->direct_route.destination = NULL; 985 datalink->direct_route.mask = NULL; 986 datalink->direct_route.gateway = NULL; 987 datalink->direct_route.flags = 0; 988 datalink->direct_route.mtu = 0; 989 datalink->direct_route.interface_address = &datalink->direct_address; 990 datalink->direct_route.ref_count = 1; 991 // make sure this doesn't get deleted accidently 992 993 // provide its link back to the interface 994 datalink->direct_address.local = NULL; 995 datalink->direct_address.destination = NULL; 996 datalink->direct_address.mask = NULL; 997 datalink->direct_address.domain = domain; 998 datalink->direct_address.interface = this; 999 datalink->direct_address.flags = IFAF_DIRECT_ADDRESS; 1000 1001 fDatalinkTable.Insert(datalink); 1002 1003 status_t status = get_domain_datalink_protocols(this, domain); 1004 if (status == B_OK) 1005 return B_OK; 1006 1007 fDatalinkTable.Remove(datalink); 1008 delete datalink; 1009 1010 return status; 1011 } 1012 1013 1014 domain_datalink* 1015 Interface::DomainDatalink(uint8 family) 1016 { 1017 // Note: domain datalinks cannot be removed while the interface is alive, 1018 // since this would require us either to hold the lock while calling this 1019 // function, or introduce reference counting for the domain_datalink 1020 // structure. 1021 RecursiveLocker locker(fLock); 1022 return fDatalinkTable.Lookup(family); 1023 } 1024 1025 1026 #if ENABLE_DEBUGGER_COMMANDS 1027 1028 1029 void 1030 Interface::Dump() const 1031 { 1032 kprintf("name: %s\n", name); 1033 kprintf("device: %p\n", device); 1034 kprintf("device_interface: %p\n", fDeviceInterface); 1035 kprintf("index: %" B_PRIu32 "\n", index); 1036 kprintf("flags: %#" B_PRIx32 "\n", flags); 1037 kprintf("type: %u\n", type); 1038 kprintf("mtu: %" B_PRIu32 "\n", mtu); 1039 kprintf("metric: %" B_PRIu32 "\n", metric); 1040 kprintf("ref count: %" B_PRId32 "\n", CountReferences()); 1041 1042 kprintf("datalink protocols:\n"); 1043 1044 DatalinkTable::Iterator datalinkIterator = fDatalinkTable.GetIterator(); 1045 size_t i = 0; 1046 while (domain_datalink* datalink = datalinkIterator.Next()) { 1047 kprintf("%2zu. domain: %p\n", ++i, datalink->domain); 1048 kprintf(" first_protocol: %p\n", datalink->first_protocol); 1049 kprintf(" first_info: %p\n", datalink->first_info); 1050 kprintf(" direct_route: %p\n", &datalink->direct_route); 1051 } 1052 1053 kprintf("addresses:\n"); 1054 1055 AddressList::ConstIterator iterator = fAddresses.GetIterator(); 1056 i = 0; 1057 while (InterfaceAddress* address = iterator.Next()) { 1058 address->Dump(++i, true); 1059 } 1060 } 1061 1062 1063 #endif // ENABLE_DEBUGGER_COMMANDS 1064 1065 1066 status_t 1067 Interface::_SetUp() 1068 { 1069 status_t status = up_device_interface(fDeviceInterface); 1070 if (status != B_OK) 1071 return status; 1072 1073 // Propagate flag to all datalink protocols 1074 1075 RecursiveLocker locker(fLock); 1076 1077 DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator(); 1078 while (domain_datalink* datalink = iterator.Next()) { 1079 status = datalink->first_info->interface_up(datalink->first_protocol); 1080 if (status != B_OK) { 1081 // Revert "up" status 1082 DatalinkTable::Iterator secondIterator 1083 = fDatalinkTable.GetIterator(); 1084 while (secondIterator.HasNext()) { 1085 domain_datalink* secondDatalink = secondIterator.Next(); 1086 if (secondDatalink == NULL || secondDatalink == datalink) 1087 break; 1088 1089 secondDatalink->first_info->interface_down( 1090 secondDatalink->first_protocol); 1091 } 1092 1093 down_device_interface(fDeviceInterface); 1094 return status; 1095 } 1096 } 1097 1098 // Add default routes for the existing addresses 1099 1100 AddressList::Iterator addressIterator = fAddresses.GetIterator(); 1101 while (InterfaceAddress* address = addressIterator.Next()) { 1102 address->AddDefaultRoutes(SIOCSIFADDR); 1103 } 1104 1105 flags |= IFF_UP; 1106 return B_OK; 1107 } 1108 1109 1110 InterfaceAddress* 1111 Interface::_FirstForFamily(int family) 1112 { 1113 ASSERT_LOCKED_RECURSIVE(&fLock); 1114 1115 AddressList::Iterator iterator = fAddresses.GetIterator(); 1116 while (InterfaceAddress* address = iterator.Next()) { 1117 if (address->domain != NULL && address->domain->family == family) 1118 return address; 1119 } 1120 1121 return NULL; 1122 } 1123 1124 1125 status_t 1126 Interface::_ChangeAddress(RecursiveLocker& locker, InterfaceAddress* address, 1127 int32 option, const sockaddr* originalAddress, 1128 const sockaddr* requestedAddress) 1129 { 1130 // Copy old address 1131 sockaddr_storage oldAddress; 1132 if (address->domain->address_module->set_to((sockaddr*)&oldAddress, 1133 originalAddress) != B_OK) 1134 oldAddress.ss_family = AF_UNSPEC; 1135 1136 // Copy new address (this also makes sure that sockaddr::sa_len is set 1137 // correctly) 1138 sockaddr_storage newAddress; 1139 if (address->domain->address_module->set_to((sockaddr*)&newAddress, 1140 requestedAddress) != B_OK) 1141 newAddress.ss_family = AF_UNSPEC; 1142 1143 // Test if anything changed for real 1144 if (address->domain->address_module->equal_addresses( 1145 (sockaddr*)&oldAddress, (sockaddr*)&newAddress)) { 1146 // Nothing to do 1147 TRACE(" option %" B_PRId32 " addresses are equal!\n", option); 1148 return B_OK; 1149 } 1150 1151 // TODO: mark this address busy or call while holding the lock! 1152 address->AcquireReference(); 1153 locker.Unlock(); 1154 1155 domain_datalink* datalink = DomainDatalink(address->domain); 1156 status_t status = datalink->first_protocol->module->change_address( 1157 datalink->first_protocol, address, option, 1158 oldAddress.ss_family != AF_UNSPEC ? (sockaddr*)&oldAddress : NULL, 1159 newAddress.ss_family != AF_UNSPEC ? (sockaddr*)&newAddress : NULL); 1160 1161 locker.Lock(); 1162 address->ReleaseReference(); 1163 return status; 1164 } 1165 1166 1167 // #pragma mark - 1168 1169 1170 /*! Searches for a specific interface by name. 1171 You need to have the interface list's lock hold when calling this function. 1172 */ 1173 static struct Interface* 1174 find_interface(const char* name) 1175 { 1176 ASSERT_LOCKED_MUTEX(&sLock); 1177 1178 InterfaceList::Iterator iterator = sInterfaces.GetIterator(); 1179 while (Interface* interface = iterator.Next()) { 1180 if (!strcmp(interface->name, name)) 1181 return interface; 1182 } 1183 1184 return NULL; 1185 } 1186 1187 1188 /*! Searches for a specific interface by index. 1189 You need to have the interface list's lock hold when calling this function. 1190 */ 1191 static struct Interface* 1192 find_interface(uint32 index) 1193 { 1194 InterfaceList::Iterator iterator = sInterfaces.GetIterator(); 1195 while (Interface* interface = iterator.Next()) { 1196 if (interface->index == index) 1197 return interface; 1198 } 1199 1200 return NULL; 1201 } 1202 1203 1204 // #pragma mark - 1205 1206 1207 status_t 1208 add_interface(const char* name, net_domain_private* domain, 1209 const ifaliasreq& request, net_device_interface* deviceInterface) 1210 { 1211 MutexLocker locker(sLock); 1212 1213 if (find_interface(name) != NULL) 1214 return B_NAME_IN_USE; 1215 1216 Interface* interface 1217 = new(std::nothrow) Interface(name, deviceInterface); 1218 if (interface == NULL) 1219 return B_NO_MEMORY; 1220 1221 sInterfaces.Add(interface); 1222 interface->AcquireReference(); 1223 // We need another reference to be able to use the interface without 1224 // holding sLock. 1225 1226 locker.Unlock(); 1227 1228 status_t status = add_interface_address(interface, domain, request); 1229 if (status == B_OK) 1230 notify_interface_added(interface); 1231 else { 1232 locker.Lock(); 1233 sInterfaces.Remove(interface); 1234 locker.Unlock(); 1235 interface->ReleaseReference(); 1236 } 1237 1238 interface->ReleaseReference(); 1239 1240 return status; 1241 } 1242 1243 1244 /*! Removes the interface from the list, and puts the stack's reference to it. 1245 */ 1246 void 1247 remove_interface(Interface* interface) 1248 { 1249 interface->SetDown(); 1250 interface->RemoveAddresses(); 1251 1252 MutexLocker locker(sLock); 1253 sInterfaces.Remove(interface); 1254 locker.Unlock(); 1255 1256 notify_interface_removed(interface); 1257 1258 interface->ReleaseReference(); 1259 } 1260 1261 1262 /*! This is called whenever a device interface is being removed. We will get 1263 the corresponding Interface, and remove it. 1264 */ 1265 void 1266 interface_removed_device_interface(net_device_interface* deviceInterface) 1267 { 1268 MutexLocker locker(sLock); 1269 1270 Interface* interface = find_interface(deviceInterface->device->name); 1271 if (interface != NULL) 1272 remove_interface(interface); 1273 } 1274 1275 1276 status_t 1277 add_interface_address(Interface* interface, net_domain_private* domain, 1278 const ifaliasreq& request) 1279 { 1280 // Make sure the family of the provided addresses is valid 1281 if ((request.ifra_addr.ss_family != domain->family 1282 && request.ifra_addr.ss_family != AF_UNSPEC) 1283 || (request.ifra_mask.ss_family != domain->family 1284 && request.ifra_mask.ss_family != AF_UNSPEC) 1285 || (request.ifra_broadaddr.ss_family != domain->family 1286 && request.ifra_broadaddr.ss_family != AF_UNSPEC)) 1287 return B_BAD_VALUE; 1288 1289 RecursiveLocker locker(interface->Lock()); 1290 1291 InterfaceAddress* address 1292 = new(std::nothrow) InterfaceAddress(interface, domain); 1293 if (address == NULL) 1294 return B_NO_MEMORY; 1295 1296 status_t status = address->SetTo(request); 1297 if (status == B_OK) 1298 status = interface->CreateDomainDatalinkIfNeeded(domain); 1299 if (status == B_OK) 1300 status = interface->AddAddress(address); 1301 1302 if (status == B_OK && address->local != NULL) { 1303 // update the datalink protocols 1304 domain_datalink* datalink = interface->DomainDatalink(domain->family); 1305 1306 status = datalink->first_protocol->module->change_address( 1307 datalink->first_protocol, address, SIOCAIFADDR, NULL, 1308 address->local); 1309 if (status != B_OK) 1310 interface->RemoveAddress(address); 1311 } 1312 if (status == B_OK) 1313 notify_interface_changed(interface); 1314 else 1315 delete address; 1316 1317 return status; 1318 } 1319 1320 1321 status_t 1322 update_interface_address(InterfaceAddress* interfaceAddress, int32 option, 1323 const sockaddr* oldAddress, const sockaddr* newAddress) 1324 { 1325 TRACE("%s(address %p, option %" B_PRId32 ", oldAddress %s, newAddress " 1326 "%s)\n", __FUNCTION__, interfaceAddress, option, 1327 AddressString(interfaceAddress->domain, oldAddress).Data(), 1328 AddressString(interfaceAddress->domain, newAddress).Data()); 1329 1330 MutexLocker locker(sHashLock); 1331 1332 // set logical interface address 1333 sockaddr** _address = interfaceAddress->AddressFor(option); 1334 if (_address == NULL) 1335 return B_BAD_VALUE; 1336 1337 Interface* interface = (Interface*)interfaceAddress->interface; 1338 1339 interfaceAddress->RemoveDefaultRoutes(option); 1340 1341 if (option == SIOCDIFADDR) { 1342 // Remove address, and release its reference (causing our caller to 1343 // delete it) 1344 locker.Unlock(); 1345 1346 invalidate_routes(interfaceAddress); 1347 1348 interface->RemoveAddress(interfaceAddress); 1349 interfaceAddress->ReleaseReference(); 1350 return B_OK; 1351 } 1352 1353 if (interfaceAddress->LocalIsDefined()) 1354 sAddressTable.Remove(interfaceAddress); 1355 1356 // Copy new address over 1357 status_t status = InterfaceAddress::Set(_address, newAddress); 1358 if (status == B_OK) { 1359 sockaddr* address = *_address; 1360 1361 if (option == SIOCSIFADDR || option == SIOCSIFNETMASK) { 1362 // Reset netmask and broadcast addresses to defaults 1363 net_domain* domain = interfaceAddress->domain; 1364 sockaddr* defaultNetmask = NULL; 1365 const sockaddr* netmask = NULL; 1366 if (option == SIOCSIFADDR) { 1367 defaultNetmask = InterfaceAddress::Prepare( 1368 &interfaceAddress->mask, address->sa_len); 1369 } else 1370 netmask = newAddress; 1371 1372 // Reset the broadcast address if the address family has 1373 // such 1374 sockaddr* defaultBroadcast = NULL; 1375 if ((domain->address_module->flags 1376 & NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS) != 0) { 1377 defaultBroadcast = InterfaceAddress::Prepare( 1378 &interfaceAddress->destination, address->sa_len); 1379 } else 1380 InterfaceAddress::Set(&interfaceAddress->destination, NULL); 1381 1382 domain->address_module->set_to_defaults(defaultNetmask, 1383 defaultBroadcast, interfaceAddress->local, netmask); 1384 } 1385 1386 interfaceAddress->AddDefaultRoutes(option); 1387 notify_interface_changed(interface); 1388 } 1389 1390 if (interfaceAddress->LocalIsDefined()) 1391 sAddressTable.Insert(interfaceAddress); 1392 return status; 1393 } 1394 1395 1396 Interface* 1397 get_interface(net_domain* domain, uint32 index) 1398 { 1399 MutexLocker locker(sLock); 1400 1401 Interface* interface; 1402 if (index == 0) 1403 interface = sInterfaces.First(); 1404 else 1405 interface = find_interface(index); 1406 if (interface == NULL) 1407 return NULL; 1408 1409 if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK) 1410 return NULL; 1411 1412 interface->AcquireReference(); 1413 return interface; 1414 } 1415 1416 1417 Interface* 1418 get_interface(net_domain* domain, const char* name) 1419 { 1420 MutexLocker locker(sLock); 1421 1422 Interface* interface = find_interface(name); 1423 if (interface == NULL) 1424 return NULL; 1425 1426 if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK) 1427 return NULL; 1428 1429 interface->AcquireReference(); 1430 return interface; 1431 } 1432 1433 1434 Interface* 1435 get_interface_for_device(net_domain* domain, uint32 index) 1436 { 1437 MutexLocker locker(sLock); 1438 1439 InterfaceList::Iterator iterator = sInterfaces.GetIterator(); 1440 while (Interface* interface = iterator.Next()) { 1441 if (interface->device->index == index) { 1442 if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK) 1443 return NULL; 1444 1445 interface->AcquireReference(); 1446 return interface; 1447 } 1448 } 1449 1450 return NULL; 1451 } 1452 1453 1454 /*! Returns a reference to an Interface that matches the given \a linkAddress. 1455 The link address is checked against its hardware address, or its interface 1456 name, or finally the interface index. 1457 */ 1458 Interface* 1459 get_interface_for_link(net_domain* domain, const sockaddr* _linkAddress) 1460 { 1461 sockaddr_dl& linkAddress = *(sockaddr_dl*)_linkAddress; 1462 1463 MutexLocker locker(sLock); 1464 1465 InterfaceList::Iterator iterator = sInterfaces.GetIterator(); 1466 while (Interface* interface = iterator.Next()) { 1467 // Test if the hardware address matches, or if the given interface 1468 // matches, or if at least the index matches. 1469 if ((linkAddress.sdl_alen == interface->device->address.length 1470 && memcmp(LLADDR(&linkAddress), interface->device->address.data, 1471 linkAddress.sdl_alen) == 0) 1472 || (linkAddress.sdl_nlen > 0 1473 && !strcmp(interface->name, (const char*)linkAddress.sdl_data)) 1474 || (linkAddress.sdl_nlen == 0 && linkAddress.sdl_alen == 0 1475 && linkAddress.sdl_index == interface->index)) { 1476 if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK) 1477 return NULL; 1478 1479 interface->AcquireReference(); 1480 return interface; 1481 } 1482 } 1483 1484 return NULL; 1485 } 1486 1487 1488 InterfaceAddress* 1489 get_interface_address(const sockaddr* local) 1490 { 1491 if (local->sa_family == AF_UNSPEC) 1492 return NULL; 1493 1494 MutexLocker locker(sHashLock); 1495 1496 InterfaceAddress* address = sAddressTable.Lookup(local); 1497 if (address == NULL) 1498 return NULL; 1499 1500 address->AcquireReference(); 1501 return address; 1502 } 1503 1504 1505 InterfaceAddress* 1506 get_interface_address_for_destination(net_domain* domain, 1507 const sockaddr* destination) 1508 { 1509 MutexLocker locker(sLock); 1510 1511 InterfaceList::Iterator iterator = sInterfaces.GetIterator(); 1512 while (Interface* interface = iterator.Next()) { 1513 InterfaceAddress* address 1514 = interface->AddressForDestination(domain, destination); 1515 if (address != NULL) 1516 return address; 1517 } 1518 1519 return NULL; 1520 } 1521 1522 1523 /*! Returns a reference to an InterfaceAddress of the specified \a domain that 1524 belongs to the interface identified via \a linkAddress. Only the hardware 1525 address is matched. 1526 1527 If \a unconfiguredOnly is set, the interface address must not yet be 1528 configured, or must currently be in the process of being configured. 1529 */ 1530 InterfaceAddress* 1531 get_interface_address_for_link(net_domain* domain, const sockaddr* address, 1532 bool unconfiguredOnly) 1533 { 1534 sockaddr_dl& linkAddress = *(sockaddr_dl*)address; 1535 1536 MutexLocker locker(sLock); 1537 1538 InterfaceList::Iterator iterator = sInterfaces.GetIterator(); 1539 while (Interface* interface = iterator.Next()) { 1540 // Test if the hardware address matches, or if the given interface 1541 // matches, or if at least the index matches. 1542 if (linkAddress.sdl_alen == interface->device->address.length 1543 && memcmp(LLADDR(&linkAddress), interface->device->address.data, 1544 linkAddress.sdl_alen) == 0) { 1545 TRACE(" %s matches\n", interface->name); 1546 // link address matches 1547 if (unconfiguredOnly) 1548 return interface->FirstUnconfiguredForFamily(domain->family); 1549 1550 return interface->FirstForFamily(domain->family); 1551 } 1552 } 1553 1554 return NULL; 1555 } 1556 1557 1558 uint32 1559 count_interfaces() 1560 { 1561 MutexLocker locker(sLock); 1562 1563 return sInterfaces.Count(); 1564 } 1565 1566 1567 /*! Dumps a list of all interfaces into the supplied userland buffer. 1568 If the interfaces don't fit into the buffer, an error (\c ENOBUFS) is 1569 returned. 1570 */ 1571 status_t 1572 list_interfaces(int family, void* _buffer, size_t* bufferSize) 1573 { 1574 MutexLocker locker(sLock); 1575 1576 UserBuffer buffer(_buffer, *bufferSize); 1577 1578 InterfaceList::Iterator iterator = sInterfaces.GetIterator(); 1579 while (Interface* interface = iterator.Next()) { 1580 // Copy name 1581 buffer.Push(interface->name, IF_NAMESIZE); 1582 1583 // Copy address 1584 InterfaceAddress* address = interface->FirstForFamily(family); 1585 size_t length = 0; 1586 1587 if (address != NULL && address->local != NULL) { 1588 // Actual address 1589 buffer.Push(address->local, length = address->local->sa_len); 1590 } else { 1591 // Empty address 1592 sockaddr empty; 1593 empty.sa_len = 2; 1594 empty.sa_family = AF_UNSPEC; 1595 buffer.Push(&empty, length = empty.sa_len); 1596 } 1597 1598 if (address != NULL) 1599 address->ReleaseReference(); 1600 1601 if (IF_NAMESIZE + length < sizeof(ifreq)) { 1602 // Make sure at least sizeof(ifreq) bytes are written for each 1603 // interface for compatibility with other platforms 1604 buffer.Pad(sizeof(ifreq) - IF_NAMESIZE - length); 1605 } 1606 1607 if (buffer.Status() != B_OK) 1608 return buffer.Status(); 1609 } 1610 1611 *bufferSize = buffer.BytesConsumed(); 1612 return B_OK; 1613 } 1614 1615 1616 // #pragma mark - 1617 1618 1619 status_t 1620 init_interfaces() 1621 { 1622 mutex_init(&sLock, "net interfaces"); 1623 mutex_init(&sHashLock, "net local addresses"); 1624 1625 new (&sInterfaces) InterfaceList; 1626 new (&sAddressTable) AddressTable; 1627 // static C++ objects are not initialized in the module startup 1628 1629 #if ENABLE_DEBUGGER_COMMANDS 1630 add_debugger_command("net_interface", &dump_interface, 1631 "Dump the given network interface"); 1632 add_debugger_command("net_interfaces", &dump_interfaces, 1633 "Dump all network interfaces"); 1634 add_debugger_command("net_local", &dump_local, 1635 "Dump all local interface addresses"); 1636 add_debugger_command("net_route", &dump_route, 1637 "Dump the given network route"); 1638 #endif 1639 return B_OK; 1640 } 1641 1642 1643 status_t 1644 uninit_interfaces() 1645 { 1646 #if ENABLE_DEBUGGER_COMMANDS 1647 remove_debugger_command("net_interface", &dump_interface); 1648 remove_debugger_command("net_interfaces", &dump_interfaces); 1649 remove_debugger_command("net_local", &dump_local); 1650 remove_debugger_command("net_route", &dump_route); 1651 #endif 1652 1653 mutex_destroy(&sLock); 1654 mutex_destroy(&sHashLock); 1655 return B_OK; 1656 } 1657 1658