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