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