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