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