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	size_t len;
64	size_t needed;
65	int mib[6];
66	int i;
67	char *buf;
68	char *data;
69	char *next;
70	char *p;
71	struct ifma_msghdr *ifmam;
72	struct ifmaddrs *ifa, *ift;
73	struct rt_msghdr *rtm;
74	struct sockaddr *sa;
75
76	mib[0] = CTL_NET;
77	mib[1] = PF_ROUTE;
78	mib[2] = 0;             /* protocol */
79	mib[3] = 0;             /* wildcard address family */
80	mib[4] = NET_RT_IFMALIST;
81	mib[5] = 0;             /* no flags */
82	do {
83		if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
84			return (-1);
85		if ((buf = malloc(needed)) == NULL)
86			return (-1);
87		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
88			if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
89				free(buf);
90				return (-1);
91			}
92			free(buf);
93			buf = NULL;
94		}
95	} while (buf == NULL);
96
97	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
98		rtm = (struct rt_msghdr *)(void *)next;
99		if (rtm->rtm_version != RTM_VERSION)
100			continue;
101		switch (rtm->rtm_type) {
102		case RTM_NEWMADDR:
103			ifmam = (struct ifma_msghdr *)(void *)rtm;
104			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
105				break;
106			icnt++;
107			p = (char *)(ifmam + 1);
108			for (i = 0; i < RTAX_MAX; i++) {
109				if ((RTA_MASKS & ifmam->ifmam_addrs &
110				    (1 << i)) == 0)
111					continue;
112				sa = (struct sockaddr *)(void *)p;
113				len = SA_RLEN(sa);
114				dcnt += len;
115				p += len;
116			}
117			break;
118		}
119	}
120
121	data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt);
122	if (data == NULL) {
123		free(buf);
124		return (-1);
125	}
126
127	ifa = (struct ifmaddrs *)(void *)data;
128	data += sizeof(struct ifmaddrs) * icnt;
129
130	memset(ifa, 0, sizeof(struct ifmaddrs) * icnt);
131	ift = ifa;
132
133	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
134		rtm = (struct rt_msghdr *)(void *)next;
135		if (rtm->rtm_version != RTM_VERSION)
136			continue;
137
138		switch (rtm->rtm_type) {
139		case RTM_NEWMADDR:
140			ifmam = (struct ifma_msghdr *)(void *)rtm;
141			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
142				break;
143
144			p = (char *)(ifmam + 1);
145			for (i = 0; i < RTAX_MAX; i++) {
146				if ((RTA_MASKS & ifmam->ifmam_addrs &
147				    (1 << i)) == 0)
148					continue;
149				sa = (struct sockaddr *)(void *)p;
150				len = SA_RLEN(sa);
151				switch (i) {
152				case RTAX_GATEWAY:
153					ift->ifma_lladdr =
154					    (struct sockaddr *)(void *)data;
155					memcpy(data, p, len);
156					data += len;
157					break;
158
159				case RTAX_IFP:
160					ift->ifma_name =
161					    (struct sockaddr *)(void *)data;
162					memcpy(data, p, len);
163					data += len;
164					break;
165
166				case RTAX_IFA:
167					ift->ifma_addr =
168					    (struct sockaddr *)(void *)data;
169					memcpy(data, p, len);
170					data += len;
171					break;
172
173				default:
174					data += len;
175					break;
176				}
177				p += len;
178			}
179			ift->ifma_next = ift + 1;
180			ift = ift->ifma_next;
181			break;
182		}
183	}
184
185	free(buf);
186
187	if (ift > ifa) {
188		ift--;
189		ift->ifma_next = NULL;
190		*pif = ifa;
191	} else {
192		*pif = NULL;
193		free(ifa);
194	}
195	return (0);
196}
197
198void
199freeifmaddrs(struct ifmaddrs *ifmp)
200{
201
202	free(ifmp);
203}
204