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