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