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