GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/net/getifaddrs.c Lines: 0 147 0.0 %
Date: 2017-11-13 Branches: 0 92 0.0 %

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
	int mib[6];
54
	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
	mib[0] = CTL_NET;
72
	mib[1] = PF_ROUTE;
73
	mib[2] = 0;             /* protocol */
74
	mib[3] = 0;             /* wildcard address family */
75
	mib[4] = NET_RT_IFLIST;
76
	mib[5] = 0;             /* no flags */
77
	while (1) {
78
		if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) {
79
			free(buf);
80
			return (-1);
81
		}
82
		if (needed == 0)
83
			break;
84
		if ((bufp = realloc(buf, needed)) == NULL) {
85
			free(buf);
86
			return (-1);
87
		}
88
		buf = bufp;
89
		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
	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
99
		rtm = (struct rt_msghdr *)next;
100
		if (rtm->rtm_version != RTM_VERSION)
101
			continue;
102
		switch (rtm->rtm_type) {
103
		case RTM_IFINFO:
104
			ifm = (struct if_msghdr *)rtm;
105
			if (ifm->ifm_addrs & RTA_IFP) {
106
				index = ifm->ifm_index;
107
				++icnt;
108
				dl = (struct sockaddr_dl *)(next +
109
				    rtm->rtm_hdrlen);
110
				dcnt += SA_RLEN((struct sockaddr *)dl) +
111
					ALIGNBYTES;
112
				dcnt += sizeof(ifm->ifm_data);
113
				ncnt += dl->sdl_nlen + 1;
114
			} else
115
				index = 0;
116
			break;
117
118
		case RTM_NEWADDR:
119
			ifam = (struct ifa_msghdr *)rtm;
120
			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
			if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
125
				break;
126
			p = next + rtm->rtm_hdrlen;
127
			++icnt;
128
			/* Scan to look for length of address */
129
			alen = 0;
130
			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
131
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
132
				    == 0)
133
					continue;
134
				sa = (struct sockaddr *)p;
135
				len = SA_RLEN(sa);
136
				if (i == RTAX_IFA) {
137
					alen = len;
138
					break;
139
				}
140
				p += len;
141
			}
142
			for (p = p0, i = 0; i < RTAX_MAX; i++) {
143
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
144
				    == 0)
145
					continue;
146
				sa = (struct sockaddr *)p;
147
				len = SA_RLEN(sa);
148
				if (i == RTAX_NETMASK && sa->sa_len == 0)
149
					dcnt += alen;
150
				else
151
					dcnt += len;
152
				p += len;
153
			}
154
			break;
155
		}
156
	}
157
158
	if (icnt + dcnt + ncnt == 1) {
159
		*pif = NULL;
160
		free(buf);
161
		return (0);
162
	}
163
	data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
164
	if (data == NULL) {
165
		free(buf);
166
		return(-1);
167
	}
168
169
	ifa = (struct ifaddrs *)data;
170
	data += sizeof(struct ifaddrs) * icnt;
171
	names = data + dcnt;
172
173
	memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
174
	ift = ifa;
175
176
	index = 0;
177
	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
178
		rtm = (struct rt_msghdr *)next;
179
		if (rtm->rtm_version != RTM_VERSION)
180
			continue;
181
		switch (rtm->rtm_type) {
182
		case RTM_IFINFO:
183
			ifm = (struct if_msghdr *)rtm;
184
			if (ifm->ifm_addrs & RTA_IFP) {
185
				index = ifm->ifm_index;
186
				dl = (struct sockaddr_dl *)(next +
187
				    rtm->rtm_hdrlen);
188
189
				cif = ift;
190
				ift->ifa_name = names;
191
				ift->ifa_flags = (int)ifm->ifm_flags;
192
				memcpy(names, dl->sdl_data, dl->sdl_nlen);
193
				names[dl->sdl_nlen] = 0;
194
				names += dl->sdl_nlen + 1;
195
196
				ift->ifa_addr = (struct sockaddr *)data;
197
				memcpy(data, dl,
198
				    ((struct sockaddr *)dl)->sa_len);
199
				data += SA_RLEN((struct sockaddr *)dl);
200
201
				/* ifm_data needs to be aligned */
202
				ift->ifa_data = data = (void *)ALIGN(data);
203
				dlen = rtm->rtm_hdrlen -
204
				    offsetof(struct if_msghdr, ifm_data);
205
				if (dlen > sizeof(ifm->ifm_data))
206
					dlen = sizeof(ifm->ifm_data);
207
				memcpy(data, &ifm->ifm_data, dlen);
208
 				data += sizeof(ifm->ifm_data);
209
210
				ift = (ift->ifa_next = ift + 1);
211
			} else
212
				index = 0;
213
			break;
214
215
		case RTM_NEWADDR:
216
			ifam = (struct ifa_msghdr *)rtm;
217
			if (index && ifam->ifam_index != index)
218
				abort();	/* XXX abort illegal in library */
219
220
			if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
221
				break;
222
			ift->ifa_name = cif->ifa_name;
223
			ift->ifa_flags = cif->ifa_flags;
224
			ift->ifa_data = NULL;
225
			p = next + rtm->rtm_hdrlen;
226
			/* Scan to look for length of address */
227
			alen = 0;
228
			for (p0 = p, i = 0; i < RTAX_MAX; i++) {
229
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
230
				    == 0)
231
					continue;
232
				sa = (struct sockaddr *)p;
233
				len = SA_RLEN(sa);
234
				if (i == RTAX_IFA) {
235
					alen = len;
236
					break;
237
				}
238
				p += len;
239
			}
240
			for (p = p0, i = 0; i < RTAX_MAX; i++) {
241
				if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
242
				    == 0)
243
					continue;
244
				sa = (struct sockaddr *)p;
245
				len = SA_RLEN(sa);
246
				switch (i) {
247
				case RTAX_IFA:
248
					ift->ifa_addr = (struct sockaddr *)data;
249
					memcpy(data, p, len);
250
					data += len;
251
					break;
252
253
				case RTAX_NETMASK:
254
					ift->ifa_netmask =
255
					    (struct sockaddr *)data;
256
					if (sa->sa_len == 0) {
257
						memset(data, 0, alen);
258
						data += alen;
259
						break;
260
					}
261
					memcpy(data, p, len);
262
					data += len;
263
					break;
264
265
				case RTAX_BRD:
266
					ift->ifa_broadaddr =
267
					    (struct sockaddr *)data;
268
					memcpy(data, p, len);
269
					data += len;
270
					break;
271
				}
272
				p += len;
273
			}
274
275
276
			ift = (ift->ifa_next = ift + 1);
277
			break;
278
		}
279
	}
280
281
	free(buf);
282
	if (--ift >= ifa) {
283
		ift->ifa_next = NULL;
284
		*pif = ifa;
285
	} else {
286
		*pif = NULL;
287
		free(ifa);
288
	}
289
	return (0);
290
}
291
DEF_WEAK(getifaddrs);
292
293
void
294
freeifaddrs(struct ifaddrs *ifp)
295
{
296
	free(ifp);
297
}
298
DEF_WEAK(freeifaddrs);