GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/net/getifaddrs.c Lines: 132 152 86.8 %
Date: 2017-11-07 Branches: 63 92 68.5 %

Line Branch Exec Source
1
/*	$OpenBSD: getifaddrs.c,v 1.13 2015/09/14 11:01:47 guenther Exp $	*/
2
3
/*
4
 * Copyright (c) 1995, 1999
5
 *	Berkeley Software Design, Inc.  All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
14
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
 * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
17
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
 * SUCH DAMAGE.
24
 *
25
 *	BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
26
 */
27
28
#include <sys/param.h>	/* ALIGN */
29
#include <sys/types.h>
30
#include <sys/ioctl.h>
31
#include <sys/socket.h>
32
#include <net/if.h>
33
#include <net/route.h>
34
#include <sys/sysctl.h>
35
#include <net/if_dl.h>
36
37
#include <errno.h>
38
#include <ifaddrs.h>
39
#include <stddef.h>
40
#include <stdlib.h>
41
#include <string.h>
42
#include <unistd.h>
43
44
#define	SALIGN	(sizeof(long) - 1)
45
#define	SA_RLEN(sa)	((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
46
47
int
48
getifaddrs(struct ifaddrs **pif)
49
{
50
	int icnt = 1;
51
	int dcnt = 0;
52
	int ncnt = 0;
53
266
	int mib[6];
54
133
	size_t needed;
55
	char *buf = NULL, *bufp;
56
	char *next;
57
	struct ifaddrs *cif = 0;
58
	char *p, *p0;
59
	struct rt_msghdr *rtm;
60
	struct if_msghdr *ifm;
61
	struct ifa_msghdr *ifam;
62
	struct sockaddr_dl *dl;
63
	struct sockaddr *sa;
64
	u_short index = 0;
65
	size_t len, alen, dlen;
66
	struct ifaddrs *ifa, *ift;
67
	int i;
68
	char *data;
69
	char *names;
70
71
133
	mib[0] = CTL_NET;
72
133
	mib[1] = PF_ROUTE;
73
133
	mib[2] = 0;             /* protocol */
74
133
	mib[3] = 0;             /* wildcard address family */
75
133
	mib[4] = NET_RT_IFLIST;
76
133
	mib[5] = 0;             /* no flags */
77
133
	while (1) {
78
133
		if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) {
79
			free(buf);
80
			return (-1);
81
		}
82
133
		if (needed == 0)
83
			break;
84
133
		if ((bufp = realloc(buf, needed)) == NULL) {
85
			free(buf);
86
			return (-1);
87
		}
88
		buf = bufp;
89
133
		if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) {
90
			if (errno == ENOMEM)
91
				continue;
92
			free(buf);
93
			return (-1);
94
		}
95
		break;
96
	}
97
98
4326
	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
99
2030
		rtm = (struct rt_msghdr *)next;
100
2030
		if (rtm->rtm_version != RTM_VERSION)
101
			continue;
102
4060
		switch (rtm->rtm_type) {
103
		case RTM_IFINFO:
104
1107
			ifm = (struct if_msghdr *)rtm;
105
1107
			if (ifm->ifm_addrs & RTA_IFP) {
106
1107
				index = ifm->ifm_index;
107
1107
				++icnt;
108
1107
				dl = (struct sockaddr_dl *)(next +
109
1107
				    rtm->rtm_hdrlen);
110
3321
				dcnt += SA_RLEN((struct sockaddr *)dl) +
111
					ALIGNBYTES;
112
1107
				dcnt += sizeof(ifm->ifm_data);
113
1107
				ncnt += dl->sdl_nlen + 1;
114
1107
			} else
115
				index = 0;
116
			break;
117
118
		case RTM_NEWADDR:
119
923
			ifam = (struct ifa_msghdr *)rtm;
120

1846
			if (index && ifam->ifam_index != index)
121
				abort();	/* XXX abort illegal in library */
122
123
#define	RTA_MASKS	(RTA_NETMASK | RTA_IFA | RTA_BRD)
124

1846
			if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
125
				break;
126
923
			p = next + rtm->rtm_hdrlen;
127
923
			++icnt;
128
			/* Scan to look for length of address */
129
			alen = 0;
130
11076
			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
131
11076
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
132
5538
				    == 0)
133
					continue;
134
1846
				sa = (struct sockaddr *)p;
135
5538
				len = SA_RLEN(sa);
136
1846
				if (i == RTAX_IFA) {
137
					alen = len;
138
923
					break;
139
				}
140
923
				p += len;
141
923
			}
142
29536
			for (p = p0, i = 0; i < RTAX_MAX; i++) {
143
27690
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
144
13845
				    == 0)
145
					continue;
146
2671
				sa = (struct sockaddr *)p;
147
7590
				len = SA_RLEN(sa);
148

3594
				if (i == RTAX_NETMASK && sa->sa_len == 0)
149
					dcnt += alen;
150
				else
151
2671
					dcnt += len;
152
2671
				p += len;
153
2671
			}
154
			break;
155
		}
156
	}
157
158
133
	if (icnt + dcnt + ncnt == 1) {
159
		*pif = NULL;
160
		free(buf);
161
		return (0);
162
	}
163
133
	data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
164
133
	if (data == NULL) {
165
		free(buf);
166
		return(-1);
167
	}
168
169
133
	ifa = (struct ifaddrs *)data;
170
133
	data += sizeof(struct ifaddrs) * icnt;
171
133
	names = data + dcnt;
172
173
133
	memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
174
	ift = ifa;
175
176
	index = 0;
177
4326
	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
178
2030
		rtm = (struct rt_msghdr *)next;
179
2030
		if (rtm->rtm_version != RTM_VERSION)
180
			continue;
181
3137
		switch (rtm->rtm_type) {
182
		case RTM_IFINFO:
183
1107
			ifm = (struct if_msghdr *)rtm;
184
1107
			if (ifm->ifm_addrs & RTA_IFP) {
185
1107
				index = ifm->ifm_index;
186
1107
				dl = (struct sockaddr_dl *)(next +
187
1107
				    rtm->rtm_hdrlen);
188
189
				cif = ift;
190
1107
				ift->ifa_name = names;
191
1107
				ift->ifa_flags = (int)ifm->ifm_flags;
192
1107
				memcpy(names, dl->sdl_data, dl->sdl_nlen);
193
1107
				names[dl->sdl_nlen] = 0;
194
1107
				names += dl->sdl_nlen + 1;
195
196
1107
				ift->ifa_addr = (struct sockaddr *)data;
197
1107
				memcpy(data, dl,
198
1107
				    ((struct sockaddr *)dl)->sa_len);
199
3321
				data += SA_RLEN((struct sockaddr *)dl);
200
201
				/* ifm_data needs to be aligned */
202
1107
				ift->ifa_data = data = (void *)ALIGN(data);
203
1107
				dlen = rtm->rtm_hdrlen -
204
				    offsetof(struct if_msghdr, ifm_data);
205
1107
				if (dlen > sizeof(ifm->ifm_data))
206
					dlen = sizeof(ifm->ifm_data);
207
1107
				memcpy(data, &ifm->ifm_data, dlen);
208
1107
 				data += sizeof(ifm->ifm_data);
209
210
1107
				ift = (ift->ifa_next = ift + 1);
211
1107
			} else
212
				index = 0;
213
			break;
214
215
		case RTM_NEWADDR:
216
923
			ifam = (struct ifa_msghdr *)rtm;
217

1846
			if (index && ifam->ifam_index != index)
218
				abort();	/* XXX abort illegal in library */
219
220

1846
			if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
221
				break;
222
923
			ift->ifa_name = cif->ifa_name;
223
923
			ift->ifa_flags = cif->ifa_flags;
224
923
			ift->ifa_data = NULL;
225
923
			p = next + rtm->rtm_hdrlen;
226
			/* Scan to look for length of address */
227
			alen = 0;
228
11076
			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
229
11076
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
230
5538
				    == 0)
231
					continue;
232
1846
				sa = (struct sockaddr *)p;
233
5538
				len = SA_RLEN(sa);
234
1846
				if (i == RTAX_IFA) {
235
					alen = len;
236
923
					break;
237
				}
238
923
				p += len;
239
923
			}
240
29536
			for (p = p0, i = 0; i < RTAX_MAX; i++) {
241
27690
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
242
13845
				    == 0)
243
					continue;
244
2671
				sa = (struct sockaddr *)p;
245
10261
				len = SA_RLEN(sa);
246

5342
				switch (i) {
247
				case RTAX_IFA:
248
923
					ift->ifa_addr = (struct sockaddr *)data;
249
923
					memcpy(data, p, len);
250
923
					data += len;
251
923
					break;
252
253
				case RTAX_NETMASK:
254
923
					ift->ifa_netmask =
255
923
					    (struct sockaddr *)data;
256
923
					if (sa->sa_len == 0) {
257
						memset(data, 0, alen);
258
						data += alen;
259
						break;
260
					}
261
923
					memcpy(data, p, len);
262
923
					data += len;
263
923
					break;
264
265
				case RTAX_BRD:
266
825
					ift->ifa_broadaddr =
267
825
					    (struct sockaddr *)data;
268
825
					memcpy(data, p, len);
269
825
					data += len;
270
825
					break;
271
				}
272
2671
				p += len;
273
2671
			}
274
275
276
923
			ift = (ift->ifa_next = ift + 1);
277
923
			break;
278
		}
279
	}
280
281
133
	free(buf);
282
133
	if (--ift >= ifa) {
283
133
		ift->ifa_next = NULL;
284
133
		*pif = ifa;
285
133
	} else {
286
		*pif = NULL;
287
		free(ifa);
288
	}
289
133
	return (0);
290
133
}
291
DEF_WEAK(getifaddrs);
292
293
void
294
freeifaddrs(struct ifaddrs *ifp)
295
{
296
266
	free(ifp);
297
133
}
298
DEF_WEAK(freeifaddrs);