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