xref: /freebsd/lib/libc/net/getifmaddrs.c (revision 2546665afcaf0d53dc2c7058fee96354b3680f5a)
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 
57 int
58 getifmaddrs(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 
202 void
203 freeifmaddrs(struct ifmaddrs *ifmp)
204 {
205 
206 	free(ifmp);
207 }
208