xref: /haiku/src/add-ons/kernel/network/stack/interfaces.cpp (revision 344ded80d400028c8f561b4b876257b94c12db4a)
1 /*
2  * Copyright 2006-2011, 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 "interfaces.h"
11 
12 #include <net/if_dl.h>
13 #include <new>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/sockio.h>
18 
19 #include <KernelExport.h>
20 
21 #include <net_device.h>
22 #include <NetUtilities.h>
23 
24 #include "device_interfaces.h"
25 #include "domains.h"
26 #include "stack_private.h"
27 #include "utility.h"
28 
29 
30 //#define TRACE_INTERFACES
31 #ifdef TRACE_INTERFACES
32 #	define TRACE(x...) dprintf(STACK_DEBUG_PREFIX x)
33 #else
34 #	define TRACE(x...) ;
35 #endif
36 
37 
38 struct AddressHashDefinition {
39 	typedef const sockaddr* KeyType;
40 	typedef InterfaceAddress ValueType;
41 
42 	AddressHashDefinition()
43 	{
44 	}
45 
46 	size_t HashKey(const KeyType& key) const
47 	{
48 		net_domain* domain = get_domain(key->sa_family);
49 		if (domain == NULL)
50 			return 0;
51 
52 		return domain->address_module->hash_address(key, false);
53 	}
54 
55 	size_t Hash(InterfaceAddress* address) const
56 	{
57 		return address->domain->address_module->hash_address(address->local,
58 			false);
59 	}
60 
61 	bool Compare(const KeyType& key, InterfaceAddress* address) const
62 	{
63 		if (address->local == NULL)
64 			return key->sa_family == AF_UNSPEC;
65 
66 		if (address->local->sa_family != key->sa_family)
67 			return false;
68 
69 		return address->domain->address_module->equal_addresses(key,
70 			address->local);
71 	}
72 
73 	InterfaceAddress*& GetLink(InterfaceAddress* address) const
74 	{
75 		return address->HashTableLink();
76 	}
77 };
78 
79 typedef BOpenHashTable<AddressHashDefinition, true, false> AddressTable;
80 
81 
82 static recursive_lock sLock;
83 static InterfaceList sInterfaces;
84 static mutex sHashLock;
85 static AddressTable sAddressTable;
86 static uint32 sInterfaceIndex;
87 
88 
89 #if 0
90 //! For debugging purposes only
91 void
92 dump_interface_refs(void)
93 {
94 	RecursiveLocker locker(sLock);
95 
96 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
97 	while (Interface* interface = iterator.Next()) {
98 		dprintf("%p: %s, %ld\n", interface, interface->name,
99 			interface->CountReferences());
100 	}
101 }
102 #endif
103 
104 
105 #if ENABLE_DEBUGGER_COMMANDS
106 
107 
108 static int
109 dump_interface(int argc, char** argv)
110 {
111 	if (argc != 2) {
112 		kprintf("usage: %s [name|address]\n", argv[0]);
113 		return 0;
114 	}
115 
116 	Interface* interface = NULL;
117 
118 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
119 	while ((interface = iterator.Next()) != NULL) {
120 		if (!strcmp(argv[1], interface->name))
121 			break;
122 	}
123 
124 	if (interface == NULL)
125 		interface = (Interface*)parse_expression(argv[1]);
126 
127 	interface->Dump();
128 
129 	return 0;
130 }
131 
132 
133 static int
134 dump_interfaces(int argc, char** argv)
135 {
136 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
137 	while (Interface* interface = iterator.Next()) {
138 		kprintf("%p  %s\n", interface, interface->name);
139 	}
140 	return 0;
141 }
142 
143 
144 static int
145 dump_local(int argc, char** argv)
146 {
147 	AddressTable::Iterator iterator = sAddressTable.GetIterator();
148 	size_t i = 0;
149 	while (InterfaceAddress* address = iterator.Next()) {
150 		address->Dump(++i);
151 		dprintf("    hash:          %" B_PRIu32 "\n",
152 			address->domain->address_module->hash_address(address->local,
153 				false));
154 	}
155 	return 0;
156 }
157 
158 
159 static int
160 dump_route(int argc, char** argv)
161 {
162 	if (argc != 2) {
163 		kprintf("usage: %s [address]\n", argv[0]);
164 		return 0;
165 	}
166 
167 	net_route* route = (net_route*)parse_expression(argv[1]);
168 	kprintf("destination:       %p\n", route->destination);
169 	kprintf("mask:              %p\n", route->mask);
170 	kprintf("gateway:           %p\n", route->gateway);
171 	kprintf("flags:             %" B_PRIx32 "\n", route->flags);
172 	kprintf("mtu:               %" B_PRIu32 "\n", route->mtu);
173 	kprintf("interface address: %p\n", route->interface_address);
174 
175 	if (route->interface_address != NULL) {
176 		((InterfaceAddress*)route->interface_address)->Dump();
177 	}
178 
179 	return 0;
180 }
181 
182 
183 #endif	// ENABLE_DEBUGGER_COMMANDS
184 
185 
186 InterfaceAddress::InterfaceAddress()
187 {
188 	_Init(NULL, NULL);
189 }
190 
191 
192 InterfaceAddress::InterfaceAddress(net_interface* netInterface,
193 	net_domain* netDomain)
194 {
195 	_Init(netInterface, netDomain);
196 }
197 
198 
199 InterfaceAddress::~InterfaceAddress()
200 {
201 	TRACE("InterfaceAddress %p: destructor\n", this);
202 
203 	if (interface != NULL && (flags & IFAF_DIRECT_ADDRESS) == 0)
204 		((Interface*)interface)->ReleaseReference();
205 }
206 
207 
208 status_t
209 InterfaceAddress::SetTo(const ifaliasreq& request)
210 {
211 	status_t status = SetLocal((const sockaddr*)&request.ifra_addr);
212 	if (status == B_OK)
213 		status = SetDestination((const sockaddr*)&request.ifra_broadaddr);
214 	if (status == B_OK)
215 		status = SetMask((const sockaddr*)&request.ifra_mask);
216 
217 	return status;
218 }
219 
220 
221 status_t
222 InterfaceAddress::SetLocal(const sockaddr* to)
223 {
224 	return Set(&local, to);
225 }
226 
227 
228 status_t
229 InterfaceAddress::SetDestination(const sockaddr* to)
230 {
231 	return Set(&destination, to);
232 }
233 
234 
235 status_t
236 InterfaceAddress::SetMask(const sockaddr* to)
237 {
238 	return Set(&mask, to);
239 }
240 
241 
242 sockaddr**
243 InterfaceAddress::AddressFor(int32 option)
244 {
245 	switch (option) {
246 		case SIOCSIFADDR:
247 		case SIOCGIFADDR:
248 		case SIOCDIFADDR:
249 			return &local;
250 
251 		case SIOCSIFNETMASK:
252 		case SIOCGIFNETMASK:
253 			return &mask;
254 
255 		case SIOCSIFBRDADDR:
256 		case SIOCSIFDSTADDR:
257 		case SIOCGIFBRDADDR:
258 		case SIOCGIFDSTADDR:
259 			return &destination;
260 
261 		default:
262 			return NULL;
263 	}
264 }
265 
266 
267 /*!	Adds the default routes that every interface address needs, ie. the local
268 	host route, and one for the subnet (if set).
269 */
270 void
271 InterfaceAddress::AddDefaultRoutes(int32 option)
272 {
273 	net_route route;
274 	route.destination = local;
275 	route.gateway = NULL;
276 	route.interface_address = this;
277 
278 	if (mask != NULL && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) {
279 		route.mask = mask;
280 		route.flags = 0;
281 		add_route(domain, &route);
282 	}
283 
284 	if (option == SIOCSIFADDR) {
285 		route.mask = NULL;
286 		route.flags = RTF_LOCAL | RTF_HOST;
287 		add_route(domain, &route);
288 	}
289 }
290 
291 
292 /*!	Removes the default routes as set by AddDefaultRoutes() again. */
293 void
294 InterfaceAddress::RemoveDefaultRoutes(int32 option)
295 {
296 	net_route route;
297 	route.destination = local;
298 	route.gateway = NULL;
299 	route.interface_address = this;
300 
301 	if (mask != NULL && (option == SIOCSIFNETMASK || option == SIOCSIFADDR)) {
302 		route.mask = mask;
303 		route.flags = 0;
304 		remove_route(domain, &route);
305 	}
306 
307 	if (option == SIOCSIFADDR) {
308 		route.mask = NULL;
309 		route.flags = RTF_LOCAL | RTF_HOST;
310 		remove_route(domain, &route);
311 	}
312 }
313 
314 
315 bool
316 InterfaceAddress::LocalIsDefined() const
317 {
318 	return local != NULL && local->sa_family != AF_UNSPEC;
319 }
320 
321 
322 #if ENABLE_DEBUGGER_COMMANDS
323 
324 
325 void
326 InterfaceAddress::Dump(size_t index, bool hideInterface)
327 {
328 	if (index)
329 		kprintf("%2zu. ", index);
330 	else
331 		kprintf("    ");
332 
333 	if (!hideInterface) {
334 		kprintf("interface:   %p (%s)\n    ", interface,
335 			interface != NULL ? interface->name : "-");
336 	}
337 
338 	kprintf("domain:      %p (family %u)\n", domain,
339 		domain != NULL ? domain->family : AF_UNSPEC);
340 
341 	char buffer[64];
342 	if (local != NULL && domain != NULL) {
343 		domain->address_module->print_address_buffer(local, buffer,
344 			sizeof(buffer), false);
345 	} else
346 		strcpy(buffer, "-");
347 	kprintf("    local:       %s\n", buffer);
348 
349 	if (mask != NULL && domain != NULL) {
350 		domain->address_module->print_address_buffer(mask, buffer,
351 			sizeof(buffer), false);
352 	} else
353 		strcpy(buffer, "-");
354 	kprintf("    mask:        %s\n", buffer);
355 
356 	if (destination != NULL && domain != NULL) {
357 		domain->address_module->print_address_buffer(destination, buffer,
358 			sizeof(buffer), false);
359 	} else
360 		strcpy(buffer, "-");
361 	kprintf("    destination: %s\n", buffer);
362 
363 	kprintf("    ref count:   %" B_PRId32 "\n", CountReferences());
364 }
365 
366 
367 #endif	// ENABLE_DEBUGGER_COMMANDS
368 
369 
370 /*static*/ status_t
371 InterfaceAddress::Set(sockaddr** _address, const sockaddr* to)
372 {
373 	sockaddr* address = *_address;
374 
375 	if (to == NULL || to->sa_family == AF_UNSPEC) {
376 		// Clear address
377 		free(address);
378 		*_address = NULL;
379 		return B_OK;
380 	}
381 
382 	// Set address
383 
384 	size_t size = max_c(to->sa_len, sizeof(sockaddr));
385 	if (size > sizeof(sockaddr_storage))
386 		size = sizeof(sockaddr_storage);
387 
388 	address = Prepare(_address, size);
389 	if (address == NULL)
390 		return B_NO_MEMORY;
391 
392 	memcpy(address, to, size);
393 	address->sa_len = size;
394 
395 	return B_OK;
396 }
397 
398 
399 /*!	Makes sure that the sockaddr object pointed to by \a _address is large
400 	enough to hold \a size bytes.
401 	\a _address may point to NULL when calling this method.
402 */
403 /*static*/ sockaddr*
404 InterfaceAddress::Prepare(sockaddr** _address, size_t size)
405 {
406 	size = max_c(size, sizeof(sockaddr));
407 	if (size > sizeof(sockaddr_storage))
408 		size = sizeof(sockaddr_storage);
409 
410 	sockaddr* address = *_address;
411 
412 	if (address == NULL || size > address->sa_len) {
413 		sockaddr* resized = (sockaddr*)realloc(address, size);
414 		if (resized == NULL) {
415 			free(address);
416 			return NULL;
417 		}
418 
419 		address = resized;
420 	}
421 
422 	address->sa_len = size;
423 
424 	*_address = address;
425 	return address;
426 }
427 
428 
429 void
430 InterfaceAddress::_Init(net_interface* netInterface, net_domain* netDomain)
431 {
432 	TRACE("InterfaceAddress %p: init interface %p, domain %p\n", this,
433 		netInterface, netDomain);
434 
435 	interface = netInterface;
436 	domain = netDomain;
437 	local = NULL;
438 	destination = NULL;
439 	mask = NULL;
440 	flags = 0;
441 
442 	if (interface != NULL)
443 		((Interface*)interface)->AcquireReference();
444 }
445 
446 
447 // #pragma mark -
448 
449 
450 Interface::Interface(const char* interfaceName,
451 	net_device_interface* deviceInterface)
452 	:
453 	fBusy(false)
454 {
455 	TRACE("Interface %p: new \"%s\", device interface %p\n", this,
456 		interfaceName, deviceInterface);
457 
458 	int written = strlcpy(name, interfaceName, IF_NAMESIZE);
459 	memset(name + written, 0, IF_NAMESIZE - written);
460 		// Clear remaining space
461 
462 	device = deviceInterface->device;
463 
464 	index = ++sInterfaceIndex;
465 	flags = 0;
466 	type = 0;
467 	metric = 0;
468 
469 	fDeviceInterface = acquire_device_interface(deviceInterface);
470 
471 	recursive_lock_init(&fLock, name);
472 
473 	// Grab a reference to the networking stack, to make sure it won't be
474 	// unloaded as long as an interface exists
475 	module_info* module;
476 	get_module(gNetStackInterfaceModule.info.name, &module);
477 }
478 
479 
480 Interface::~Interface()
481 {
482 	TRACE("Interface %p: destructor\n", this);
483 	ASSERT((flags & IFF_UP) == 0);
484 
485 	// Uninitialize the domain datalink protocols
486 
487 	DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator();
488 	while (domain_datalink* datalink = iterator.Next()) {
489 		put_domain_datalink_protocols(this, datalink->domain);
490 	}
491 
492 	// Free domain datalink objects
493 
494 	domain_datalink* next = fDatalinkTable.Clear(true);
495 	while (next != NULL) {
496 		domain_datalink* datalink = next;
497 		next = next->hash_link;
498 
499 		delete datalink;
500 	}
501 
502 	put_device_interface(fDeviceInterface);
503 
504 	recursive_lock_destroy(&fLock);
505 
506 	// Release reference of the stack - at this point, our stack may be unloaded
507 	// if no other interfaces or sockets are left
508 	put_module(gNetStackInterfaceModule.info.name);
509 }
510 
511 
512 /*!	Returns a reference to the first InterfaceAddress that is from the same
513 	as the specified \a family.
514 */
515 InterfaceAddress*
516 Interface::FirstForFamily(int family)
517 {
518 	RecursiveLocker locker(fLock);
519 
520 	InterfaceAddress* address = _FirstForFamily(family);
521 	if (address != NULL) {
522 		address->AcquireReference();
523 		return address;
524 	}
525 
526 	return NULL;
527 }
528 
529 
530 /*!	Returns a reference to the first unconfigured address of this interface
531 	for the specified \a family.
532 */
533 InterfaceAddress*
534 Interface::FirstUnconfiguredForFamily(int family)
535 {
536 	RecursiveLocker locker(fLock);
537 
538 	AddressList::Iterator iterator = fAddresses.GetIterator();
539 	while (InterfaceAddress* address = iterator.Next()) {
540 		if (address->domain->family == family
541 			&& (address->local == NULL
542 				// TODO: this has to be solved differently!!
543 				|| (flags & IFF_CONFIGURING) != 0)) {
544 			address->AcquireReference();
545 			return address;
546 		}
547 	}
548 
549 	return NULL;
550 }
551 
552 
553 /*!	Returns a reference to the InterfaceAddress that has the specified
554 	\a destination address.
555 */
556 InterfaceAddress*
557 Interface::AddressForDestination(net_domain* domain,
558 	const sockaddr* destination)
559 {
560 	RecursiveLocker locker(fLock);
561 
562 	if ((device->flags & IFF_BROADCAST) == 0) {
563 		// The device does not support broadcasting
564 		return NULL;
565 	}
566 
567 	AddressList::Iterator iterator = fAddresses.GetIterator();
568 	while (InterfaceAddress* address = iterator.Next()) {
569 		if (address->domain == domain
570 			&& address->destination != NULL
571 			&& domain->address_module->equal_addresses(address->destination,
572 					destination)) {
573 			address->AcquireReference();
574 			return address;
575 		}
576 	}
577 
578 	return NULL;
579 }
580 
581 
582 /*!	Returns a reference to the InterfaceAddress that has the specified
583 	\a local address.
584 */
585 InterfaceAddress*
586 Interface::AddressForLocal(net_domain* domain, const sockaddr* local)
587 {
588 	RecursiveLocker locker(fLock);
589 
590 	AddressList::Iterator iterator = fAddresses.GetIterator();
591 	while (InterfaceAddress* address = iterator.Next()) {
592 		if (address->domain == domain
593 			&& address->local != NULL
594 			&& domain->address_module->equal_addresses(address->local, local)) {
595 			address->AcquireReference();
596 			return address;
597 		}
598 	}
599 
600 	return NULL;
601 }
602 
603 
604 status_t
605 Interface::AddAddress(InterfaceAddress* address)
606 {
607 	net_domain* domain = address->domain;
608 	if (domain == NULL)
609 		return B_BAD_VALUE;
610 
611 	RecursiveLocker locker(fLock);
612 	fAddresses.Add(address);
613 	locker.Unlock();
614 
615 	if (address->LocalIsDefined()) {
616 		MutexLocker hashLocker(sHashLock);
617 		sAddressTable.Insert(address);
618 	}
619 	return B_OK;
620 }
621 
622 
623 void
624 Interface::RemoveAddress(InterfaceAddress* address)
625 {
626 	net_domain* domain = address->domain;
627 	if (domain == NULL)
628 		return;
629 
630 	RecursiveLocker locker(fLock);
631 
632 	fAddresses.Remove(address);
633 	address->GetDoublyLinkedListLink()->next = NULL;
634 
635 	locker.Unlock();
636 
637 	if (address->LocalIsDefined()) {
638 		MutexLocker hashLocker(sHashLock);
639 		sAddressTable.Remove(address);
640 	}
641 }
642 
643 
644 bool
645 Interface::GetNextAddress(InterfaceAddress** _address)
646 {
647 	RecursiveLocker locker(fLock);
648 
649 	InterfaceAddress* address = *_address;
650 	if (address == NULL) {
651 		// get first address
652 		address = fAddresses.First();
653 	} else {
654 		// get next, if possible
655 		InterfaceAddress* next = fAddresses.GetNext(address);
656 		address->ReleaseReference();
657 		address = next;
658 	}
659 
660 	*_address = address;
661 
662 	if (address == NULL)
663 		return false;
664 
665 	address->AcquireReference();
666 	return true;
667 }
668 
669 
670 InterfaceAddress*
671 Interface::AddressAt(size_t index)
672 {
673 	RecursiveLocker locker(fLock);
674 
675 	AddressList::Iterator iterator = fAddresses.GetIterator();
676 	size_t i = 0;
677 
678 	while (InterfaceAddress* address = iterator.Next()) {
679 		if (i++ == index) {
680 			address->AcquireReference();
681 			return address;
682 		}
683 	}
684 
685 	return NULL;
686 }
687 
688 
689 int32
690 Interface::IndexOfAddress(InterfaceAddress* address)
691 {
692 	if (address == NULL)
693 		return -1;
694 
695 	RecursiveLocker locker(fLock);
696 
697 	AddressList::Iterator iterator = fAddresses.GetIterator();
698 	int32 index = 0;
699 
700 	while (iterator.HasNext()) {
701 		if (address == iterator.Next())
702 			return index;
703 
704 		index++;
705 	}
706 
707 	return -1;
708 }
709 
710 
711 size_t
712 Interface::CountAddresses()
713 {
714 	RecursiveLocker locker(fLock);
715 	return fAddresses.Count();
716 }
717 
718 
719 void
720 Interface::RemoveAddresses()
721 {
722 	RecursiveLocker locker(fLock);
723 
724 	while (InterfaceAddress* address = fAddresses.RemoveHead()) {
725 		locker.Unlock();
726 
727 		if (address->LocalIsDefined()) {
728 			MutexLocker hashLocker(sHashLock);
729 			sAddressTable.Remove(address);
730 		}
731 		address->ReleaseReference();
732 
733 		locker.Lock();
734 	}
735 }
736 
737 
738 /*!	This is called in order to call the correct methods of the datalink
739 	protocols, ie. it will translate address changes to
740 	net_datalink_protocol::change_address(), and IFF_UP changes to
741 	net_datalink_protocol::interface_up(), and interface_down().
742 
743 	Everything else is passed unchanged to net_datalink_protocol::control().
744 */
745 status_t
746 Interface::Control(net_domain* domain, int32 option, ifreq& request,
747 	ifreq* userRequest, size_t length)
748 {
749 	switch (option) {
750 		case SIOCSIFFLAGS:
751 		{
752 			if (length != sizeof(ifreq))
753 				return B_BAD_VALUE;
754 
755 			uint32 requestFlags = request.ifr_flags;
756 			uint32 oldFlags = flags;
757 			status_t status = B_OK;
758 
759 			request.ifr_flags &= ~(IFF_UP | IFF_LINK | IFF_BROADCAST);
760 
761 			if ((requestFlags & IFF_UP) != (flags & IFF_UP)) {
762 				if ((requestFlags & IFF_UP) != 0)
763 					status = _SetUp();
764 				else
765 					SetDown();
766 			}
767 
768 			if (status == B_OK) {
769 				// TODO: maybe allow deleting IFF_BROADCAST on the interface
770 				// level?
771 				flags &= IFF_UP | IFF_LINK | IFF_BROADCAST;
772 				flags |= request.ifr_flags;
773 			}
774 
775 			if (oldFlags != flags) {
776 				TRACE("Interface %p: flags changed from %" B_PRIx32 " to %"
777 					B_PRIx32 "\n", this, oldFlags, flags);
778 				notify_interface_changed(this, oldFlags, flags);
779 			}
780 
781 			return status;
782 		}
783 
784 		case B_SOCKET_SET_ALIAS:
785 		{
786 			if (length != sizeof(ifaliasreq))
787 				return B_BAD_VALUE;
788 
789 			RecursiveLocker locker(fLock);
790 
791 			ifaliasreq aliasRequest;
792 			if (user_memcpy(&aliasRequest, userRequest, sizeof(ifaliasreq))
793 					!= B_OK)
794 				return B_BAD_ADDRESS;
795 
796 			InterfaceAddress* address = NULL;
797 			if (aliasRequest.ifra_index < 0) {
798 				if (!domain->address_module->is_empty_address(
799 						(const sockaddr*)&aliasRequest.ifra_addr, false)) {
800 					// Find first address that matches the local address
801 					address = AddressForLocal(domain,
802 						(const sockaddr*)&aliasRequest.ifra_addr);
803 				}
804 				if (address == NULL) {
805 					// Find first address for family
806 					address = FirstForFamily(domain->family);
807 				}
808 				if (address == NULL) {
809 					// Create new on the fly
810 					address = new(std::nothrow) InterfaceAddress(this, domain);
811 					if (address == NULL)
812 						return B_NO_MEMORY;
813 
814 					status_t status = AddAddress(address);
815 					if (status != B_OK) {
816 						delete address;
817 						return status;
818 					}
819 
820 					// Note, even if setting the address failed, the empty
821 					// address added here will still be added to the interface.
822 					address->AcquireReference();
823 				}
824 			} else
825 				address = AddressAt(aliasRequest.ifra_index);
826 
827 			if (address == NULL)
828 				return B_BAD_VALUE;
829 
830 			status_t status = B_OK;
831 
832 			if (!domain->address_module->equal_addresses(
833 					(sockaddr*)&aliasRequest.ifra_addr, address->local)) {
834 				status = _ChangeAddress(locker, address, SIOCSIFADDR,
835 					address->local, (sockaddr*)&aliasRequest.ifra_addr);
836 			}
837 
838 			if (status == B_OK && !domain->address_module->equal_addresses(
839 					(sockaddr*)&aliasRequest.ifra_mask, address->mask)
840 				&& !domain->address_module->is_empty_address(
841 					(sockaddr*)&aliasRequest.ifra_mask, false)) {
842 				status = _ChangeAddress(locker, address, SIOCSIFNETMASK,
843 					address->mask, (sockaddr*)&aliasRequest.ifra_mask);
844 			}
845 
846 			if (status == B_OK && !domain->address_module->equal_addresses(
847 					(sockaddr*)&aliasRequest.ifra_destination,
848 					address->destination)
849 				&& !domain->address_module->is_empty_address(
850 					(sockaddr*)&aliasRequest.ifra_destination, false)) {
851 				status = _ChangeAddress(locker, address,
852 					(domain->address_module->flags
853 						& NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS) != 0
854 							? SIOCSIFBRDADDR : SIOCSIFDSTADDR,
855 					address->destination,
856 					(sockaddr*)&aliasRequest.ifra_destination);
857 			}
858 
859 			address->ReleaseReference();
860 			return status;
861 		}
862 
863 		case SIOCSIFADDR:
864 		case SIOCSIFNETMASK:
865 		case SIOCSIFBRDADDR:
866 		case SIOCSIFDSTADDR:
867 		case SIOCDIFADDR:
868 		{
869 			if (length != sizeof(ifreq))
870 				return B_BAD_VALUE;
871 
872 			RecursiveLocker locker(fLock);
873 
874 			InterfaceAddress* address = NULL;
875 			sockaddr_storage newAddress;
876 
877 			size_t size = max_c(request.ifr_addr.sa_len, sizeof(sockaddr));
878 			if (size > sizeof(sockaddr_storage))
879 				size = sizeof(sockaddr_storage);
880 
881 			if (user_memcpy(&newAddress, &userRequest->ifr_addr, size) != B_OK)
882 				return B_BAD_ADDRESS;
883 
884 			if (option == SIOCDIFADDR) {
885 				// Find referring address - we can't use the hash, as another
886 				// interface might use the same address.
887 				AddressList::Iterator iterator = fAddresses.GetIterator();
888 				while ((address = iterator.Next()) != NULL) {
889 					if (address->domain == domain
890 						&& domain->address_module->equal_addresses(
891 							address->local, (sockaddr*)&newAddress))
892 						break;
893 				}
894 
895 				if (address == NULL)
896 					return B_BAD_VALUE;
897 			} else {
898 				// Just use the first address for this family
899 				address = _FirstForFamily(domain->family);
900 				if (address == NULL) {
901 					// Create new on the fly
902 					address = new(std::nothrow) InterfaceAddress(this, domain);
903 					if (address == NULL)
904 						return B_NO_MEMORY;
905 
906 					status_t status = AddAddress(address);
907 					if (status != B_OK) {
908 						delete address;
909 						return status;
910 					}
911 
912 					// Note, even if setting the address failed, the empty
913 					// address added here will still be added to the interface.
914 				}
915 			}
916 
917 			return _ChangeAddress(locker, address, option,
918 				*address->AddressFor(option),
919 				option != SIOCDIFADDR ? (sockaddr*)&newAddress : NULL);
920 		}
921 
922 		default:
923 			// pass the request into the datalink protocol stack
924 			domain_datalink* datalink = DomainDatalink(domain->family);
925 			if (datalink->first_info != NULL) {
926 				return datalink->first_info->control(
927 					datalink->first_protocol, option, userRequest, length);
928 			}
929 			break;
930 	}
931 
932 	return B_BAD_VALUE;
933 }
934 
935 
936 void
937 Interface::SetDown()
938 {
939 	if ((flags & IFF_UP) == 0)
940 		return;
941 
942 	RecursiveLocker interfacesLocker(sLock);
943 
944 	if (IsBusy())
945 		return;
946 
947 	SetBusy(true);
948 	interfacesLocker.Unlock();
949 
950 	DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator();
951 	while (domain_datalink* datalink = iterator.Next()) {
952 		datalink->first_info->interface_down(datalink->first_protocol);
953 	}
954 
955 	flags &= ~IFF_UP;
956 
957 	SetBusy(false);
958 }
959 
960 
961 /*!	Called when a device lost its IFF_UP status. We will invalidate all
962 	interface routes here.
963 */
964 void
965 Interface::WentDown()
966 {
967 	TRACE("Interface %p: went down\n", this);
968 
969 	RecursiveLocker locker(fLock);
970 
971 	AddressList::Iterator iterator = fAddresses.GetIterator();
972 	while (InterfaceAddress* address = iterator.Next()) {
973 		if (address->domain != NULL)
974 			invalidate_routes(address->domain, this);
975 	}
976 }
977 
978 
979 status_t
980 Interface::CreateDomainDatalinkIfNeeded(net_domain* domain)
981 {
982 	RecursiveLocker locker(fLock);
983 
984 	if (fDatalinkTable.Lookup(domain->family) != NULL)
985 		return B_OK;
986 
987 	TRACE("Interface %p: create domain datalink for domain %p\n", this, domain);
988 
989 	domain_datalink* datalink = new(std::nothrow) domain_datalink;
990 	if (datalink == NULL)
991 		return B_NO_MEMORY;
992 
993 	datalink->first_protocol = NULL;
994 	datalink->first_info = NULL;
995 	datalink->domain = domain;
996 
997 	// setup direct route for bound devices
998 	datalink->direct_route.destination = NULL;
999 	datalink->direct_route.mask = NULL;
1000 	datalink->direct_route.gateway = NULL;
1001 	datalink->direct_route.flags = 0;
1002 	datalink->direct_route.mtu = 0;
1003 	datalink->direct_route.interface_address = &datalink->direct_address;
1004 	datalink->direct_route.ref_count = 1;
1005 		// make sure this doesn't get deleted accidently
1006 
1007 	// provide its link back to the interface
1008 	datalink->direct_address.local = NULL;
1009 	datalink->direct_address.destination = NULL;
1010 	datalink->direct_address.mask = NULL;
1011 	datalink->direct_address.domain = domain;
1012 	datalink->direct_address.interface = this;
1013 	datalink->direct_address.flags = IFAF_DIRECT_ADDRESS;
1014 
1015 	fDatalinkTable.Insert(datalink);
1016 
1017 	status_t status = get_domain_datalink_protocols(this, domain);
1018 	if (status == B_OK)
1019 		return B_OK;
1020 
1021 	fDatalinkTable.Remove(datalink);
1022 	delete datalink;
1023 
1024 	return status;
1025 }
1026 
1027 
1028 domain_datalink*
1029 Interface::DomainDatalink(uint8 family)
1030 {
1031 	// Note: domain datalinks cannot be removed while the interface is alive,
1032 	// since this would require us either to hold the lock while calling this
1033 	// function, or introduce reference counting for the domain_datalink
1034 	// structure.
1035 	RecursiveLocker locker(fLock);
1036 	return fDatalinkTable.Lookup(family);
1037 }
1038 
1039 
1040 #if ENABLE_DEBUGGER_COMMANDS
1041 
1042 
1043 void
1044 Interface::Dump() const
1045 {
1046 	kprintf("name:                %s\n", name);
1047 	kprintf("device:              %p\n", device);
1048 	kprintf("device_interface:    %p\n", fDeviceInterface);
1049 	kprintf("index:               %" B_PRIu32 "\n", index);
1050 	kprintf("flags:               %#" B_PRIx32 "\n", flags);
1051 	kprintf("type:                %u\n", type);
1052 	kprintf("metric:              %" B_PRIu32 "\n", metric);
1053 	kprintf("ref count:           %" B_PRId32 "\n", CountReferences());
1054 
1055 	kprintf("datalink protocols:\n");
1056 
1057 	DatalinkTable::Iterator datalinkIterator = fDatalinkTable.GetIterator();
1058 	size_t i = 0;
1059 	while (domain_datalink* datalink = datalinkIterator.Next()) {
1060 		kprintf("%2zu. domain:          %p\n", ++i, datalink->domain);
1061 		kprintf("    first_protocol:  %p\n", datalink->first_protocol);
1062 		kprintf("    first_info:      %p\n", datalink->first_info);
1063 		kprintf("    direct_route:    %p\n", &datalink->direct_route);
1064 	}
1065 
1066 	kprintf("addresses:\n");
1067 
1068 	AddressList::ConstIterator iterator = fAddresses.GetIterator();
1069 	i = 0;
1070 	while (InterfaceAddress* address = iterator.Next()) {
1071 		address->Dump(++i, true);
1072 	}
1073 }
1074 
1075 
1076 #endif	// ENABLE_DEBUGGER_COMMANDS
1077 
1078 
1079 status_t
1080 Interface::_SetUp()
1081 {
1082 	status_t status = up_device_interface(fDeviceInterface);
1083 	if (status != B_OK)
1084 		return status;
1085 
1086 	RecursiveLocker interfacesLocker(sLock);
1087 	SetBusy(true);
1088 	interfacesLocker.Unlock();
1089 
1090 	// Propagate flag to all datalink protocols
1091 	DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator();
1092 	while (domain_datalink* datalink = iterator.Next()) {
1093 		status = datalink->first_info->interface_up(datalink->first_protocol);
1094 		if (status != B_OK) {
1095 			// Revert "up" status
1096 			DatalinkTable::Iterator secondIterator
1097 				= fDatalinkTable.GetIterator();
1098 			while (secondIterator.HasNext()) {
1099 				domain_datalink* secondDatalink = secondIterator.Next();
1100 				if (secondDatalink == NULL || secondDatalink == datalink)
1101 					break;
1102 
1103 				secondDatalink->first_info->interface_down(
1104 					secondDatalink->first_protocol);
1105 			}
1106 
1107 			down_device_interface(fDeviceInterface);
1108 			SetBusy(false);
1109 			return status;
1110 		}
1111 	}
1112 
1113 	// Add default routes for the existing addresses
1114 
1115 	AddressList::Iterator addressIterator = fAddresses.GetIterator();
1116 	while (InterfaceAddress* address = addressIterator.Next()) {
1117 		address->AddDefaultRoutes(SIOCSIFADDR);
1118 	}
1119 
1120 	flags |= IFF_UP;
1121 	SetBusy(false);
1122 
1123 	return B_OK;
1124 }
1125 
1126 
1127 InterfaceAddress*
1128 Interface::_FirstForFamily(int family)
1129 {
1130 	ASSERT_LOCKED_RECURSIVE(&fLock);
1131 
1132 	AddressList::Iterator iterator = fAddresses.GetIterator();
1133 	while (InterfaceAddress* address = iterator.Next()) {
1134 		if (address->domain != NULL && address->domain->family == family)
1135 			return address;
1136 	}
1137 
1138 	return NULL;
1139 }
1140 
1141 
1142 status_t
1143 Interface::_ChangeAddress(RecursiveLocker& locker, InterfaceAddress* address,
1144 	int32 option, const sockaddr* originalAddress,
1145 	const sockaddr* requestedAddress)
1146 {
1147 	// Copy old address
1148 	sockaddr_storage oldAddress;
1149 	if (address->domain->address_module->set_to((sockaddr*)&oldAddress,
1150 			originalAddress) != B_OK)
1151 		oldAddress.ss_family = AF_UNSPEC;
1152 
1153 	// Copy new address (this also makes sure that sockaddr::sa_len is set
1154 	// correctly)
1155 	sockaddr_storage newAddress;
1156 	if (address->domain->address_module->set_to((sockaddr*)&newAddress,
1157 			requestedAddress) != B_OK)
1158 		newAddress.ss_family = AF_UNSPEC;
1159 
1160 	// Test if anything changed for real
1161 	if (address->domain->address_module->equal_addresses(
1162 			(sockaddr*)&oldAddress, (sockaddr*)&newAddress)) {
1163 		// Nothing to do
1164 		TRACE("  option %" B_PRId32 " addresses are equal!\n", option);
1165 		return B_OK;
1166 	}
1167 
1168 	// TODO: mark this address busy or call while holding the lock!
1169 	address->AcquireReference();
1170 	locker.Unlock();
1171 
1172 	domain_datalink* datalink = DomainDatalink(address->domain);
1173 	status_t status = datalink->first_protocol->module->change_address(
1174 		datalink->first_protocol, address, option,
1175 		oldAddress.ss_family != AF_UNSPEC ? (sockaddr*)&oldAddress : NULL,
1176 		newAddress.ss_family != AF_UNSPEC ? (sockaddr*)&newAddress : NULL);
1177 
1178 	locker.Lock();
1179 	address->ReleaseReference();
1180 	return status;
1181 }
1182 
1183 
1184 // #pragma mark -
1185 
1186 
1187 /*!	Searches for a specific interface by name.
1188 	You need to have the interface list's lock hold when calling this function.
1189 */
1190 static Interface*
1191 find_interface(const char* name)
1192 {
1193 	ASSERT_LOCKED_RECURSIVE(&sLock);
1194 
1195 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1196 	while (Interface* interface = iterator.Next()) {
1197 		if (!strcmp(interface->name, name))
1198 			return interface;
1199 	}
1200 
1201 	return NULL;
1202 }
1203 
1204 
1205 /*!	Searches for a specific interface by index.
1206 	You need to have the interface list's lock hold when calling this function.
1207 */
1208 static Interface*
1209 find_interface(uint32 index)
1210 {
1211 	ASSERT_LOCKED_RECURSIVE(&sLock);
1212 
1213 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1214 	while (Interface* interface = iterator.Next()) {
1215 		if (interface->index == index)
1216 			return interface;
1217 	}
1218 
1219 	return NULL;
1220 }
1221 
1222 
1223 // #pragma mark -
1224 
1225 
1226 status_t
1227 add_interface(const char* name, net_domain_private* domain,
1228 	const ifaliasreq& request, net_device_interface* deviceInterface)
1229 {
1230 	RecursiveLocker locker(sLock);
1231 
1232 	if (find_interface(name) != NULL)
1233 		return B_NAME_IN_USE;
1234 
1235 	Interface* interface
1236 		= new(std::nothrow) Interface(name, deviceInterface);
1237 	if (interface == NULL)
1238 		return B_NO_MEMORY;
1239 
1240 	sInterfaces.Add(interface);
1241 	interface->AcquireReference();
1242 		// We need another reference to be able to use the interface without
1243 		// holding sLock.
1244 
1245 	locker.Unlock();
1246 
1247 	status_t status = add_interface_address(interface, domain, request);
1248 	if (status == B_OK)
1249 		notify_interface_added(interface);
1250 	else {
1251 		locker.Lock();
1252 		sInterfaces.Remove(interface);
1253 		locker.Unlock();
1254 		interface->ReleaseReference();
1255 	}
1256 
1257 	interface->ReleaseReference();
1258 
1259 	return status;
1260 }
1261 
1262 
1263 /*!	Removes the interface from the list, and puts the stack's reference to it.
1264 */
1265 void
1266 remove_interface(Interface* interface)
1267 {
1268 	interface->SetDown();
1269 	interface->RemoveAddresses();
1270 
1271 	RecursiveLocker locker(sLock);
1272 	sInterfaces.Remove(interface);
1273 	locker.Unlock();
1274 
1275 	notify_interface_removed(interface);
1276 
1277 	interface->ReleaseReference();
1278 }
1279 
1280 
1281 /*!	This is called whenever a device interface is being removed. We will get
1282 	the corresponding Interface, and remove it.
1283 */
1284 void
1285 interface_removed_device_interface(net_device_interface* deviceInterface)
1286 {
1287 	RecursiveLocker locker(sLock);
1288 
1289 	Interface* interface = find_interface(deviceInterface->device->name);
1290 	if (interface != NULL)
1291 		remove_interface(interface);
1292 }
1293 
1294 
1295 status_t
1296 add_interface_address(Interface* interface, net_domain_private* domain,
1297 	const ifaliasreq& request)
1298 {
1299 	// Make sure the family of the provided addresses is valid
1300 	if ((request.ifra_addr.ss_family != domain->family
1301 			&& request.ifra_addr.ss_family != AF_UNSPEC)
1302 		|| (request.ifra_mask.ss_family != domain->family
1303 			&& request.ifra_mask.ss_family != AF_UNSPEC)
1304 		|| (request.ifra_broadaddr.ss_family != domain->family
1305 			&& request.ifra_broadaddr.ss_family != AF_UNSPEC))
1306 		return B_BAD_VALUE;
1307 
1308 	RecursiveLocker locker(interface->Lock());
1309 
1310 	InterfaceAddress* address
1311 		= new(std::nothrow) InterfaceAddress(interface, domain);
1312 	if (address == NULL)
1313 		return B_NO_MEMORY;
1314 
1315 	status_t status = address->SetTo(request);
1316 	if (status == B_OK)
1317 		status = interface->CreateDomainDatalinkIfNeeded(domain);
1318 	if (status == B_OK)
1319 		status = interface->AddAddress(address);
1320 
1321 	if (status == B_OK && address->local != NULL) {
1322 		// update the datalink protocols
1323 		domain_datalink* datalink = interface->DomainDatalink(domain->family);
1324 
1325 		status = datalink->first_protocol->module->change_address(
1326 			datalink->first_protocol, address, SIOCAIFADDR, NULL,
1327 			address->local);
1328 		if (status != B_OK)
1329 			interface->RemoveAddress(address);
1330 	}
1331 	if (status == B_OK)
1332 		notify_interface_changed(interface);
1333 	else
1334 		delete address;
1335 
1336 	return status;
1337 }
1338 
1339 
1340 status_t
1341 update_interface_address(InterfaceAddress* interfaceAddress, int32 option,
1342 	const sockaddr* oldAddress, const sockaddr* newAddress)
1343 {
1344 	TRACE("%s(address %p, option %" B_PRId32 ", oldAddress %s, newAddress "
1345 		"%s)\n", __FUNCTION__, interfaceAddress, option,
1346 		AddressString(interfaceAddress->domain, oldAddress).Data(),
1347 		AddressString(interfaceAddress->domain, newAddress).Data());
1348 
1349 	MutexLocker locker(sHashLock);
1350 
1351 	// set logical interface address
1352 	sockaddr** _address = interfaceAddress->AddressFor(option);
1353 	if (_address == NULL)
1354 		return B_BAD_VALUE;
1355 
1356 	Interface* interface = (Interface*)interfaceAddress->interface;
1357 
1358 	interfaceAddress->RemoveDefaultRoutes(option);
1359 
1360 	if (option == SIOCDIFADDR) {
1361 		// Remove address, and release its reference (causing our caller to
1362 		// delete it)
1363 		locker.Unlock();
1364 
1365 		invalidate_routes(interfaceAddress);
1366 
1367 		interface->RemoveAddress(interfaceAddress);
1368 		interfaceAddress->ReleaseReference();
1369 		return B_OK;
1370 	}
1371 
1372 	if (interfaceAddress->LocalIsDefined())
1373 		sAddressTable.Remove(interfaceAddress);
1374 
1375 	// Copy new address over
1376 	status_t status = InterfaceAddress::Set(_address, newAddress);
1377 	if (status == B_OK) {
1378 		sockaddr* address = *_address;
1379 
1380 		if (option == SIOCSIFADDR || option == SIOCSIFNETMASK) {
1381 			// Reset netmask and broadcast addresses to defaults
1382 			net_domain* domain = interfaceAddress->domain;
1383 			sockaddr* defaultNetmask = NULL;
1384 			const sockaddr* netmask = NULL;
1385 			if (option == SIOCSIFADDR) {
1386 				defaultNetmask = InterfaceAddress::Prepare(
1387 					&interfaceAddress->mask, address->sa_len);
1388 			} else
1389 				netmask = newAddress;
1390 
1391 			// Reset the broadcast address if the address family has
1392 			// such
1393 			sockaddr* defaultBroadcast = NULL;
1394 			if ((domain->address_module->flags
1395 					& NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS) != 0) {
1396 				defaultBroadcast = InterfaceAddress::Prepare(
1397 					&interfaceAddress->destination, address->sa_len);
1398 			} else
1399 				InterfaceAddress::Set(&interfaceAddress->destination, NULL);
1400 
1401 			domain->address_module->set_to_defaults(defaultNetmask,
1402 				defaultBroadcast, interfaceAddress->local, netmask);
1403 		}
1404 
1405 		interfaceAddress->AddDefaultRoutes(option);
1406 		notify_interface_changed(interface);
1407 	}
1408 
1409 	if (interfaceAddress->LocalIsDefined())
1410 		sAddressTable.Insert(interfaceAddress);
1411 	return status;
1412 }
1413 
1414 
1415 Interface*
1416 get_interface(net_domain* domain, uint32 index)
1417 {
1418 	RecursiveLocker locker(sLock);
1419 
1420 	Interface* interface;
1421 	if (index == 0)
1422 		interface = sInterfaces.First();
1423 	else
1424 		interface = find_interface(index);
1425 	if (interface == NULL || interface->IsBusy())
1426 		return NULL;
1427 
1428 	// We must unlock before invoking CreateDomainDatalinkIfNeeded, because
1429 	// otherwise we can hit lock ordering inversions with receive threads,
1430 	// usually in register_device_handler.
1431 	BReference<Interface> interfaceRef(interface);
1432 	locker.Unlock();
1433 
1434 	if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK)
1435 		return NULL;
1436 
1437 	return interfaceRef.Detach();
1438 }
1439 
1440 
1441 Interface*
1442 get_interface(net_domain* domain, const char* name)
1443 {
1444 	RecursiveLocker locker(sLock);
1445 
1446 	Interface* interface = find_interface(name);
1447 	if (interface == NULL || interface->IsBusy())
1448 		return NULL;
1449 
1450 	// See comment in get_interface.
1451 	BReference<Interface> interfaceRef(interface);
1452 	locker.Unlock();
1453 
1454 	if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK)
1455 		return NULL;
1456 
1457 	return interfaceRef.Detach();
1458 }
1459 
1460 
1461 Interface*
1462 get_interface_for_device(net_domain* domain, uint32 index)
1463 {
1464 	RecursiveLocker locker(sLock);
1465 
1466 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1467 	while (Interface* interface = iterator.Next()) {
1468 		if (interface->device->index == index) {
1469 			if (interface->IsBusy())
1470 				return NULL;
1471 
1472 			// See comment in get_interface.
1473 			BReference<Interface> interfaceRef(interface);
1474 			locker.Unlock();
1475 
1476 			if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK)
1477 				return NULL;
1478 
1479 			return interfaceRef.Detach();
1480 		}
1481 	}
1482 
1483 	return NULL;
1484 }
1485 
1486 
1487 /*!	Returns a reference to an Interface that matches the given \a linkAddress.
1488 	The link address is checked against its hardware address, or its interface
1489 	name, or finally the interface index.
1490 */
1491 Interface*
1492 get_interface_for_link(net_domain* domain, const sockaddr* _linkAddress)
1493 {
1494 	sockaddr_dl& linkAddress = *(sockaddr_dl*)_linkAddress;
1495 
1496 	RecursiveLocker locker(sLock);
1497 
1498 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1499 	while (Interface* interface = iterator.Next()) {
1500 		if (interface->IsBusy())
1501 			continue;
1502 		// Test if the hardware address matches, or if the given interface
1503 		// matches, or if at least the index matches.
1504 		if ((linkAddress.sdl_alen == interface->device->address.length
1505 				&& memcmp(LLADDR(&linkAddress), interface->device->address.data,
1506 					linkAddress.sdl_alen) == 0)
1507 			|| (linkAddress.sdl_nlen > 0
1508 				&& !strcmp(interface->name, (const char*)linkAddress.sdl_data))
1509 			|| (linkAddress.sdl_nlen == 0 && linkAddress.sdl_alen == 0
1510 				&& linkAddress.sdl_index == interface->index)) {
1511 			if (interface->IsBusy())
1512 				return NULL;
1513 
1514 			// See comment in get_interface.
1515 			BReference<Interface> interfaceRef(interface);
1516 			locker.Unlock();
1517 
1518 			if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK)
1519 				return NULL;
1520 
1521 			return interfaceRef.Detach();
1522 		}
1523 	}
1524 
1525 	return NULL;
1526 }
1527 
1528 
1529 InterfaceAddress*
1530 get_interface_address(const sockaddr* local)
1531 {
1532 	if (local->sa_family == AF_UNSPEC)
1533 		return NULL;
1534 
1535 	MutexLocker locker(sHashLock);
1536 
1537 	InterfaceAddress* address = sAddressTable.Lookup(local);
1538 	if (address == NULL)
1539 		return NULL;
1540 
1541 	address->AcquireReference();
1542 	return address;
1543 }
1544 
1545 
1546 InterfaceAddress*
1547 get_interface_address_for_destination(net_domain* domain,
1548 	const sockaddr* destination)
1549 {
1550 	RecursiveLocker locker(sLock);
1551 
1552 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1553 	while (Interface* interface = iterator.Next()) {
1554 		if (interface->IsBusy())
1555 			continue;
1556 
1557 		InterfaceAddress* address
1558 			= interface->AddressForDestination(domain, destination);
1559 		if (address != NULL)
1560 			return address;
1561 	}
1562 
1563 	return NULL;
1564 }
1565 
1566 
1567 /*!	Returns a reference to an InterfaceAddress of the specified \a domain that
1568 	belongs to the interface identified via \a linkAddress. Only the hardware
1569 	address is matched.
1570 
1571 	If \a unconfiguredOnly is set, the interface address must not yet be
1572 	configured, or must currently be in the process of being configured.
1573 */
1574 InterfaceAddress*
1575 get_interface_address_for_link(net_domain* domain, const sockaddr* address,
1576 	bool unconfiguredOnly)
1577 {
1578 	sockaddr_dl& linkAddress = *(sockaddr_dl*)address;
1579 
1580 	RecursiveLocker locker(sLock);
1581 
1582 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1583 	while (Interface* interface = iterator.Next()) {
1584 		if (interface->IsBusy())
1585 			continue;
1586 		// Test if the hardware address matches, or if the given interface
1587 		// matches, or if at least the index matches.
1588 		if (linkAddress.sdl_alen == interface->device->address.length
1589 			&& memcmp(LLADDR(&linkAddress), interface->device->address.data,
1590 				linkAddress.sdl_alen) == 0) {
1591 			TRACE("  %s matches\n", interface->name);
1592 			// link address matches
1593 			if (unconfiguredOnly)
1594 				return interface->FirstUnconfiguredForFamily(domain->family);
1595 
1596 			return interface->FirstForFamily(domain->family);
1597 		}
1598 	}
1599 
1600 	return NULL;
1601 }
1602 
1603 
1604 uint32
1605 count_interfaces()
1606 {
1607 	RecursiveLocker locker(sLock);
1608 
1609 	return sInterfaces.Count();
1610 }
1611 
1612 
1613 /*!	Dumps a list of all interfaces into the supplied userland buffer.
1614 	If the interfaces don't fit into the buffer, an error (\c ENOBUFS) is
1615 	returned.
1616 */
1617 status_t
1618 list_interfaces(int family, void* _buffer, size_t* bufferSize)
1619 {
1620 	RecursiveLocker locker(sLock);
1621 
1622 	UserBuffer buffer(_buffer, *bufferSize);
1623 
1624 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1625 	while (Interface* interface = iterator.Next()) {
1626 		// Copy name
1627 		buffer.Push(interface->name, IF_NAMESIZE);
1628 
1629 		// Copy address
1630 		InterfaceAddress* address = interface->FirstForFamily(family);
1631 		size_t length = 0;
1632 
1633 		if (address != NULL && address->local != NULL) {
1634 			// Actual address
1635 			buffer.Push(address->local, length = address->local->sa_len);
1636 		} else {
1637 			// Empty address
1638 			sockaddr empty;
1639 			empty.sa_len = 2;
1640 			empty.sa_family = AF_UNSPEC;
1641 			buffer.Push(&empty, length = empty.sa_len);
1642 		}
1643 
1644 		if (address != NULL)
1645 			address->ReleaseReference();
1646 
1647 		if (IF_NAMESIZE + length < sizeof(ifreq)) {
1648 			// Make sure at least sizeof(ifreq) bytes are written for each
1649 			// interface for compatibility with other platforms
1650 			buffer.Pad(sizeof(ifreq) - IF_NAMESIZE - length);
1651 		}
1652 
1653 		if (buffer.Status() != B_OK)
1654 			return buffer.Status();
1655 	}
1656 
1657 	*bufferSize = buffer.BytesConsumed();
1658 	return B_OK;
1659 }
1660 
1661 
1662 //	#pragma mark -
1663 
1664 
1665 status_t
1666 init_interfaces()
1667 {
1668 	recursive_lock_init(&sLock, "net interfaces");
1669 	mutex_init(&sHashLock, "net local addresses");
1670 
1671 	new (&sInterfaces) InterfaceList;
1672 	new (&sAddressTable) AddressTable;
1673 		// static C++ objects are not initialized in the module startup
1674 
1675 #if ENABLE_DEBUGGER_COMMANDS
1676 	add_debugger_command("net_interface", &dump_interface,
1677 		"Dump the given network interface");
1678 	add_debugger_command("net_interfaces", &dump_interfaces,
1679 		"Dump all network interfaces");
1680 	add_debugger_command("net_local", &dump_local,
1681 		"Dump all local interface addresses");
1682 	add_debugger_command("net_route", &dump_route,
1683 		"Dump the given network route");
1684 #endif
1685 	return B_OK;
1686 }
1687 
1688 
1689 status_t
1690 uninit_interfaces()
1691 {
1692 #if ENABLE_DEBUGGER_COMMANDS
1693 	remove_debugger_command("net_interface", &dump_interface);
1694 	remove_debugger_command("net_interfaces", &dump_interfaces);
1695 	remove_debugger_command("net_local", &dump_local);
1696 	remove_debugger_command("net_route", &dump_route);
1697 #endif
1698 
1699 	recursive_lock_destroy(&sLock);
1700 	mutex_destroy(&sHashLock);
1701 	return B_OK;
1702 }
1703 
1704