xref: /haiku/src/add-ons/kernel/network/stack/interfaces.cpp (revision 7b3e89c0944ae1efa9a8fc66c7303874b7a344b2)
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 
484 	// Uninitialize the domain datalink protocols
485 
486 	DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator();
487 	while (domain_datalink* datalink = iterator.Next()) {
488 		put_domain_datalink_protocols(this, datalink->domain);
489 	}
490 
491 	// Free domain datalink objects
492 
493 	domain_datalink* next = fDatalinkTable.Clear(true);
494 	while (next != NULL) {
495 		domain_datalink* datalink = next;
496 		next = next->hash_link;
497 
498 		delete datalink;
499 	}
500 
501 	put_device_interface(fDeviceInterface);
502 
503 	recursive_lock_destroy(&fLock);
504 
505 	// Release reference of the stack - at this point, our stack may be unloaded
506 	// if no other interfaces or sockets are left
507 	put_module(gNetStackInterfaceModule.info.name);
508 }
509 
510 
511 /*!	Returns a reference to the first InterfaceAddress that is from the same
512 	as the specified \a family.
513 */
514 InterfaceAddress*
515 Interface::FirstForFamily(int family)
516 {
517 	RecursiveLocker locker(fLock);
518 
519 	InterfaceAddress* address = _FirstForFamily(family);
520 	if (address != NULL) {
521 		address->AcquireReference();
522 		return address;
523 	}
524 
525 	return NULL;
526 }
527 
528 
529 /*!	Returns a reference to the first unconfigured address of this interface
530 	for the specified \a family.
531 */
532 InterfaceAddress*
533 Interface::FirstUnconfiguredForFamily(int family)
534 {
535 	RecursiveLocker locker(fLock);
536 
537 	AddressList::Iterator iterator = fAddresses.GetIterator();
538 	while (InterfaceAddress* address = iterator.Next()) {
539 		if (address->domain->family == family
540 			&& (address->local == NULL
541 				// TODO: this has to be solved differently!!
542 				|| (flags & IFF_CONFIGURING) != 0)) {
543 			address->AcquireReference();
544 			return address;
545 		}
546 	}
547 
548 	return NULL;
549 }
550 
551 
552 /*!	Returns a reference to the InterfaceAddress that has the specified
553 	\a destination address.
554 */
555 InterfaceAddress*
556 Interface::AddressForDestination(net_domain* domain,
557 	const sockaddr* destination)
558 {
559 	RecursiveLocker locker(fLock);
560 
561 	if ((device->flags & IFF_BROADCAST) == 0) {
562 		// The device does not support broadcasting
563 		return NULL;
564 	}
565 
566 	AddressList::Iterator iterator = fAddresses.GetIterator();
567 	while (InterfaceAddress* address = iterator.Next()) {
568 		if (address->domain == domain
569 			&& address->destination != NULL
570 			&& domain->address_module->equal_addresses(address->destination,
571 					destination)) {
572 			address->AcquireReference();
573 			return address;
574 		}
575 	}
576 
577 	return NULL;
578 }
579 
580 
581 /*!	Returns a reference to the InterfaceAddress that has the specified
582 	\a local address.
583 */
584 InterfaceAddress*
585 Interface::AddressForLocal(net_domain* domain, const sockaddr* local)
586 {
587 	RecursiveLocker locker(fLock);
588 
589 	AddressList::Iterator iterator = fAddresses.GetIterator();
590 	while (InterfaceAddress* address = iterator.Next()) {
591 		if (address->domain == domain
592 			&& address->local != NULL
593 			&& domain->address_module->equal_addresses(address->local, local)) {
594 			address->AcquireReference();
595 			return address;
596 		}
597 	}
598 
599 	return NULL;
600 }
601 
602 
603 status_t
604 Interface::AddAddress(InterfaceAddress* address)
605 {
606 	net_domain* domain = address->domain;
607 	if (domain == NULL)
608 		return B_BAD_VALUE;
609 
610 	RecursiveLocker locker(fLock);
611 	fAddresses.Add(address);
612 	locker.Unlock();
613 
614 	if (address->LocalIsDefined()) {
615 		MutexLocker hashLocker(sHashLock);
616 		sAddressTable.Insert(address);
617 	}
618 	return B_OK;
619 }
620 
621 
622 void
623 Interface::RemoveAddress(InterfaceAddress* address)
624 {
625 	net_domain* domain = address->domain;
626 	if (domain == NULL)
627 		return;
628 
629 	RecursiveLocker locker(fLock);
630 
631 	fAddresses.Remove(address);
632 	address->GetDoublyLinkedListLink()->next = NULL;
633 
634 	locker.Unlock();
635 
636 	if (address->LocalIsDefined()) {
637 		MutexLocker hashLocker(sHashLock);
638 		sAddressTable.Remove(address);
639 	}
640 }
641 
642 
643 bool
644 Interface::GetNextAddress(InterfaceAddress** _address)
645 {
646 	RecursiveLocker locker(fLock);
647 
648 	InterfaceAddress* address = *_address;
649 	if (address == NULL) {
650 		// get first address
651 		address = fAddresses.First();
652 	} else {
653 		// get next, if possible
654 		InterfaceAddress* next = fAddresses.GetNext(address);
655 		address->ReleaseReference();
656 		address = next;
657 	}
658 
659 	*_address = address;
660 
661 	if (address == NULL)
662 		return false;
663 
664 	address->AcquireReference();
665 	return true;
666 }
667 
668 
669 InterfaceAddress*
670 Interface::AddressAt(size_t index)
671 {
672 	RecursiveLocker locker(fLock);
673 
674 	AddressList::Iterator iterator = fAddresses.GetIterator();
675 	size_t i = 0;
676 
677 	while (InterfaceAddress* address = iterator.Next()) {
678 		if (i++ == index) {
679 			address->AcquireReference();
680 			return address;
681 		}
682 	}
683 
684 	return NULL;
685 }
686 
687 
688 int32
689 Interface::IndexOfAddress(InterfaceAddress* address)
690 {
691 	if (address == NULL)
692 		return -1;
693 
694 	RecursiveLocker locker(fLock);
695 
696 	AddressList::Iterator iterator = fAddresses.GetIterator();
697 	int32 index = 0;
698 
699 	while (iterator.HasNext()) {
700 		if (address == iterator.Next())
701 			return index;
702 
703 		index++;
704 	}
705 
706 	return -1;
707 }
708 
709 
710 size_t
711 Interface::CountAddresses()
712 {
713 	RecursiveLocker locker(fLock);
714 	return fAddresses.Count();
715 }
716 
717 
718 void
719 Interface::RemoveAddresses()
720 {
721 	RecursiveLocker locker(fLock);
722 
723 	while (InterfaceAddress* address = fAddresses.RemoveHead()) {
724 		locker.Unlock();
725 
726 		if (address->LocalIsDefined()) {
727 			MutexLocker hashLocker(sHashLock);
728 			sAddressTable.Remove(address);
729 		}
730 		address->ReleaseReference();
731 
732 		locker.Lock();
733 	}
734 }
735 
736 
737 /*!	This is called in order to call the correct methods of the datalink
738 	protocols, ie. it will translate address changes to
739 	net_datalink_protocol::change_address(), and IFF_UP changes to
740 	net_datalink_protocol::interface_up(), and interface_down().
741 
742 	Everything else is passed unchanged to net_datalink_protocol::control().
743 */
744 status_t
745 Interface::Control(net_domain* domain, int32 option, ifreq& request,
746 	ifreq* userRequest, size_t length)
747 {
748 	switch (option) {
749 		case SIOCSIFFLAGS:
750 		{
751 			if (length != sizeof(ifreq))
752 				return B_BAD_VALUE;
753 
754 			uint32 requestFlags = request.ifr_flags;
755 			uint32 oldFlags = flags;
756 			status_t status = B_OK;
757 
758 			request.ifr_flags &= ~(IFF_UP | IFF_LINK | IFF_BROADCAST);
759 
760 			if ((requestFlags & IFF_UP) != (flags & IFF_UP)) {
761 				if ((requestFlags & IFF_UP) != 0)
762 					status = _SetUp();
763 				else
764 					SetDown();
765 			}
766 
767 			if (status == B_OK) {
768 				// TODO: maybe allow deleting IFF_BROADCAST on the interface
769 				// level?
770 				flags &= IFF_UP | IFF_LINK | IFF_BROADCAST;
771 				flags |= request.ifr_flags;
772 			}
773 
774 			if (oldFlags != flags) {
775 				TRACE("Interface %p: flags changed from %" B_PRIx32 " to %"
776 					B_PRIx32 "\n", this, oldFlags, flags);
777 				notify_interface_changed(this, oldFlags, flags);
778 			}
779 
780 			return status;
781 		}
782 
783 		case B_SOCKET_SET_ALIAS:
784 		{
785 			if (length != sizeof(ifaliasreq))
786 				return B_BAD_VALUE;
787 
788 			RecursiveLocker locker(fLock);
789 
790 			ifaliasreq aliasRequest;
791 			if (user_memcpy(&aliasRequest, userRequest, sizeof(ifaliasreq))
792 					!= B_OK)
793 				return B_BAD_ADDRESS;
794 
795 			InterfaceAddress* address = NULL;
796 			if (aliasRequest.ifra_index < 0) {
797 				if (!domain->address_module->is_empty_address(
798 						(const sockaddr*)&aliasRequest.ifra_addr, false)) {
799 					// Find first address that matches the local address
800 					address = AddressForLocal(domain,
801 						(const sockaddr*)&aliasRequest.ifra_addr);
802 				}
803 				if (address == NULL) {
804 					// Find first address for family
805 					address = FirstForFamily(domain->family);
806 				}
807 				if (address == NULL) {
808 					// Create new on the fly
809 					address = new(std::nothrow) InterfaceAddress(this, domain);
810 					if (address == NULL)
811 						return B_NO_MEMORY;
812 
813 					status_t status = AddAddress(address);
814 					if (status != B_OK) {
815 						delete address;
816 						return status;
817 					}
818 
819 					// Note, even if setting the address failed, the empty
820 					// address added here will still be added to the interface.
821 					address->AcquireReference();
822 				}
823 			} else
824 				address = AddressAt(aliasRequest.ifra_index);
825 
826 			if (address == NULL)
827 				return B_BAD_VALUE;
828 
829 			status_t status = B_OK;
830 
831 			if (!domain->address_module->equal_addresses(
832 					(sockaddr*)&aliasRequest.ifra_addr, address->local)) {
833 				status = _ChangeAddress(locker, address, SIOCSIFADDR,
834 					address->local, (sockaddr*)&aliasRequest.ifra_addr);
835 			}
836 
837 			if (status == B_OK && !domain->address_module->equal_addresses(
838 					(sockaddr*)&aliasRequest.ifra_mask, address->mask)
839 				&& !domain->address_module->is_empty_address(
840 					(sockaddr*)&aliasRequest.ifra_mask, false)) {
841 				status = _ChangeAddress(locker, address, SIOCSIFNETMASK,
842 					address->mask, (sockaddr*)&aliasRequest.ifra_mask);
843 			}
844 
845 			if (status == B_OK && !domain->address_module->equal_addresses(
846 					(sockaddr*)&aliasRequest.ifra_destination,
847 					address->destination)
848 				&& !domain->address_module->is_empty_address(
849 					(sockaddr*)&aliasRequest.ifra_destination, false)) {
850 				status = _ChangeAddress(locker, address,
851 					(domain->address_module->flags
852 						& NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS) != 0
853 							? SIOCSIFBRDADDR : SIOCSIFDSTADDR,
854 					address->destination,
855 					(sockaddr*)&aliasRequest.ifra_destination);
856 			}
857 
858 			address->ReleaseReference();
859 			return status;
860 		}
861 
862 		case SIOCSIFADDR:
863 		case SIOCSIFNETMASK:
864 		case SIOCSIFBRDADDR:
865 		case SIOCSIFDSTADDR:
866 		case SIOCDIFADDR:
867 		{
868 			if (length != sizeof(ifreq))
869 				return B_BAD_VALUE;
870 
871 			RecursiveLocker locker(fLock);
872 
873 			InterfaceAddress* address = NULL;
874 			sockaddr_storage newAddress;
875 
876 			size_t size = max_c(request.ifr_addr.sa_len, sizeof(sockaddr));
877 			if (size > sizeof(sockaddr_storage))
878 				size = sizeof(sockaddr_storage);
879 
880 			if (user_memcpy(&newAddress, &userRequest->ifr_addr, size) != B_OK)
881 				return B_BAD_ADDRESS;
882 
883 			if (option == SIOCDIFADDR) {
884 				// Find referring address - we can't use the hash, as another
885 				// interface might use the same address.
886 				AddressList::Iterator iterator = fAddresses.GetIterator();
887 				while ((address = iterator.Next()) != NULL) {
888 					if (address->domain == domain
889 						&& domain->address_module->equal_addresses(
890 							address->local, (sockaddr*)&newAddress))
891 						break;
892 				}
893 
894 				if (address == NULL)
895 					return B_BAD_VALUE;
896 			} else {
897 				// Just use the first address for this family
898 				address = _FirstForFamily(domain->family);
899 				if (address == NULL) {
900 					// Create new on the fly
901 					address = new(std::nothrow) InterfaceAddress(this, domain);
902 					if (address == NULL)
903 						return B_NO_MEMORY;
904 
905 					status_t status = AddAddress(address);
906 					if (status != B_OK) {
907 						delete address;
908 						return status;
909 					}
910 
911 					// Note, even if setting the address failed, the empty
912 					// address added here will still be added to the interface.
913 				}
914 			}
915 
916 			return _ChangeAddress(locker, address, option,
917 				*address->AddressFor(option),
918 				option != SIOCDIFADDR ? (sockaddr*)&newAddress : NULL);
919 		}
920 
921 		default:
922 			// pass the request into the datalink protocol stack
923 			domain_datalink* datalink = DomainDatalink(domain->family);
924 			if (datalink->first_info != NULL) {
925 				return datalink->first_info->control(
926 					datalink->first_protocol, option, userRequest, length);
927 			}
928 			break;
929 	}
930 
931 	return B_BAD_VALUE;
932 }
933 
934 
935 void
936 Interface::SetDown()
937 {
938 	if ((flags & IFF_UP) == 0)
939 		return;
940 
941 	RecursiveLocker interfacesLocker(sLock);
942 
943 	if (IsBusy())
944 		return;
945 
946 	SetBusy(true);
947 	interfacesLocker.Unlock();
948 
949 	DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator();
950 	while (domain_datalink* datalink = iterator.Next()) {
951 		datalink->first_info->interface_down(datalink->first_protocol);
952 	}
953 
954 	flags &= ~IFF_UP;
955 
956 	SetBusy(false);
957 }
958 
959 
960 /*!	Called when a device lost its IFF_UP status. We will invalidate all
961 	interface routes here.
962 */
963 void
964 Interface::WentDown()
965 {
966 	TRACE("Interface %p: went down\n", this);
967 
968 	RecursiveLocker locker(fLock);
969 
970 	AddressList::Iterator iterator = fAddresses.GetIterator();
971 	while (InterfaceAddress* address = iterator.Next()) {
972 		if (address->domain != NULL)
973 			invalidate_routes(address->domain, this);
974 	}
975 }
976 
977 
978 status_t
979 Interface::CreateDomainDatalinkIfNeeded(net_domain* domain)
980 {
981 	RecursiveLocker locker(fLock);
982 
983 	if (fDatalinkTable.Lookup(domain->family) != NULL)
984 		return B_OK;
985 
986 	TRACE("Interface %p: create domain datalink for domain %p\n", this, domain);
987 
988 	domain_datalink* datalink = new(std::nothrow) domain_datalink;
989 	if (datalink == NULL)
990 		return B_NO_MEMORY;
991 
992 	datalink->first_protocol = NULL;
993 	datalink->first_info = NULL;
994 	datalink->domain = domain;
995 
996 	// setup direct route for bound devices
997 	datalink->direct_route.destination = NULL;
998 	datalink->direct_route.mask = NULL;
999 	datalink->direct_route.gateway = NULL;
1000 	datalink->direct_route.flags = 0;
1001 	datalink->direct_route.mtu = 0;
1002 	datalink->direct_route.interface_address = &datalink->direct_address;
1003 	datalink->direct_route.ref_count = 1;
1004 		// make sure this doesn't get deleted accidently
1005 
1006 	// provide its link back to the interface
1007 	datalink->direct_address.local = NULL;
1008 	datalink->direct_address.destination = NULL;
1009 	datalink->direct_address.mask = NULL;
1010 	datalink->direct_address.domain = domain;
1011 	datalink->direct_address.interface = this;
1012 	datalink->direct_address.flags = IFAF_DIRECT_ADDRESS;
1013 
1014 	fDatalinkTable.Insert(datalink);
1015 
1016 	status_t status = get_domain_datalink_protocols(this, domain);
1017 	if (status == B_OK)
1018 		return B_OK;
1019 
1020 	fDatalinkTable.Remove(datalink);
1021 	delete datalink;
1022 
1023 	return status;
1024 }
1025 
1026 
1027 domain_datalink*
1028 Interface::DomainDatalink(uint8 family)
1029 {
1030 	// Note: domain datalinks cannot be removed while the interface is alive,
1031 	// since this would require us either to hold the lock while calling this
1032 	// function, or introduce reference counting for the domain_datalink
1033 	// structure.
1034 	RecursiveLocker locker(fLock);
1035 	return fDatalinkTable.Lookup(family);
1036 }
1037 
1038 
1039 #if ENABLE_DEBUGGER_COMMANDS
1040 
1041 
1042 void
1043 Interface::Dump() const
1044 {
1045 	kprintf("name:                %s\n", name);
1046 	kprintf("device:              %p\n", device);
1047 	kprintf("device_interface:    %p\n", fDeviceInterface);
1048 	kprintf("index:               %" B_PRIu32 "\n", index);
1049 	kprintf("flags:               %#" B_PRIx32 "\n", flags);
1050 	kprintf("type:                %u\n", type);
1051 	kprintf("metric:              %" B_PRIu32 "\n", metric);
1052 	kprintf("ref count:           %" B_PRId32 "\n", CountReferences());
1053 
1054 	kprintf("datalink protocols:\n");
1055 
1056 	DatalinkTable::Iterator datalinkIterator = fDatalinkTable.GetIterator();
1057 	size_t i = 0;
1058 	while (domain_datalink* datalink = datalinkIterator.Next()) {
1059 		kprintf("%2zu. domain:          %p\n", ++i, datalink->domain);
1060 		kprintf("    first_protocol:  %p\n", datalink->first_protocol);
1061 		kprintf("    first_info:      %p\n", datalink->first_info);
1062 		kprintf("    direct_route:    %p\n", &datalink->direct_route);
1063 	}
1064 
1065 	kprintf("addresses:\n");
1066 
1067 	AddressList::ConstIterator iterator = fAddresses.GetIterator();
1068 	i = 0;
1069 	while (InterfaceAddress* address = iterator.Next()) {
1070 		address->Dump(++i, true);
1071 	}
1072 }
1073 
1074 
1075 #endif	// ENABLE_DEBUGGER_COMMANDS
1076 
1077 
1078 status_t
1079 Interface::_SetUp()
1080 {
1081 	status_t status = up_device_interface(fDeviceInterface);
1082 	if (status != B_OK)
1083 		return status;
1084 
1085 	RecursiveLocker interfacesLocker(sLock);
1086 	SetBusy(true);
1087 	interfacesLocker.Unlock();
1088 
1089 	// Propagate flag to all datalink protocols
1090 	DatalinkTable::Iterator iterator = fDatalinkTable.GetIterator();
1091 	while (domain_datalink* datalink = iterator.Next()) {
1092 		status = datalink->first_info->interface_up(datalink->first_protocol);
1093 		if (status != B_OK) {
1094 			// Revert "up" status
1095 			DatalinkTable::Iterator secondIterator
1096 				= fDatalinkTable.GetIterator();
1097 			while (secondIterator.HasNext()) {
1098 				domain_datalink* secondDatalink = secondIterator.Next();
1099 				if (secondDatalink == NULL || secondDatalink == datalink)
1100 					break;
1101 
1102 				secondDatalink->first_info->interface_down(
1103 					secondDatalink->first_protocol);
1104 			}
1105 
1106 			down_device_interface(fDeviceInterface);
1107 			SetBusy(false);
1108 			return status;
1109 		}
1110 	}
1111 
1112 	// Add default routes for the existing addresses
1113 
1114 	AddressList::Iterator addressIterator = fAddresses.GetIterator();
1115 	while (InterfaceAddress* address = addressIterator.Next()) {
1116 		address->AddDefaultRoutes(SIOCSIFADDR);
1117 	}
1118 
1119 	flags |= IFF_UP;
1120 	SetBusy(false);
1121 
1122 	return B_OK;
1123 }
1124 
1125 
1126 InterfaceAddress*
1127 Interface::_FirstForFamily(int family)
1128 {
1129 	ASSERT_LOCKED_RECURSIVE(&fLock);
1130 
1131 	AddressList::Iterator iterator = fAddresses.GetIterator();
1132 	while (InterfaceAddress* address = iterator.Next()) {
1133 		if (address->domain != NULL && address->domain->family == family)
1134 			return address;
1135 	}
1136 
1137 	return NULL;
1138 }
1139 
1140 
1141 status_t
1142 Interface::_ChangeAddress(RecursiveLocker& locker, InterfaceAddress* address,
1143 	int32 option, const sockaddr* originalAddress,
1144 	const sockaddr* requestedAddress)
1145 {
1146 	// Copy old address
1147 	sockaddr_storage oldAddress;
1148 	if (address->domain->address_module->set_to((sockaddr*)&oldAddress,
1149 			originalAddress) != B_OK)
1150 		oldAddress.ss_family = AF_UNSPEC;
1151 
1152 	// Copy new address (this also makes sure that sockaddr::sa_len is set
1153 	// correctly)
1154 	sockaddr_storage newAddress;
1155 	if (address->domain->address_module->set_to((sockaddr*)&newAddress,
1156 			requestedAddress) != B_OK)
1157 		newAddress.ss_family = AF_UNSPEC;
1158 
1159 	// Test if anything changed for real
1160 	if (address->domain->address_module->equal_addresses(
1161 			(sockaddr*)&oldAddress, (sockaddr*)&newAddress)) {
1162 		// Nothing to do
1163 		TRACE("  option %" B_PRId32 " addresses are equal!\n", option);
1164 		return B_OK;
1165 	}
1166 
1167 	// TODO: mark this address busy or call while holding the lock!
1168 	address->AcquireReference();
1169 	locker.Unlock();
1170 
1171 	domain_datalink* datalink = DomainDatalink(address->domain);
1172 	status_t status = datalink->first_protocol->module->change_address(
1173 		datalink->first_protocol, address, option,
1174 		oldAddress.ss_family != AF_UNSPEC ? (sockaddr*)&oldAddress : NULL,
1175 		newAddress.ss_family != AF_UNSPEC ? (sockaddr*)&newAddress : NULL);
1176 
1177 	locker.Lock();
1178 	address->ReleaseReference();
1179 	return status;
1180 }
1181 
1182 
1183 // #pragma mark -
1184 
1185 
1186 /*!	Searches for a specific interface by name.
1187 	You need to have the interface list's lock hold when calling this function.
1188 */
1189 static Interface*
1190 find_interface(const char* name)
1191 {
1192 	ASSERT_LOCKED_RECURSIVE(&sLock);
1193 
1194 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1195 	while (Interface* interface = iterator.Next()) {
1196 		if (!strcmp(interface->name, name))
1197 			return interface;
1198 	}
1199 
1200 	return NULL;
1201 }
1202 
1203 
1204 /*!	Searches for a specific interface by index.
1205 	You need to have the interface list's lock hold when calling this function.
1206 */
1207 static Interface*
1208 find_interface(uint32 index)
1209 {
1210 	ASSERT_LOCKED_RECURSIVE(&sLock);
1211 
1212 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1213 	while (Interface* interface = iterator.Next()) {
1214 		if (interface->index == index)
1215 			return interface;
1216 	}
1217 
1218 	return NULL;
1219 }
1220 
1221 
1222 // #pragma mark -
1223 
1224 
1225 status_t
1226 add_interface(const char* name, net_domain_private* domain,
1227 	const ifaliasreq& request, net_device_interface* deviceInterface)
1228 {
1229 	RecursiveLocker locker(sLock);
1230 
1231 	if (find_interface(name) != NULL)
1232 		return B_NAME_IN_USE;
1233 
1234 	Interface* interface
1235 		= new(std::nothrow) Interface(name, deviceInterface);
1236 	if (interface == NULL)
1237 		return B_NO_MEMORY;
1238 
1239 	sInterfaces.Add(interface);
1240 	interface->AcquireReference();
1241 		// We need another reference to be able to use the interface without
1242 		// holding sLock.
1243 
1244 	locker.Unlock();
1245 
1246 	status_t status = add_interface_address(interface, domain, request);
1247 	if (status == B_OK)
1248 		notify_interface_added(interface);
1249 	else {
1250 		locker.Lock();
1251 		sInterfaces.Remove(interface);
1252 		locker.Unlock();
1253 		interface->ReleaseReference();
1254 	}
1255 
1256 	interface->ReleaseReference();
1257 
1258 	return status;
1259 }
1260 
1261 
1262 /*!	Removes the interface from the list, and puts the stack's reference to it.
1263 */
1264 void
1265 remove_interface(Interface* interface)
1266 {
1267 	interface->SetDown();
1268 	interface->RemoveAddresses();
1269 
1270 	RecursiveLocker locker(sLock);
1271 	sInterfaces.Remove(interface);
1272 	locker.Unlock();
1273 
1274 	notify_interface_removed(interface);
1275 
1276 	interface->ReleaseReference();
1277 }
1278 
1279 
1280 /*!	This is called whenever a device interface is being removed. We will get
1281 	the corresponding Interface, and remove it.
1282 */
1283 void
1284 interface_removed_device_interface(net_device_interface* deviceInterface)
1285 {
1286 	RecursiveLocker locker(sLock);
1287 
1288 	Interface* interface = find_interface(deviceInterface->device->name);
1289 	if (interface != NULL)
1290 		remove_interface(interface);
1291 }
1292 
1293 
1294 status_t
1295 add_interface_address(Interface* interface, net_domain_private* domain,
1296 	const ifaliasreq& request)
1297 {
1298 	// Make sure the family of the provided addresses is valid
1299 	if ((request.ifra_addr.ss_family != domain->family
1300 			&& request.ifra_addr.ss_family != AF_UNSPEC)
1301 		|| (request.ifra_mask.ss_family != domain->family
1302 			&& request.ifra_mask.ss_family != AF_UNSPEC)
1303 		|| (request.ifra_broadaddr.ss_family != domain->family
1304 			&& request.ifra_broadaddr.ss_family != AF_UNSPEC))
1305 		return B_BAD_VALUE;
1306 
1307 	RecursiveLocker locker(interface->Lock());
1308 
1309 	InterfaceAddress* address
1310 		= new(std::nothrow) InterfaceAddress(interface, domain);
1311 	if (address == NULL)
1312 		return B_NO_MEMORY;
1313 
1314 	status_t status = address->SetTo(request);
1315 	if (status == B_OK)
1316 		status = interface->CreateDomainDatalinkIfNeeded(domain);
1317 	if (status == B_OK)
1318 		status = interface->AddAddress(address);
1319 
1320 	if (status == B_OK && address->local != NULL) {
1321 		// update the datalink protocols
1322 		domain_datalink* datalink = interface->DomainDatalink(domain->family);
1323 
1324 		status = datalink->first_protocol->module->change_address(
1325 			datalink->first_protocol, address, SIOCAIFADDR, NULL,
1326 			address->local);
1327 		if (status != B_OK)
1328 			interface->RemoveAddress(address);
1329 	}
1330 	if (status == B_OK)
1331 		notify_interface_changed(interface);
1332 	else
1333 		delete address;
1334 
1335 	return status;
1336 }
1337 
1338 
1339 status_t
1340 update_interface_address(InterfaceAddress* interfaceAddress, int32 option,
1341 	const sockaddr* oldAddress, const sockaddr* newAddress)
1342 {
1343 	TRACE("%s(address %p, option %" B_PRId32 ", oldAddress %s, newAddress "
1344 		"%s)\n", __FUNCTION__, interfaceAddress, option,
1345 		AddressString(interfaceAddress->domain, oldAddress).Data(),
1346 		AddressString(interfaceAddress->domain, newAddress).Data());
1347 
1348 	MutexLocker locker(sHashLock);
1349 
1350 	// set logical interface address
1351 	sockaddr** _address = interfaceAddress->AddressFor(option);
1352 	if (_address == NULL)
1353 		return B_BAD_VALUE;
1354 
1355 	Interface* interface = (Interface*)interfaceAddress->interface;
1356 
1357 	interfaceAddress->RemoveDefaultRoutes(option);
1358 
1359 	if (option == SIOCDIFADDR) {
1360 		// Remove address, and release its reference (causing our caller to
1361 		// delete it)
1362 		locker.Unlock();
1363 
1364 		invalidate_routes(interfaceAddress);
1365 
1366 		interface->RemoveAddress(interfaceAddress);
1367 		interfaceAddress->ReleaseReference();
1368 		return B_OK;
1369 	}
1370 
1371 	if (interfaceAddress->LocalIsDefined())
1372 		sAddressTable.Remove(interfaceAddress);
1373 
1374 	// Copy new address over
1375 	status_t status = InterfaceAddress::Set(_address, newAddress);
1376 	if (status == B_OK) {
1377 		sockaddr* address = *_address;
1378 
1379 		if (option == SIOCSIFADDR || option == SIOCSIFNETMASK) {
1380 			// Reset netmask and broadcast addresses to defaults
1381 			net_domain* domain = interfaceAddress->domain;
1382 			sockaddr* defaultNetmask = NULL;
1383 			const sockaddr* netmask = NULL;
1384 			if (option == SIOCSIFADDR) {
1385 				defaultNetmask = InterfaceAddress::Prepare(
1386 					&interfaceAddress->mask, address->sa_len);
1387 			} else
1388 				netmask = newAddress;
1389 
1390 			// Reset the broadcast address if the address family has
1391 			// such
1392 			sockaddr* defaultBroadcast = NULL;
1393 			if ((domain->address_module->flags
1394 					& NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS) != 0) {
1395 				defaultBroadcast = InterfaceAddress::Prepare(
1396 					&interfaceAddress->destination, address->sa_len);
1397 			} else
1398 				InterfaceAddress::Set(&interfaceAddress->destination, NULL);
1399 
1400 			domain->address_module->set_to_defaults(defaultNetmask,
1401 				defaultBroadcast, interfaceAddress->local, netmask);
1402 		}
1403 
1404 		interfaceAddress->AddDefaultRoutes(option);
1405 		notify_interface_changed(interface);
1406 	}
1407 
1408 	if (interfaceAddress->LocalIsDefined())
1409 		sAddressTable.Insert(interfaceAddress);
1410 	return status;
1411 }
1412 
1413 
1414 Interface*
1415 get_interface(net_domain* domain, uint32 index)
1416 {
1417 	RecursiveLocker locker(sLock);
1418 
1419 	Interface* interface;
1420 	if (index == 0)
1421 		interface = sInterfaces.First();
1422 	else
1423 		interface = find_interface(index);
1424 	if (interface == NULL || interface->IsBusy())
1425 		return NULL;
1426 
1427 	// We must unlock before invoking CreateDomainDatalinkIfNeeded, because
1428 	// otherwise we can hit lock ordering inversions with receive threads,
1429 	// usually in register_device_handler.
1430 	BReference<Interface> interfaceRef(interface);
1431 	locker.Unlock();
1432 
1433 	if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK)
1434 		return NULL;
1435 
1436 	return interfaceRef.Detach();
1437 }
1438 
1439 
1440 Interface*
1441 get_interface(net_domain* domain, const char* name)
1442 {
1443 	RecursiveLocker locker(sLock);
1444 
1445 	Interface* interface = find_interface(name);
1446 	if (interface == NULL || interface->IsBusy())
1447 		return NULL;
1448 
1449 	// See comment in get_interface.
1450 	BReference<Interface> interfaceRef(interface);
1451 	locker.Unlock();
1452 
1453 	if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK)
1454 		return NULL;
1455 
1456 	return interfaceRef.Detach();
1457 }
1458 
1459 
1460 Interface*
1461 get_interface_for_device(net_domain* domain, uint32 index)
1462 {
1463 	RecursiveLocker locker(sLock);
1464 
1465 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1466 	while (Interface* interface = iterator.Next()) {
1467 		if (interface->device->index == index) {
1468 			if (interface->IsBusy())
1469 				return NULL;
1470 
1471 			// See comment in get_interface.
1472 			BReference<Interface> interfaceRef(interface);
1473 			locker.Unlock();
1474 
1475 			if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK)
1476 				return NULL;
1477 
1478 			return interfaceRef.Detach();
1479 		}
1480 	}
1481 
1482 	return NULL;
1483 }
1484 
1485 
1486 /*!	Returns a reference to an Interface that matches the given \a linkAddress.
1487 	The link address is checked against its hardware address, or its interface
1488 	name, or finally the interface index.
1489 */
1490 Interface*
1491 get_interface_for_link(net_domain* domain, const sockaddr* _linkAddress)
1492 {
1493 	sockaddr_dl& linkAddress = *(sockaddr_dl*)_linkAddress;
1494 
1495 	RecursiveLocker locker(sLock);
1496 
1497 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1498 	while (Interface* interface = iterator.Next()) {
1499 		if (interface->IsBusy())
1500 			continue;
1501 		// Test if the hardware address matches, or if the given interface
1502 		// matches, or if at least the index matches.
1503 		if ((linkAddress.sdl_alen == interface->device->address.length
1504 				&& memcmp(LLADDR(&linkAddress), interface->device->address.data,
1505 					linkAddress.sdl_alen) == 0)
1506 			|| (linkAddress.sdl_nlen > 0
1507 				&& !strcmp(interface->name, (const char*)linkAddress.sdl_data))
1508 			|| (linkAddress.sdl_nlen == 0 && linkAddress.sdl_alen == 0
1509 				&& linkAddress.sdl_index == interface->index)) {
1510 			if (interface->IsBusy())
1511 				return NULL;
1512 
1513 			// See comment in get_interface.
1514 			BReference<Interface> interfaceRef(interface);
1515 			locker.Unlock();
1516 
1517 			if (interface->CreateDomainDatalinkIfNeeded(domain) != B_OK)
1518 				return NULL;
1519 
1520 			return interfaceRef.Detach();
1521 		}
1522 	}
1523 
1524 	return NULL;
1525 }
1526 
1527 
1528 InterfaceAddress*
1529 get_interface_address(const sockaddr* local)
1530 {
1531 	if (local->sa_family == AF_UNSPEC)
1532 		return NULL;
1533 
1534 	MutexLocker locker(sHashLock);
1535 
1536 	InterfaceAddress* address = sAddressTable.Lookup(local);
1537 	if (address == NULL)
1538 		return NULL;
1539 
1540 	address->AcquireReference();
1541 	return address;
1542 }
1543 
1544 
1545 InterfaceAddress*
1546 get_interface_address_for_destination(net_domain* domain,
1547 	const sockaddr* destination)
1548 {
1549 	RecursiveLocker locker(sLock);
1550 
1551 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1552 	while (Interface* interface = iterator.Next()) {
1553 		if (interface->IsBusy())
1554 			continue;
1555 
1556 		InterfaceAddress* address
1557 			= interface->AddressForDestination(domain, destination);
1558 		if (address != NULL)
1559 			return address;
1560 	}
1561 
1562 	return NULL;
1563 }
1564 
1565 
1566 /*!	Returns a reference to an InterfaceAddress of the specified \a domain that
1567 	belongs to the interface identified via \a linkAddress. Only the hardware
1568 	address is matched.
1569 
1570 	If \a unconfiguredOnly is set, the interface address must not yet be
1571 	configured, or must currently be in the process of being configured.
1572 */
1573 InterfaceAddress*
1574 get_interface_address_for_link(net_domain* domain, const sockaddr* address,
1575 	bool unconfiguredOnly)
1576 {
1577 	sockaddr_dl& linkAddress = *(sockaddr_dl*)address;
1578 
1579 	RecursiveLocker locker(sLock);
1580 
1581 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1582 	while (Interface* interface = iterator.Next()) {
1583 		if (interface->IsBusy())
1584 			continue;
1585 		// Test if the hardware address matches, or if the given interface
1586 		// matches, or if at least the index matches.
1587 		if (linkAddress.sdl_alen == interface->device->address.length
1588 			&& memcmp(LLADDR(&linkAddress), interface->device->address.data,
1589 				linkAddress.sdl_alen) == 0) {
1590 			TRACE("  %s matches\n", interface->name);
1591 			// link address matches
1592 			if (unconfiguredOnly)
1593 				return interface->FirstUnconfiguredForFamily(domain->family);
1594 
1595 			return interface->FirstForFamily(domain->family);
1596 		}
1597 	}
1598 
1599 	return NULL;
1600 }
1601 
1602 
1603 uint32
1604 count_interfaces()
1605 {
1606 	RecursiveLocker locker(sLock);
1607 
1608 	return sInterfaces.Count();
1609 }
1610 
1611 
1612 /*!	Dumps a list of all interfaces into the supplied userland buffer.
1613 	If the interfaces don't fit into the buffer, an error (\c ENOBUFS) is
1614 	returned.
1615 */
1616 status_t
1617 list_interfaces(int family, void* _buffer, size_t* bufferSize)
1618 {
1619 	RecursiveLocker locker(sLock);
1620 
1621 	UserBuffer buffer(_buffer, *bufferSize);
1622 
1623 	InterfaceList::Iterator iterator = sInterfaces.GetIterator();
1624 	while (Interface* interface = iterator.Next()) {
1625 		// Copy name
1626 		buffer.Push(interface->name, IF_NAMESIZE);
1627 
1628 		// Copy address
1629 		InterfaceAddress* address = interface->FirstForFamily(family);
1630 		size_t length = 0;
1631 
1632 		if (address != NULL && address->local != NULL) {
1633 			// Actual address
1634 			buffer.Push(address->local, length = address->local->sa_len);
1635 		} else {
1636 			// Empty address
1637 			sockaddr empty;
1638 			empty.sa_len = 2;
1639 			empty.sa_family = AF_UNSPEC;
1640 			buffer.Push(&empty, length = empty.sa_len);
1641 		}
1642 
1643 		if (address != NULL)
1644 			address->ReleaseReference();
1645 
1646 		if (IF_NAMESIZE + length < sizeof(ifreq)) {
1647 			// Make sure at least sizeof(ifreq) bytes are written for each
1648 			// interface for compatibility with other platforms
1649 			buffer.Pad(sizeof(ifreq) - IF_NAMESIZE - length);
1650 		}
1651 
1652 		if (buffer.Status() != B_OK)
1653 			return buffer.Status();
1654 	}
1655 
1656 	*bufferSize = buffer.BytesConsumed();
1657 	return B_OK;
1658 }
1659 
1660 
1661 //	#pragma mark -
1662 
1663 
1664 status_t
1665 init_interfaces()
1666 {
1667 	recursive_lock_init(&sLock, "net interfaces");
1668 	mutex_init(&sHashLock, "net local addresses");
1669 
1670 	new (&sInterfaces) InterfaceList;
1671 	new (&sAddressTable) AddressTable;
1672 		// static C++ objects are not initialized in the module startup
1673 
1674 #if ENABLE_DEBUGGER_COMMANDS
1675 	add_debugger_command("net_interface", &dump_interface,
1676 		"Dump the given network interface");
1677 	add_debugger_command("net_interfaces", &dump_interfaces,
1678 		"Dump all network interfaces");
1679 	add_debugger_command("net_local", &dump_local,
1680 		"Dump all local interface addresses");
1681 	add_debugger_command("net_route", &dump_route,
1682 		"Dump the given network route");
1683 #endif
1684 	return B_OK;
1685 }
1686 
1687 
1688 status_t
1689 uninit_interfaces()
1690 {
1691 #if ENABLE_DEBUGGER_COMMANDS
1692 	remove_debugger_command("net_interface", &dump_interface);
1693 	remove_debugger_command("net_interfaces", &dump_interfaces);
1694 	remove_debugger_command("net_local", &dump_local);
1695 	remove_debugger_command("net_route", &dump_route);
1696 #endif
1697 
1698 	recursive_lock_destroy(&sLock);
1699 	mutex_destroy(&sHashLock);
1700 	return B_OK;
1701 }
1702 
1703