2 * Copyright 2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Adrien Destugues, pulkomandy@pulkomandy.tk
7 * Axel Dörfler, axeld@pinc-software.de
16 #include <netinet/in.h>
19 #include <sys/socket.h>
20 #include <sys/sockio.h>
23 #include <AutoDeleter.h>
29 copy_address(const sockaddr
& address
)
31 if (address
.sa_family
== AF_UNSPEC
)
34 sockaddr_storage
* copy
= new (std::nothrow
) sockaddr_storage
;
38 size_t length
= std::min(sizeof(sockaddr_storage
), (size_t)address
.sa_len
);
39 switch (address
.sa_family
) {
41 length
= sizeof(sockaddr_in
);
44 length
= sizeof(sockaddr_in6
);
47 memcpy(copy
, &address
, length
);
48 copy
->ss_len
= length
;
49 return (sockaddr
*)copy
;
53 /*! Returns a chained list of all interfaces.
55 We follow BSD semantics, and only return one entry per interface,
56 not per address; since this is mainly used by NetBSD's netresolv, it's
57 probably what it expects.
60 getifaddrs(struct ifaddrs
** _ifaddrs
)
62 if (_ifaddrs
== NULL
) {
67 int socket
= ::socket(AF_INET
, SOCK_DGRAM
, 0);
71 FileDescriptorCloser
closer(socket
);
73 // Get interface count
75 config
.ifc_len
= sizeof(config
.ifc_value
);
76 if (ioctl(socket
, SIOCGIFCOUNT
, &config
, sizeof(struct ifconf
)) < 0)
79 size_t count
= (size_t)config
.ifc_value
;
81 // No interfaces found
86 // Allocate a buffer for ifreqs for all interfaces
87 char* buffer
= (char*)malloc(count
* sizeof(struct ifreq
));
93 MemoryDeleter
deleter(buffer
);
95 // Get interfaces configuration
96 config
.ifc_len
= count
* sizeof(struct ifreq
);
97 config
.ifc_buf
= buffer
;
98 if (ioctl(socket
, SIOCGIFCONF
, &config
, sizeof(struct ifconf
)) < 0)
101 ifreq
* interfaces
= (ifreq
*)buffer
;
102 ifreq
* end
= (ifreq
*)(buffer
+ config
.ifc_len
);
103 struct ifaddrs
* previous
= NULL
;
105 for (uint32_t i
= 0; interfaces
< end
; i
++) {
106 struct ifaddrs
* current
= new(std::nothrow
) ifaddrs();
107 if (current
== NULL
) {
108 freeifaddrs(previous
);
113 // Chain this interface with the next one
114 current
->ifa_next
= previous
;
117 current
->ifa_name
= strdup(interfaces
[0].ifr_name
);
118 current
->ifa_addr
= copy_address(interfaces
[0].ifr_addr
);
119 current
->ifa_netmask
= NULL
;
120 current
->ifa_dstaddr
= NULL
;
121 current
->ifa_data
= NULL
;
124 strlcpy(request
.ifr_name
, interfaces
[0].ifr_name
, IF_NAMESIZE
);
126 if (ioctl(socket
, SIOCGIFFLAGS
, &request
, sizeof(struct ifreq
)) == 0)
127 current
->ifa_flags
= request
.ifr_flags
;
128 if (ioctl(socket
, SIOCGIFNETMASK
, &request
, sizeof(struct ifreq
))
130 current
->ifa_netmask
= copy_address(request
.ifr_mask
);
132 if (ioctl(socket
, SIOCGIFDSTADDR
, &request
, sizeof(struct ifreq
))
134 current
->ifa_dstaddr
= copy_address(request
.ifr_dstaddr
);
137 // Move on to next interface
138 interfaces
= (ifreq
*)((uint8_t*)interfaces
139 + _SIZEOF_ADDR_IFREQ(interfaces
[0]));
142 *_ifaddrs
= previous
;
148 freeifaddrs(struct ifaddrs
* ifa
)
150 while (ifa
!= NULL
) {
151 free((void*)ifa
->ifa_name
);
152 delete ifa
->ifa_addr
;
153 delete ifa
->ifa_netmask
;
154 delete ifa
->ifa_dstaddr
;
156 struct ifaddrs
* next
= ifa
->ifa_next
;