getifmaddrs.c revision 47c129ab4445e4c2476772fd12576c58374dc7f0
1/*
2 * Copyright (c) 2003 Bruce M. Simpson.
3 * All rights reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *        This product includes software developed by Bruce M. Simpson.
16 * 4. Neither the name of Bruce M. Simpson nor the names of other
17 *    contributors may be used to endorse or promote products derived
18 *    from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY BRUCE M. SIMPSON AND AFFILIATES
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL BRUCE M. SIMPSON OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD$");
35
36#include "namespace.h"
37#include <sys/param.h>
38#include <sys/sysctl.h>
39#include <sys/ioctl.h>
40#include <sys/socket.h>
41#include <net/if.h>
42#include <net/if_dl.h>
43#include <net/route.h>
44
45#include <errno.h>
46#include <ifaddrs.h>
47#include <stdlib.h>
48#include <string.h>
49#include "un-namespace.h"
50
51#define	SALIGN	(sizeof(long) - 1)
52#define	SA_RLEN(sa)	((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
53			    (SALIGN + 1))
54#define	MAX_SYSCTL_TRY	5
55#define	RTA_MASKS	(RTA_GATEWAY | RTA_IFP | RTA_IFA)
56
57int
58getifmaddrs(struct ifmaddrs **pif)
59{
60	int icnt = 1;
61	int dcnt = 0;
62	int ntry = 0;
63	u_short idx = 0;
64	size_t len;
65	size_t needed;
66	int mib[6];
67	int i;
68	char *buf;
69	char *data;
70	char *names;
71	char *next;
72	char *p;
73	struct ifma_msghdr *ifmam;
74	struct ifmaddrs *ifa, *ift;
75	struct rt_msghdr *rtm;
76	struct sockaddr *sa;
77
78	mib[0] = CTL_NET;
79	mib[1] = PF_ROUTE;
80	mib[2] = 0;             /* protocol */
81	mib[3] = 0;             /* wildcard address family */
82	mib[4] = NET_RT_IFMALIST;
83	mib[5] = 0;             /* no flags */
84	do {
85		if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
86			return (-1);
87		if ((buf = malloc(needed)) == NULL)
88			return (-1);
89		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
90			if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
91				free(buf);
92				return (-1);
93			}
94			free(buf);
95			buf = NULL;
96		}
97	} while (buf == NULL);
98
99	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
100		rtm = (struct rt_msghdr *)(void *)next;
101		if (rtm->rtm_version != RTM_VERSION)
102			continue;
103		switch (rtm->rtm_type) {
104		case RTM_NEWMADDR:
105			ifmam = (struct ifma_msghdr *)(void *)rtm;
106			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
107				break;
108			icnt++;
109			p = (char *)(ifmam + 1);
110			for (i = 0; i < RTAX_MAX; i++) {
111				if ((RTA_MASKS & ifmam->ifmam_addrs &
112				    (1 << i)) == 0)
113					continue;
114				sa = (struct sockaddr *)(void *)p;
115				len = SA_RLEN(sa);
116				dcnt += len;
117				p += len;
118			}
119			break;
120		}
121	}
122
123	data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt);
124	if (data == NULL) {
125		free(buf);
126		return (-1);
127	}
128
129	ifa = (struct ifmaddrs *)(void *)data;
130	data += sizeof(struct ifmaddrs) * icnt;
131	names = data + dcnt;
132
133	memset(ifa, 0, sizeof(struct ifmaddrs) * icnt);
134	ift = ifa;
135
136	idx = 0;
137	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
138		rtm = (struct rt_msghdr *)(void *)next;
139		if (rtm->rtm_version != RTM_VERSION)
140			continue;
141
142		switch (rtm->rtm_type) {
143		case RTM_NEWMADDR:
144			ifmam = (struct ifma_msghdr *)(void *)rtm;
145			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
146				break;
147
148			p = (char *)(ifmam + 1);
149			for (i = 0; i < RTAX_MAX; i++) {
150				if ((RTA_MASKS & ifmam->ifmam_addrs &
151				    (1 << i)) == 0)
152					continue;
153				sa = (struct sockaddr *)(void *)p;
154				len = SA_RLEN(sa);
155				switch (i) {
156				case RTAX_GATEWAY:
157					ift->ifma_lladdr =
158					    (struct sockaddr *)(void *)data;
159					memcpy(data, p, len);
160					data += len;
161					break;
162
163				case RTAX_IFP:
164					ift->ifma_name =
165					    (struct sockaddr *)(void *)data;
166					memcpy(data, p, len);
167					data += len;
168					break;
169
170				case RTAX_IFA:
171					ift->ifma_addr =
172					    (struct sockaddr *)(void *)data;
173					memcpy(data, p, len);
174					data += len;
175					break;
176
177				default:
178					data += len;
179					break;
180				}
181				p += len;
182			}
183			ift->ifma_next = ift + 1;
184			ift = ift->ifma_next;
185			break;
186		}
187	}
188
189	free(buf);
190
191	if (ift > ifa) {
192		ift--;
193		ift->ifma_next = NULL;
194		*pif = ifa;
195	} else {
196		*pif = NULL;
197		free(ifa);
198	}
199	return (0);
200}
201
202void
203freeifmaddrs(struct ifmaddrs *ifmp)
204{
205
206	free(ifmp);
207}
208