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