Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/net/getifaddrs.c
39476 views
1
/* $KAME: getifaddrs.c,v 1.9 2001/08/20 02:31:20 itojun Exp $ */
2
3
/*-
4
* SPDX-License-Identifier: BSD-1-Clause
5
*
6
* Copyright (c) 1995, 1999
7
* Berkeley Software Design, Inc. All rights reserved.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
14
*
15
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*
27
* BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
28
*/
29
/*
30
* NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform
31
* try-and-error for region size.
32
*/
33
34
#include "namespace.h"
35
#include <sys/types.h>
36
#include <sys/ioctl.h>
37
#include <sys/socket.h>
38
#include <net/if.h>
39
#ifdef NET_RT_IFLIST
40
#include <sys/param.h>
41
#include <net/route.h>
42
#include <sys/sysctl.h>
43
#include <net/if_dl.h>
44
#endif
45
46
#include <errno.h>
47
#include <ifaddrs.h>
48
#include <stdlib.h>
49
#include <string.h>
50
#include "un-namespace.h"
51
52
#if !defined(AF_LINK)
53
#define SA_LEN(sa) sizeof(struct sockaddr)
54
#endif
55
56
#if !defined(SA_LEN)
57
#define SA_LEN(sa) (sa)->sa_len
58
#endif
59
60
#define SALIGN (sizeof(long) - 1)
61
#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
62
63
#ifndef ALIGNBYTES
64
/*
65
* On systems with a routing socket, ALIGNBYTES should match the value
66
* that the kernel uses when building the messages.
67
*/
68
#define ALIGNBYTES XXX
69
#endif
70
#ifndef ALIGN
71
#define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
72
#endif
73
74
#define MAX_SYSCTL_TRY 5
75
76
int
77
getifaddrs(struct ifaddrs **pif)
78
{
79
int icnt = 1;
80
int dcnt = 0;
81
int ncnt = 0;
82
int ntry = 0;
83
int mib[6];
84
size_t needed;
85
char *buf;
86
char *next;
87
struct ifaddrs *cif;
88
char *p, *p0;
89
struct rt_msghdr *rtm;
90
struct if_msghdrl *ifm;
91
struct ifa_msghdrl *ifam;
92
struct sockaddr_dl *dl;
93
struct sockaddr *sa;
94
struct ifaddrs *ifa, *ift;
95
struct if_data *if_data;
96
u_short idx = 0;
97
int i;
98
size_t len, alen;
99
char *data;
100
char *names;
101
102
mib[0] = CTL_NET;
103
mib[1] = PF_ROUTE;
104
mib[2] = 0; /* protocol */
105
mib[3] = 0; /* wildcard address family */
106
mib[4] = NET_RT_IFLISTL;/* extra fields for extensible msghdr structs */
107
mib[5] = 0; /* no flags */
108
do {
109
/*
110
* We'll try to get addresses several times in case that
111
* the number of addresses is unexpectedly increased during
112
* the two sysctl calls. This should rarely happen, but we'll
113
* try to do our best for applications that assume success of
114
* this library (which should usually be the case).
115
* Portability note: since FreeBSD does not add margin of
116
* memory at the first sysctl, the possibility of failure on
117
* the second sysctl call is a bit higher.
118
*/
119
120
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
121
return (-1);
122
if ((buf = malloc(needed)) == NULL)
123
return (-1);
124
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
125
if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
126
free(buf);
127
return (-1);
128
}
129
free(buf);
130
buf = NULL;
131
}
132
} while (buf == NULL);
133
134
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
135
rtm = (struct rt_msghdr *)(void *)next;
136
if (rtm->rtm_version != RTM_VERSION)
137
continue;
138
switch (rtm->rtm_type) {
139
case RTM_IFINFO:
140
ifm = (struct if_msghdrl *)(void *)rtm;
141
if (ifm->ifm_addrs & RTA_IFP) {
142
idx = ifm->ifm_index;
143
++icnt;
144
if_data = IF_MSGHDRL_IFM_DATA(ifm);
145
dcnt += if_data->ifi_datalen;
146
dl = (struct sockaddr_dl *)IF_MSGHDRL_RTA(ifm);
147
dcnt += SA_RLEN((struct sockaddr *)(void*)dl) +
148
ALIGNBYTES;
149
ncnt += dl->sdl_nlen + 1;
150
} else
151
idx = 0;
152
break;
153
154
case RTM_NEWADDR:
155
ifam = (struct ifa_msghdrl *)(void *)rtm;
156
if (idx && ifam->ifam_index != idx)
157
abort(); /* this cannot happen */
158
159
#define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
160
if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
161
break;
162
p = (char *)IFA_MSGHDRL_RTA(ifam);
163
++icnt;
164
if_data = IFA_MSGHDRL_IFAM_DATA(ifam);
165
dcnt += if_data->ifi_datalen + ALIGNBYTES;
166
167
/* Scan to look for length of address */
168
alen = 0;
169
for (p0 = p, i = 0; i < RTAX_MAX; i++) {
170
if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
171
== 0)
172
continue;
173
sa = (struct sockaddr *)(void *)p;
174
len = SA_RLEN(sa);
175
if (i == RTAX_IFA) {
176
alen = len;
177
break;
178
}
179
p += len;
180
}
181
for (p = p0, i = 0; i < RTAX_MAX; i++) {
182
if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
183
== 0)
184
continue;
185
sa = (struct sockaddr *)(void *)p;
186
len = SA_RLEN(sa);
187
if (i == RTAX_NETMASK && SA_LEN(sa) == 0)
188
dcnt += alen;
189
else
190
dcnt += len;
191
p += len;
192
}
193
break;
194
}
195
}
196
197
if (icnt + dcnt + ncnt == 1) {
198
*pif = NULL;
199
free(buf);
200
return (0);
201
}
202
data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
203
if (data == NULL) {
204
free(buf);
205
return(-1);
206
}
207
208
ifa = (struct ifaddrs *)(void *)data;
209
data += sizeof(struct ifaddrs) * icnt;
210
names = data + dcnt;
211
212
memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
213
ift = ifa;
214
215
idx = 0;
216
cif = NULL;
217
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
218
rtm = (struct rt_msghdr *)(void *)next;
219
if (rtm->rtm_version != RTM_VERSION)
220
continue;
221
switch (rtm->rtm_type) {
222
case RTM_IFINFO:
223
ifm = (struct if_msghdrl *)(void *)rtm;
224
if ((ifm->ifm_addrs & RTA_IFP) == 0) {
225
idx = 0;
226
break;
227
}
228
229
idx = ifm->ifm_index;
230
dl = (struct sockaddr_dl *)IF_MSGHDRL_RTA(ifm);
231
232
cif = ift;
233
ift->ifa_name = names;
234
ift->ifa_flags = (int)ifm->ifm_flags;
235
memcpy(names, dl->sdl_data, (size_t)dl->sdl_nlen);
236
names[dl->sdl_nlen] = 0;
237
names += dl->sdl_nlen + 1;
238
239
ift->ifa_addr = (struct sockaddr *)(void *)data;
240
memcpy(data, dl, (size_t)SA_LEN((struct sockaddr *)
241
(void *)dl));
242
data += SA_RLEN((struct sockaddr *)(void *)dl);
243
244
if_data = IF_MSGHDRL_IFM_DATA(ifm);
245
/* ifm_data needs to be aligned */
246
ift->ifa_data = data = (void *)ALIGN(data);
247
memcpy(data, if_data, if_data->ifi_datalen);
248
data += if_data->ifi_datalen;
249
250
ift = (ift->ifa_next = ift + 1);
251
break;
252
253
case RTM_NEWADDR:
254
ifam = (struct ifa_msghdrl *)(void *)rtm;
255
if (idx && ifam->ifam_index != idx)
256
abort(); /* this cannot happen */
257
258
if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
259
break;
260
ift->ifa_name = cif->ifa_name;
261
ift->ifa_flags = cif->ifa_flags;
262
ift->ifa_data = NULL;
263
264
p = (char *)IFA_MSGHDRL_RTA(ifam);
265
/* Scan to look for length of address */
266
alen = 0;
267
for (p0 = p, i = 0; i < RTAX_MAX; i++) {
268
if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
269
== 0)
270
continue;
271
sa = (struct sockaddr *)(void *)p;
272
len = SA_RLEN(sa);
273
if (i == RTAX_IFA) {
274
alen = len;
275
break;
276
}
277
p += len;
278
}
279
for (p = p0, i = 0; i < RTAX_MAX; i++) {
280
if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
281
== 0)
282
continue;
283
sa = (struct sockaddr *)(void *)p;
284
len = SA_RLEN(sa);
285
switch (i) {
286
case RTAX_IFA:
287
ift->ifa_addr =
288
(struct sockaddr *)(void *)data;
289
memcpy(data, p, len);
290
data += len;
291
break;
292
293
case RTAX_NETMASK:
294
ift->ifa_netmask =
295
(struct sockaddr *)(void *)data;
296
if (SA_LEN(sa) == 0) {
297
memset(data, 0, alen);
298
data += alen;
299
break;
300
}
301
memcpy(data, p, len);
302
data += len;
303
break;
304
305
case RTAX_BRD:
306
ift->ifa_broadaddr =
307
(struct sockaddr *)(void *)data;
308
memcpy(data, p, len);
309
data += len;
310
break;
311
}
312
p += len;
313
}
314
315
if_data = IFA_MSGHDRL_IFAM_DATA(ifam);
316
/* ifam_data needs to be aligned */
317
ift->ifa_data = data = (void *)ALIGN(data);
318
memcpy(data, if_data, if_data->ifi_datalen);
319
data += if_data->ifi_datalen;
320
321
ift = (ift->ifa_next = ift + 1);
322
break;
323
}
324
}
325
326
free(buf);
327
328
if (--ift >= ifa) {
329
ift->ifa_next = NULL;
330
*pif = ifa;
331
} else {
332
*pif = NULL;
333
free(ifa);
334
}
335
return (0);
336
}
337
338
void
339
freeifaddrs(struct ifaddrs *ifp)
340
{
341
342
free(ifp);
343
}
344
345