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