1 /* 2 * Copyright 2006-2017, 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 "device_interfaces.h" 11 #include "domains.h" 12 #include "interfaces.h" 13 #include "stack_private.h" 14 #include "utility.h" 15 16 #include <net_device.h> 17 18 #include <lock.h> 19 #include <util/AutoLock.h> 20 21 #include <KernelExport.h> 22 23 #include <net/if_dl.h> 24 #include <netinet/in.h> 25 #include <new> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 30 31 //#define TRACE_DEVICE_INTERFACES 32 #ifdef TRACE_DEVICE_INTERFACES 33 # define TRACE(x) dprintf x 34 #else 35 # define TRACE(x) ; 36 #endif 37 38 39 static mutex sLock; 40 static DeviceInterfaceList sInterfaces; 41 static uint32 sDeviceIndex; 42 43 44 /*! A service thread for each device interface. It just reads as many packets 45 as available, deframes them, and puts them into the receive queue of the 46 device interface. 47 */ 48 static status_t 49 device_reader_thread(void* _interface) 50 { 51 net_device_interface* interface = (net_device_interface*)_interface; 52 net_device* device = interface->device; 53 status_t status = B_OK; 54 55 while ((device->flags & IFF_UP) != 0) { 56 net_buffer* buffer; 57 status = device->module->receive_data(device, &buffer); 58 if (status == B_OK) { 59 // feed device monitors 60 if (atomic_get(&interface->monitor_count) > 0) 61 device_interface_monitor_receive(interface, buffer); 62 63 ASSERT(buffer->interface_address == NULL); 64 65 if (interface->deframe_func(interface->device, buffer) != B_OK) { 66 gNetBufferModule.free(buffer); 67 continue; 68 } 69 70 fifo_enqueue_buffer(&interface->receive_queue, buffer); 71 } else if (status == B_DEVICE_NOT_FOUND) { 72 device_removed(device); 73 return status; 74 } else { 75 // In case of error, give the other threads some 76 // time to run since this is a high priority time thread. 77 snooze(10000); 78 } 79 } 80 81 return status; 82 } 83 84 85 static status_t 86 device_consumer_thread(void* _interface) 87 { 88 net_device_interface* interface = (net_device_interface*)_interface; 89 net_device* device = interface->device; 90 net_buffer* buffer; 91 92 while (atomic_get(&interface->ref_count) > 0) { 93 ssize_t status = fifo_dequeue_buffer(&interface->receive_queue, 0, 94 B_INFINITE_TIMEOUT, &buffer); 95 if (status != B_OK) { 96 if (status == B_INTERRUPTED) 97 continue; 98 break; 99 } 100 101 if (buffer->interface_address != NULL) { 102 // If the interface is already specified, this buffer was 103 // delivered locally. 104 if (buffer->interface_address->domain->module->receive_data(buffer) 105 == B_OK) 106 buffer = NULL; 107 } else { 108 sockaddr_dl& linkAddress = *(sockaddr_dl*)buffer->source; 109 int32 genericType = buffer->type; 110 int32 specificType = B_NET_FRAME_TYPE(linkAddress.sdl_type, 111 ntohs(linkAddress.sdl_e_type)); 112 113 buffer->index = interface->device->index; 114 115 // Find handler for this packet 116 117 RecursiveLocker locker(interface->receive_lock); 118 119 DeviceHandlerList::Iterator iterator 120 = interface->receive_funcs.GetIterator(); 121 while (buffer != NULL && iterator.HasNext()) { 122 net_device_handler* handler = iterator.Next(); 123 124 // If the handler returns B_OK, it consumed the buffer - first 125 // handler wins. 126 if ((handler->type == genericType 127 || handler->type == specificType) 128 && handler->func(handler->cookie, device, buffer) == B_OK) 129 buffer = NULL; 130 } 131 } 132 133 if (buffer != NULL) 134 gNetBufferModule.free(buffer); 135 } 136 137 return B_OK; 138 } 139 140 141 /*! The domain's device receive handler - this will inject the net_buffers into 142 the protocol layer (the domain's registered receive handler). 143 */ 144 static status_t 145 domain_receive_adapter(void* cookie, net_device* device, net_buffer* buffer) 146 { 147 net_domain_private* domain = (net_domain_private*)cookie; 148 149 return domain->module->receive_data(buffer); 150 } 151 152 153 static net_device_interface* 154 find_device_interface(const char* name) 155 { 156 ASSERT_LOCKED_MUTEX(&sLock); 157 DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); 158 159 while (net_device_interface* interface = iterator.Next()) { 160 if (!strcmp(interface->device->name, name)) 161 return interface; 162 } 163 164 return NULL; 165 } 166 167 168 static net_device_interface* 169 allocate_device_interface(net_device* device, net_device_module_info* module) 170 { 171 net_device_interface* interface = new(std::nothrow) net_device_interface; 172 if (interface == NULL) 173 return NULL; 174 175 recursive_lock_init(&interface->receive_lock, "device interface receive"); 176 recursive_lock_init(&interface->monitor_lock, "device interface monitors"); 177 178 char name[128]; 179 snprintf(name, sizeof(name), "%s receive queue", device->name); 180 181 if (init_fifo(&interface->receive_queue, name, 16 * 1024 * 1024) < B_OK) 182 goto error1; 183 184 interface->device = device; 185 interface->up_count = 0; 186 interface->ref_count = 1; 187 interface->busy = false; 188 interface->monitor_count = 0; 189 interface->deframe_func = NULL; 190 interface->deframe_ref_count = 0; 191 192 snprintf(name, sizeof(name), "%s consumer", device->name); 193 194 interface->reader_thread = -1; 195 interface->consumer_thread = spawn_kernel_thread(device_consumer_thread, 196 name, B_DISPLAY_PRIORITY, interface); 197 if (interface->consumer_thread < B_OK) 198 goto error2; 199 resume_thread(interface->consumer_thread); 200 201 // TODO: proper interface index allocation 202 device->index = ++sDeviceIndex; 203 device->module = module; 204 205 sInterfaces.Add(interface); 206 return interface; 207 208 error2: 209 uninit_fifo(&interface->receive_queue); 210 error1: 211 recursive_lock_destroy(&interface->receive_lock); 212 recursive_lock_destroy(&interface->monitor_lock); 213 delete interface; 214 215 return NULL; 216 } 217 218 219 static void 220 notify_device_monitors(net_device_interface* interface, int32 event) 221 { 222 RecursiveLocker locker(interface->monitor_lock); 223 224 DeviceMonitorList::Iterator iterator 225 = interface->monitor_funcs.GetIterator(); 226 while (net_device_monitor* monitor = iterator.Next()) { 227 // it's safe for the "current" item to remove itself. 228 monitor->event(monitor, event); 229 } 230 } 231 232 233 #if ENABLE_DEBUGGER_COMMANDS 234 235 236 static int 237 dump_device_interface(int argc, char** argv) 238 { 239 if (argc != 2) { 240 kprintf("usage: %s [address]\n", argv[0]); 241 return 0; 242 } 243 244 net_device_interface* interface 245 = (net_device_interface*)parse_expression(argv[1]); 246 247 kprintf("device: %p\n", interface->device); 248 kprintf("reader_thread: %" B_PRId32 "\n", interface->reader_thread); 249 kprintf("up_count: %" B_PRIu32 "\n", interface->up_count); 250 kprintf("ref_count: %" B_PRId32 "\n", interface->ref_count); 251 kprintf("deframe_func: %p\n", interface->deframe_func); 252 kprintf("deframe_ref_count: %" B_PRId32 "\n", interface->ref_count); 253 kprintf("consumer_thread: %" B_PRId32 "\n", interface->consumer_thread); 254 255 kprintf("monitor_count: %" B_PRId32 "\n", interface->monitor_count); 256 kprintf("monitor_lock: %p\n", &interface->monitor_lock); 257 kprintf("monitor_funcs:\n"); 258 DeviceMonitorList::Iterator monitorIterator 259 = interface->monitor_funcs.GetIterator(); 260 while (monitorIterator.HasNext()) 261 kprintf(" %p\n", monitorIterator.Next()); 262 263 kprintf("receive_lock: %p\n", &interface->receive_lock); 264 kprintf("receive_queue: %p\n", &interface->receive_queue); 265 kprintf("receive_funcs:\n"); 266 DeviceHandlerList::Iterator handlerIterator 267 = interface->receive_funcs.GetIterator(); 268 while (handlerIterator.HasNext()) 269 kprintf(" %p\n", handlerIterator.Next()); 270 271 return 0; 272 } 273 274 275 static int 276 dump_device_interfaces(int argc, char** argv) 277 { 278 DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); 279 while (net_device_interface* interface = iterator.Next()) { 280 kprintf(" %p %s\n", interface, interface->device->name); 281 } 282 283 return 0; 284 } 285 286 287 #endif // ENABLE_DEBUGGER_COMMANDS 288 289 290 // #pragma mark - device interfaces 291 292 293 net_device_interface* 294 acquire_device_interface(net_device_interface* interface) 295 { 296 if (interface == NULL || atomic_add(&interface->ref_count, 1) == 0) 297 return NULL; 298 299 return interface; 300 } 301 302 303 void 304 get_device_interface_address(net_device_interface* interface, 305 sockaddr* _address) 306 { 307 sockaddr_dl &address = *(sockaddr_dl*)_address; 308 309 address.sdl_family = AF_LINK; 310 address.sdl_index = interface->device->index; 311 address.sdl_type = interface->device->type; 312 address.sdl_nlen = strlen(interface->device->name); 313 address.sdl_slen = 0; 314 memcpy(address.sdl_data, interface->device->name, address.sdl_nlen); 315 316 address.sdl_alen = interface->device->address.length; 317 memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen); 318 319 address.sdl_len = sizeof(sockaddr_dl) - sizeof(address.sdl_data) 320 + address.sdl_nlen + address.sdl_alen; 321 } 322 323 324 uint32 325 count_device_interfaces() 326 { 327 MutexLocker locker(sLock); 328 329 DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); 330 uint32 count = 0; 331 332 while (iterator.HasNext()) { 333 iterator.Next(); 334 count++; 335 } 336 337 return count; 338 } 339 340 341 /*! Dumps a list of all interfaces into the supplied userland buffer. 342 If the interfaces don't fit into the buffer, an error (\c ENOBUFS) is 343 returned. 344 */ 345 status_t 346 list_device_interfaces(void* _buffer, size_t* bufferSize) 347 { 348 MutexLocker locker(sLock); 349 350 DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); 351 UserBuffer buffer(_buffer, *bufferSize); 352 353 while (net_device_interface* interface = iterator.Next()) { 354 buffer.Push(interface->device->name, IF_NAMESIZE); 355 356 sockaddr_storage address; 357 get_device_interface_address(interface, (sockaddr*)&address); 358 359 buffer.Push(&address, address.ss_len); 360 if (IF_NAMESIZE + address.ss_len < (int)sizeof(ifreq)) 361 buffer.Pad(sizeof(ifreq) - IF_NAMESIZE - address.ss_len); 362 363 if (buffer.Status() != B_OK) 364 return buffer.Status(); 365 } 366 367 *bufferSize = buffer.BytesConsumed(); 368 return B_OK; 369 } 370 371 372 /*! Releases the reference for the interface. When all references are 373 released, the interface is removed. 374 */ 375 void 376 put_device_interface(struct net_device_interface* interface) 377 { 378 if (interface == NULL) 379 return; 380 381 if (atomic_add(&interface->ref_count, -1) != 1) 382 return; 383 384 // Indicate we are in the process of destroying this interface 385 // by setting its ref_count to 0. 386 interface->ref_count = 0; 387 388 MutexLocker locker(sLock); 389 sInterfaces.Remove(interface); 390 locker.Unlock(); 391 392 uninit_fifo(&interface->receive_queue); 393 wait_for_thread(interface->consumer_thread, NULL); 394 395 net_device* device = interface->device; 396 const char* moduleName = device->module->info.name; 397 398 device->module->uninit_device(device); 399 put_module(moduleName); 400 401 recursive_lock_destroy(&interface->monitor_lock); 402 recursive_lock_destroy(&interface->receive_lock); 403 delete interface; 404 } 405 406 407 /*! Finds an interface by the specified index and acquires a reference to it. 408 */ 409 struct net_device_interface* 410 get_device_interface(uint32 index) 411 { 412 MutexLocker locker(sLock); 413 414 // TODO: maintain an array of all device interfaces instead 415 DeviceInterfaceList::Iterator iterator = sInterfaces.GetIterator(); 416 while (net_device_interface* interface = iterator.Next()) { 417 if (interface->device->index == index) { 418 if (interface->busy) 419 break; 420 421 if (atomic_add(&interface->ref_count, 1) != 0) 422 return interface; 423 } 424 } 425 426 return NULL; 427 } 428 429 430 /*! Finds an interface by the specified name and grabs a reference to it. 431 If the interface does not yet exist, a new one is created. 432 */ 433 struct net_device_interface* 434 get_device_interface(const char* name, bool create) 435 { 436 MutexLocker locker(sLock); 437 438 net_device_interface* interface = find_device_interface(name); 439 if (interface != NULL) { 440 if (interface->busy) 441 return NULL; 442 443 if (atomic_add(&interface->ref_count, 1) != 0) 444 return interface; 445 446 // try to recreate interface - it just got removed 447 } 448 449 if (!create) 450 return NULL; 451 452 void* cookie = open_module_list("network/devices"); 453 if (cookie == NULL) 454 return NULL; 455 456 while (true) { 457 char moduleName[B_FILE_NAME_LENGTH]; 458 size_t length = sizeof(moduleName); 459 if (read_next_module_name(cookie, moduleName, &length) != B_OK) 460 break; 461 462 TRACE(("get_device_interface: ask \"%s\" for %s\n", moduleName, name)); 463 464 net_device_module_info* module; 465 if (get_module(moduleName, (module_info**)&module) == B_OK) { 466 net_device* device; 467 status_t status = module->init_device(name, &device); 468 if (status == B_OK) { 469 interface = allocate_device_interface(device, module); 470 if (interface != NULL) { 471 close_module_list(cookie); 472 return interface; 473 } 474 475 module->uninit_device(device); 476 } 477 put_module(moduleName); 478 } 479 } 480 481 close_module_list(cookie); 482 483 return NULL; 484 } 485 486 487 /*! Feeds the device monitors of the \a interface with the specified \a buffer. 488 You might want to check interface::monitor_count before calling this 489 function for optimization. 490 */ 491 void 492 device_interface_monitor_receive(net_device_interface* interface, 493 net_buffer* buffer) 494 { 495 RecursiveLocker locker(interface->monitor_lock); 496 497 DeviceMonitorList::Iterator iterator 498 = interface->monitor_funcs.GetIterator(); 499 while (iterator.HasNext()) { 500 net_device_monitor* monitor = iterator.Next(); 501 monitor->receive(monitor, buffer); 502 } 503 } 504 505 506 status_t 507 up_device_interface(net_device_interface* interface) 508 { 509 net_device* device = interface->device; 510 511 RecursiveLocker locker(interface->receive_lock); 512 513 if (interface->up_count != 0) { 514 interface->up_count++; 515 return B_OK; 516 } 517 518 status_t status = device->module->up(device); 519 if (status != B_OK) 520 return status; 521 522 if (device->module->receive_data != NULL) { 523 // give the thread a nice name 524 char name[B_OS_NAME_LENGTH]; 525 snprintf(name, sizeof(name), "%s reader", device->name); 526 527 interface->reader_thread = spawn_kernel_thread(device_reader_thread, 528 name, B_REAL_TIME_DISPLAY_PRIORITY - 10, interface); 529 if (interface->reader_thread < B_OK) 530 return interface->reader_thread; 531 } 532 533 device->flags |= IFF_UP; 534 535 if (device->module->receive_data != NULL) 536 resume_thread(interface->reader_thread); 537 538 interface->up_count = 1; 539 return B_OK; 540 } 541 542 543 void 544 down_device_interface(net_device_interface* interface) 545 { 546 // Receive lock must be held when calling down_device_interface. 547 // Known callers are `interface_protocol_down' which gets 548 // here via one of the following paths: 549 // 550 // - Interface::Control() 551 // Interface::SetDown() 552 // interface_protocol_down() 553 // 554 // - datalink_control() 555 // remove_interface() 556 // Interface::SetDown() etc. 557 // 558 // - device_removed() 559 // interface_removed_device_interface() 560 // remove_interface() etc. 561 562 net_device* device = interface->device; 563 564 device->flags &= ~IFF_UP; 565 device->module->down(device); 566 567 notify_device_monitors(interface, B_DEVICE_GOING_DOWN); 568 569 if (device->module->receive_data != NULL) { 570 thread_id readerThread = interface->reader_thread; 571 572 // make sure the reader thread is gone before shutting down the interface 573 // (note that we may be the reader thread) 574 status_t status; 575 wait_for_thread(readerThread, &status); 576 } 577 } 578 579 580 // #pragma mark - devices stack API 581 582 583 /*! Unregisters a previously registered deframer function. */ 584 status_t 585 unregister_device_deframer(net_device* device) 586 { 587 MutexLocker locker(sLock); 588 589 // find device interface for this device 590 net_device_interface* interface = find_device_interface(device->name); 591 if (interface == NULL) 592 return B_DEVICE_NOT_FOUND; 593 594 RecursiveLocker _(interface->receive_lock); 595 596 if (--interface->deframe_ref_count == 0) 597 interface->deframe_func = NULL; 598 599 return B_OK; 600 } 601 602 603 /*! Registers the deframer function for the specified \a device. 604 Note, however, that right now, you can only register one single 605 deframer function per device. 606 607 If the need arises, we might want to lift that limitation at a 608 later time (which would require a slight API change, though). 609 */ 610 status_t 611 register_device_deframer(net_device* device, net_deframe_func deframeFunc) 612 { 613 MutexLocker locker(sLock); 614 615 // find device interface for this device 616 net_device_interface* interface = find_device_interface(device->name); 617 if (interface == NULL) 618 return B_DEVICE_NOT_FOUND; 619 620 RecursiveLocker _(interface->receive_lock); 621 622 if (interface->deframe_func != NULL 623 && interface->deframe_func != deframeFunc) 624 return B_ERROR; 625 626 interface->deframe_func = deframeFunc; 627 interface->deframe_ref_count++; 628 return B_OK; 629 } 630 631 632 /*! Registers a domain to receive net_buffers from the specified \a device. */ 633 status_t 634 register_domain_device_handler(struct net_device* device, int32 type, 635 struct net_domain* _domain) 636 { 637 net_domain_private* domain = (net_domain_private*)_domain; 638 if (domain->module == NULL || domain->module->receive_data == NULL) 639 return B_BAD_VALUE; 640 641 return register_device_handler(device, type, &domain_receive_adapter, 642 domain); 643 } 644 645 646 /*! Registers a receiving function callback for the specified \a device. */ 647 status_t 648 register_device_handler(struct net_device* device, int32 type, 649 net_receive_func receiveFunc, void* cookie) 650 { 651 MutexLocker locker(sLock); 652 653 // find device interface for this device 654 net_device_interface* interface = find_device_interface(device->name); 655 if (interface == NULL) 656 return B_DEVICE_NOT_FOUND; 657 658 RecursiveLocker _(interface->receive_lock); 659 660 // see if such a handler already for this device 661 662 DeviceHandlerList::Iterator iterator 663 = interface->receive_funcs.GetIterator(); 664 while (net_device_handler* handler = iterator.Next()) { 665 if (handler->type == type) 666 return B_ERROR; 667 } 668 669 // Add new handler 670 671 net_device_handler* handler = new(std::nothrow) net_device_handler; 672 if (handler == NULL) 673 return B_NO_MEMORY; 674 675 handler->func = receiveFunc; 676 handler->type = type; 677 handler->cookie = cookie; 678 interface->receive_funcs.Add(handler); 679 return B_OK; 680 } 681 682 683 /*! Unregisters a previously registered device handler. */ 684 status_t 685 unregister_device_handler(struct net_device* device, int32 type) 686 { 687 MutexLocker locker(sLock); 688 689 // find device interface for this device 690 net_device_interface* interface = find_device_interface(device->name); 691 if (interface == NULL) 692 return B_DEVICE_NOT_FOUND; 693 694 RecursiveLocker _(interface->receive_lock); 695 696 // search for the handler 697 698 DeviceHandlerList::Iterator iterator 699 = interface->receive_funcs.GetIterator(); 700 while (net_device_handler* handler = iterator.Next()) { 701 if (handler->type == type) { 702 // found it 703 iterator.Remove(); 704 delete handler; 705 return B_OK; 706 } 707 } 708 709 return B_BAD_VALUE; 710 } 711 712 713 /*! Registers a device monitor for the specified device. */ 714 status_t 715 register_device_monitor(net_device* device, net_device_monitor* monitor) 716 { 717 if (monitor->receive == NULL || monitor->event == NULL) 718 return B_BAD_VALUE; 719 720 MutexLocker locker(sLock); 721 722 // find device interface for this device 723 net_device_interface* interface = find_device_interface(device->name); 724 if (interface == NULL) 725 return B_DEVICE_NOT_FOUND; 726 727 RecursiveLocker monitorLocker(interface->monitor_lock); 728 interface->monitor_funcs.Add(monitor); 729 atomic_add(&interface->monitor_count, 1); 730 731 return B_OK; 732 } 733 734 735 /*! Unregisters a previously registered device monitor. */ 736 status_t 737 unregister_device_monitor(net_device* device, net_device_monitor* monitor) 738 { 739 MutexLocker locker(sLock); 740 741 // find device interface for this device 742 net_device_interface* interface = find_device_interface(device->name); 743 if (interface == NULL) 744 return B_DEVICE_NOT_FOUND; 745 746 RecursiveLocker monitorLocker(interface->monitor_lock); 747 748 // search for the monitor 749 750 DeviceMonitorList::Iterator iterator 751 = interface->monitor_funcs.GetIterator(); 752 while (iterator.HasNext()) { 753 if (iterator.Next() == monitor) { 754 iterator.Remove(); 755 atomic_add(&interface->monitor_count, -1); 756 return B_OK; 757 } 758 } 759 760 return B_BAD_VALUE; 761 } 762 763 764 /*! This function is called by device modules in case their link 765 state changed, ie. if an ethernet cable was plugged in or 766 removed. 767 */ 768 status_t 769 device_link_changed(net_device* device) 770 { 771 notify_link_changed(device); 772 return B_OK; 773 } 774 775 776 /*! This function is called by device modules once their device got 777 physically removed, ie. a USB networking card is unplugged. 778 */ 779 status_t 780 device_removed(net_device* device) 781 { 782 MutexLocker locker(sLock); 783 784 net_device_interface* interface = find_device_interface(device->name); 785 if (interface == NULL) 786 return B_DEVICE_NOT_FOUND; 787 if (interface->busy) 788 return B_BUSY; 789 790 // Acquire a reference to the device interface being removed 791 // so our put_() will (eventually) do the final cleanup 792 atomic_add(&interface->ref_count, 1); 793 interface->busy = true; 794 locker.Unlock(); 795 796 // Propagate the loss of the device throughout the stack. 797 798 interface_removed_device_interface(interface); 799 notify_device_monitors(interface, B_DEVICE_BEING_REMOVED); 800 801 // By now all of the monitors must have removed themselves. If they 802 // didn't, they'll probably wait forever to be callback'ed again. 803 RecursiveLocker monitorLocker(interface->monitor_lock); 804 interface->monitor_funcs.RemoveAll(); 805 monitorLocker.Unlock(); 806 807 // All of the readers should be gone as well since we are out of 808 // interfaces and put_domain_datalink_protocols() is called for 809 // each delete_interface(). 810 811 put_device_interface(interface); 812 813 return B_OK; 814 } 815 816 817 status_t 818 device_enqueue_buffer(net_device* device, net_buffer* buffer) 819 { 820 net_device_interface* interface = get_device_interface(device->index); 821 if (interface == NULL) 822 return B_DEVICE_NOT_FOUND; 823 824 status_t status = interface->deframe_func(interface->device, buffer); 825 if (status != B_OK) { 826 gNetBufferModule.free(buffer); 827 return status; 828 } 829 830 status = fifo_enqueue_buffer(&interface->receive_queue, buffer); 831 832 put_device_interface(interface); 833 return status; 834 } 835 836 837 // #pragma mark - 838 839 840 status_t 841 init_device_interfaces() 842 { 843 mutex_init(&sLock, "net device interfaces"); 844 845 new (&sInterfaces) DeviceInterfaceList; 846 // static C++ objects are not initialized in the module startup 847 848 #if ENABLE_DEBUGGER_COMMANDS 849 add_debugger_command("net_device_interface", &dump_device_interface, 850 "Dump the given network device interface"); 851 add_debugger_command("net_device_interfaces", &dump_device_interfaces, 852 "Dump network device interfaces"); 853 #endif 854 return B_OK; 855 } 856 857 858 status_t 859 uninit_device_interfaces() 860 { 861 #if ENABLE_DEBUGGER_COMMANDS 862 remove_debugger_command("net_device_interface", &dump_device_interface); 863 remove_debugger_command("net_device_interfaces", &dump_device_interfaces); 864 #endif 865 866 mutex_destroy(&sLock); 867 return B_OK; 868 } 869 870