source: vendor/3.5.0/lib/replace/getifaddrs.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 7.6 KB
Line 
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
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#define SOCKET_WRAPPER_NOT_REPLACE
23
24#include "replace.h"
25#include "system/network.h"
26
27#include <unistd.h>
28#include <stdio.h>
29#include <sys/types.h>
30
31#ifdef HAVE_SYS_TIME_H
32#include <sys/time.h>
33#endif
34
35#ifndef SIOCGIFCONF
36#ifdef HAVE_SYS_SOCKIO_H
37#include <sys/sockio.h>
38#endif
39#endif
40
41#ifdef HAVE_IFACE_GETIFADDRS
42#define _FOUND_IFACE_ANY
43#else
44
45void rep_freeifaddrs(struct ifaddrs *ifp)
46{
47 if (ifp != NULL) {
48 free(ifp->ifa_name);
49 free(ifp->ifa_addr);
50 free(ifp->ifa_netmask);
51 free(ifp->ifa_dstaddr);
52 freeifaddrs(ifp->ifa_next);
53 free(ifp);
54 }
55}
56
57static struct sockaddr *sockaddr_dup(struct sockaddr *sa)
58{
59 struct sockaddr *ret;
60 socklen_t socklen;
61#ifdef HAVE_SOCKADDR_SA_LEN
62 socklen = sa->sa_len;
63#else
64 socklen = sizeof(struct sockaddr_storage);
65#endif
66 ret = calloc(1, socklen);
67 if (ret == NULL)
68 return NULL;
69 memcpy(ret, sa, socklen);
70 return ret;
71}
72#endif
73
74#if HAVE_IFACE_IFCONF
75
76/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
77 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
78
79 It probably also works on any BSD style system. */
80
81int rep_getifaddrs(struct ifaddrs **ifap)
82{
83 struct ifconf ifc;
84 char buff[8192];
85 int fd, i, n;
86 struct ifreq *ifr=NULL;
87 struct ifaddrs *curif;
88 struct ifaddrs *lastif = NULL;
89
90 *ifap = NULL;
91
92 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
93 return -1;
94 }
95
96 ifc.ifc_len = sizeof(buff);
97 ifc.ifc_buf = buff;
98
99 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
100 close(fd);
101 return -1;
102 }
103
104 ifr = ifc.ifc_req;
105
106 n = ifc.ifc_len / sizeof(struct ifreq);
107
108 /* Loop through interfaces, looking for given IP address */
109 for (i=n-1; i>=0; i--) {
110 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) == -1) {
111 freeifaddrs(*ifap);
112 return -1;
113 }
114
115 curif = calloc(1, sizeof(struct ifaddrs));
116 curif->ifa_name = strdup(ifr[i].ifr_name);
117 curif->ifa_flags = ifr[i].ifr_flags;
118 curif->ifa_dstaddr = NULL;
119 curif->ifa_data = NULL;
120 curif->ifa_next = NULL;
121
122 curif->ifa_addr = NULL;
123 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != -1) {
124 curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr);
125 }
126
127 curif->ifa_netmask = NULL;
128 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != -1) {
129 curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr);
130 }
131
132 if (lastif == NULL) {
133 *ifap = curif;
134 } else {
135 lastif->ifa_next = curif;
136 }
137 lastif = curif;
138 }
139
140 close(fd);
141
142 return 0;
143}
144
145#define _FOUND_IFACE_ANY
146#endif /* HAVE_IFACE_IFCONF */
147#ifdef HAVE_IFACE_IFREQ
148
149#ifndef I_STR
150#include <sys/stropts.h>
151#endif
152
153/****************************************************************************
154this should cover most of the streams based systems
155Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
156****************************************************************************/
157int rep_getifaddrs(struct ifaddrs **ifap)
158{
159 struct ifreq ifreq;
160 struct strioctl strioctl;
161 char buff[8192];
162 int fd, i, n;
163 struct ifreq *ifr=NULL;
164 struct ifaddrs *curif;
165 struct ifaddrs *lastif = NULL;
166
167 *ifap = NULL;
168
169 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
170 return -1;
171 }
172
173 strioctl.ic_cmd = SIOCGIFCONF;
174 strioctl.ic_dp = buff;
175 strioctl.ic_len = sizeof(buff);
176 if (ioctl(fd, I_STR, &strioctl) < 0) {
177 close(fd);
178 return -1;
179 }
180
181 /* we can ignore the possible sizeof(int) here as the resulting
182 number of interface structures won't change */
183 n = strioctl.ic_len / sizeof(struct ifreq);
184
185 /* we will assume that the kernel returns the length as an int
186 at the start of the buffer if the offered size is a
187 multiple of the structure size plus an int */
188 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
189 ifr = (struct ifreq *)(buff + sizeof(int));
190 } else {
191 ifr = (struct ifreq *)buff;
192 }
193
194 /* Loop through interfaces */
195
196 for (i = 0; i<n; i++) {
197 ifreq = ifr[i];
198
199 curif = calloc(1, sizeof(struct ifaddrs));
200 if (lastif == NULL) {
201 *ifap = curif;
202 } else {
203 lastif->ifa_next = curif;
204 }
205
206 strioctl.ic_cmd = SIOCGIFFLAGS;
207 strioctl.ic_dp = (char *)&ifreq;
208 strioctl.ic_len = sizeof(struct ifreq);
209 if (ioctl(fd, I_STR, &strioctl) != 0) {
210 freeifaddrs(*ifap);
211 return -1;
212 }
213
214 curif->ifa_flags = ifreq.ifr_flags;
215
216 strioctl.ic_cmd = SIOCGIFADDR;
217 strioctl.ic_dp = (char *)&ifreq;
218 strioctl.ic_len = sizeof(struct ifreq);
219 if (ioctl(fd, I_STR, &strioctl) != 0) {
220 freeifaddrs(*ifap);
221 return -1;
222 }
223
224 curif->ifa_name = strdup(ifreq.ifr_name);
225 curif->ifa_addr = sockaddr_dup(&ifreq.ifr_addr);
226 curif->ifa_dstaddr = NULL;
227 curif->ifa_data = NULL;
228 curif->ifa_next = NULL;
229 curif->ifa_netmask = NULL;
230
231 strioctl.ic_cmd = SIOCGIFNETMASK;
232 strioctl.ic_dp = (char *)&ifreq;
233 strioctl.ic_len = sizeof(struct ifreq);
234 if (ioctl(fd, I_STR, &strioctl) != 0) {
235 freeifaddrs(*ifap);
236 return -1;
237 }
238
239 curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr);
240
241 lastif = curif;
242 }
243
244 close(fd);
245
246 return 0;
247}
248
249#define _FOUND_IFACE_ANY
250#endif /* HAVE_IFACE_IFREQ */
251#ifdef HAVE_IFACE_AIX
252
253/****************************************************************************
254this one is for AIX (tested on 4.2)
255****************************************************************************/
256int rep_getifaddrs(struct ifaddrs **ifap)
257{
258 char buff[8192];
259 int fd, i;
260 struct ifconf ifc;
261 struct ifreq *ifr=NULL;
262 struct ifaddrs *curif;
263 struct ifaddrs *lastif = NULL;
264
265 *ifap = NULL;
266
267 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
268 return -1;
269 }
270
271 ifc.ifc_len = sizeof(buff);
272 ifc.ifc_buf = buff;
273
274 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
275 close(fd);
276 return -1;
277 }
278
279 ifr = ifc.ifc_req;
280
281 /* Loop through interfaces */
282 i = ifc.ifc_len;
283
284 while (i > 0) {
285 uint_t inc;
286
287 inc = ifr->ifr_addr.sa_len;
288
289 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
290 freeaddrinfo(*ifap);
291 return -1;
292 }
293
294 curif = calloc(1, sizeof(struct ifaddrs));
295 if (lastif == NULL) {
296 *ifap = curif;
297 } else {
298 lastif->ifa_next = curif;
299 }
300
301 curif->ifa_name = strdup(ifr->ifr_name);
302 curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr);
303 curif->ifa_dstaddr = NULL;
304 curif->ifa_data = NULL;
305 curif->ifa_netmask = NULL;
306 curif->ifa_next = NULL;
307
308 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
309 freeaddrinfo(*ifap);
310 return -1;
311 }
312
313 curif->ifa_flags = ifr->ifr_flags;
314
315 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
316 freeaddrinfo(*ifap);
317 return -1;
318 }
319
320 curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr);
321
322 lastif = curif;
323
324 next:
325 /*
326 * Patch from Archie Cobbs (archie@whistle.com). The
327 * addresses in the SIOCGIFCONF interface list have a
328 * minimum size. Usually this doesn't matter, but if
329 * your machine has tunnel interfaces, etc. that have
330 * a zero length "link address", this does matter. */
331
332 if (inc < sizeof(ifr->ifr_addr))
333 inc = sizeof(ifr->ifr_addr);
334 inc += IFNAMSIZ;
335
336 ifr = (struct ifreq*) (((char*) ifr) + inc);
337 i -= inc;
338 }
339
340 close(fd);
341 return 0;
342}
343
344#define _FOUND_IFACE_ANY
345#endif /* HAVE_IFACE_AIX */
346#ifndef _FOUND_IFACE_ANY
347int rep_getifaddrs(struct ifaddrs **ifap)
348{
349 errno = ENOSYS;
350 return -1;
351}
352#endif
Note: See TracBrowser for help on using the repository browser.