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