tevent: let epoll_check_reopen() clear all events before reopening them
[Samba.git] / lib / replace / getifaddrs.c
bloba55ef7e30feeb1e73f1b0d9730e12408729b1eee
1 /*
2 Unix SMB/CIFS implementation.
3 Samba utility functions
4 Copyright (C) Andrew Tridgell 1998
5 Copyright (C) Jeremy Allison 2007
6 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
8 ** NOTE! The following LGPL license applies to the replace
9 ** library. This does NOT imply that all of Samba is released
10 ** under the LGPL
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 3 of the License, or (at your option) any later version.
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Library General Public License for more details.
22 You should have received a copy of the GNU Lesser General Public
23 License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 #include "replace.h"
27 #include "system/network.h"
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <sys/types.h>
33 #ifdef HAVE_SYS_TIME_H
34 #include <sys/time.h>
35 #endif
37 #ifndef SIOCGIFCONF
38 #ifdef HAVE_SYS_SOCKIO_H
39 #include <sys/sockio.h>
40 #endif
41 #endif
43 #ifdef HAVE_IFACE_GETIFADDRS
44 #define _FOUND_IFACE_ANY
45 #else
47 void rep_freeifaddrs(struct ifaddrs *ifp)
49 if (ifp != NULL) {
50 free(ifp->ifa_name);
51 free(ifp->ifa_addr);
52 free(ifp->ifa_netmask);
53 free(ifp->ifa_dstaddr);
54 freeifaddrs(ifp->ifa_next);
55 free(ifp);
59 static struct sockaddr *sockaddr_dup(struct sockaddr *sa)
61 struct sockaddr *ret;
62 socklen_t socklen;
63 #ifdef HAVE_SOCKADDR_SA_LEN
64 socklen = sa->sa_len;
65 #else
66 socklen = sizeof(struct sockaddr_storage);
67 #endif
68 ret = calloc(1, socklen);
69 if (ret == NULL)
70 return NULL;
71 memcpy(ret, sa, socklen);
72 return ret;
74 #endif
76 #ifdef HAVE_IFACE_IFCONF
78 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
79 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
81 It probably also works on any BSD style system. */
83 int rep_getifaddrs(struct ifaddrs **ifap)
85 struct ifconf ifc;
86 char buff[8192];
87 int fd, i, n;
88 struct ifreq *ifr=NULL;
89 struct ifaddrs *curif;
90 struct ifaddrs *lastif = NULL;
92 *ifap = NULL;
94 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
95 return -1;
98 ifc.ifc_len = sizeof(buff);
99 ifc.ifc_buf = buff;
101 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
102 close(fd);
103 return -1;
106 ifr = ifc.ifc_req;
108 n = ifc.ifc_len / sizeof(struct ifreq);
110 /* Loop through interfaces, looking for given IP address */
111 for (i=n-1; i>=0; i--) {
112 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) == -1) {
113 freeifaddrs(*ifap);
114 close(fd);
115 return -1;
118 curif = calloc(1, sizeof(struct ifaddrs));
119 if (curif == NULL) {
120 freeifaddrs(*ifap);
121 close(fd);
122 return -1;
124 curif->ifa_name = strdup(ifr[i].ifr_name);
125 if (curif->ifa_name == NULL) {
126 free(curif);
127 freeifaddrs(*ifap);
128 close(fd);
129 return -1;
131 curif->ifa_flags = ifr[i].ifr_flags;
132 curif->ifa_dstaddr = NULL;
133 curif->ifa_data = NULL;
134 curif->ifa_next = NULL;
136 curif->ifa_addr = NULL;
137 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != -1) {
138 curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr);
139 if (curif->ifa_addr == NULL) {
140 free(curif->ifa_name);
141 free(curif);
142 freeifaddrs(*ifap);
143 close(fd);
144 return -1;
148 curif->ifa_netmask = NULL;
149 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != -1) {
150 curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr);
151 if (curif->ifa_netmask == NULL) {
152 if (curif->ifa_addr != NULL) {
153 free(curif->ifa_addr);
155 free(curif->ifa_name);
156 free(curif);
157 freeifaddrs(*ifap);
158 close(fd);
159 return -1;
163 if (lastif == NULL) {
164 *ifap = curif;
165 } else {
166 lastif->ifa_next = curif;
168 lastif = curif;
171 close(fd);
173 return 0;
176 #define _FOUND_IFACE_ANY
177 #endif /* HAVE_IFACE_IFCONF */
178 #ifdef HAVE_IFACE_IFREQ
180 #ifndef I_STR
181 #include <sys/stropts.h>
182 #endif
184 /****************************************************************************
185 this should cover most of the streams based systems
186 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
187 ****************************************************************************/
188 int rep_getifaddrs(struct ifaddrs **ifap)
190 struct ifreq ifreq;
191 struct strioctl strioctl;
192 char buff[8192];
193 int fd, i, n;
194 struct ifreq *ifr=NULL;
195 struct ifaddrs *curif;
196 struct ifaddrs *lastif = NULL;
198 *ifap = NULL;
200 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
201 return -1;
204 strioctl.ic_cmd = SIOCGIFCONF;
205 strioctl.ic_dp = buff;
206 strioctl.ic_len = sizeof(buff);
207 if (ioctl(fd, I_STR, &strioctl) < 0) {
208 close(fd);
209 return -1;
212 /* we can ignore the possible sizeof(int) here as the resulting
213 number of interface structures won't change */
214 n = strioctl.ic_len / sizeof(struct ifreq);
216 /* we will assume that the kernel returns the length as an int
217 at the start of the buffer if the offered size is a
218 multiple of the structure size plus an int */
219 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
220 ifr = (struct ifreq *)(buff + sizeof(int));
221 } else {
222 ifr = (struct ifreq *)buff;
225 /* Loop through interfaces */
227 for (i = 0; i<n; i++) {
228 ifreq = ifr[i];
230 curif = calloc(1, sizeof(struct ifaddrs));
231 if (lastif == NULL) {
232 *ifap = curif;
233 } else {
234 lastif->ifa_next = curif;
237 strioctl.ic_cmd = SIOCGIFFLAGS;
238 strioctl.ic_dp = (char *)&ifreq;
239 strioctl.ic_len = sizeof(struct ifreq);
240 if (ioctl(fd, I_STR, &strioctl) != 0) {
241 freeifaddrs(*ifap);
242 return -1;
245 curif->ifa_flags = ifreq.ifr_flags;
247 strioctl.ic_cmd = SIOCGIFADDR;
248 strioctl.ic_dp = (char *)&ifreq;
249 strioctl.ic_len = sizeof(struct ifreq);
250 if (ioctl(fd, I_STR, &strioctl) != 0) {
251 freeifaddrs(*ifap);
252 return -1;
255 curif->ifa_name = strdup(ifreq.ifr_name);
256 curif->ifa_addr = sockaddr_dup(&ifreq.ifr_addr);
257 curif->ifa_dstaddr = NULL;
258 curif->ifa_data = NULL;
259 curif->ifa_next = NULL;
260 curif->ifa_netmask = NULL;
262 strioctl.ic_cmd = SIOCGIFNETMASK;
263 strioctl.ic_dp = (char *)&ifreq;
264 strioctl.ic_len = sizeof(struct ifreq);
265 if (ioctl(fd, I_STR, &strioctl) != 0) {
266 freeifaddrs(*ifap);
267 return -1;
270 curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr);
272 lastif = curif;
275 close(fd);
277 return 0;
280 #define _FOUND_IFACE_ANY
281 #endif /* HAVE_IFACE_IFREQ */
282 #ifdef HAVE_IFACE_AIX
284 /****************************************************************************
285 this one is for AIX (tested on 4.2)
286 ****************************************************************************/
287 int rep_getifaddrs(struct ifaddrs **ifap)
289 char buff[8192];
290 int fd, i;
291 struct ifconf ifc;
292 struct ifreq *ifr=NULL;
293 struct ifaddrs *curif;
294 struct ifaddrs *lastif = NULL;
296 *ifap = NULL;
298 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
299 return -1;
302 ifc.ifc_len = sizeof(buff);
303 ifc.ifc_buf = buff;
305 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
306 close(fd);
307 return -1;
310 ifr = ifc.ifc_req;
312 /* Loop through interfaces */
313 i = ifc.ifc_len;
315 while (i > 0) {
316 unsigned int inc;
318 inc = ifr->ifr_addr.sa_len;
320 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
321 freeaddrinfo(*ifap);
322 return -1;
325 curif = calloc(1, sizeof(struct ifaddrs));
326 if (lastif == NULL) {
327 *ifap = curif;
328 } else {
329 lastif->ifa_next = curif;
332 curif->ifa_name = strdup(ifr->ifr_name);
333 curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr);
334 curif->ifa_dstaddr = NULL;
335 curif->ifa_data = NULL;
336 curif->ifa_netmask = NULL;
337 curif->ifa_next = NULL;
339 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
340 freeaddrinfo(*ifap);
341 return -1;
344 curif->ifa_flags = ifr->ifr_flags;
346 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
347 freeaddrinfo(*ifap);
348 return -1;
351 curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr);
353 lastif = curif;
355 next:
357 * Patch from Archie Cobbs (archie@whistle.com). The
358 * addresses in the SIOCGIFCONF interface list have a
359 * minimum size. Usually this doesn't matter, but if
360 * your machine has tunnel interfaces, etc. that have
361 * a zero length "link address", this does matter. */
363 if (inc < sizeof(ifr->ifr_addr))
364 inc = sizeof(ifr->ifr_addr);
365 inc += IFNAMSIZ;
367 ifr = (struct ifreq*) (((char*) ifr) + inc);
368 i -= inc;
371 close(fd);
372 return 0;
375 #define _FOUND_IFACE_ANY
376 #endif /* HAVE_IFACE_AIX */
377 #ifndef _FOUND_IFACE_ANY
378 int rep_getifaddrs(struct ifaddrs **ifap)
380 errno = ENOSYS;
381 return -1;
383 #endif