xref: /f-stack/tools/compat/getifmaddrs.c (revision 1eaf0ac3)
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  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 
29 #include <sys/param.h>
30 #include <sys/sysctl.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <net/if.h>
34 #include <net/if_dl.h>
35 #include <net/route.h>
36 
37 #include <errno.h>
38 #include <ifaddrs.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 #define	SALIGN	(sizeof(long) - 1)
43 #define	SA_RLEN(sa)	((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
44 			    (SALIGN + 1))
45 #define	MAX_SYSCTL_TRY	5
46 #define	RTA_MASKS	(RTA_GATEWAY | RTA_IFP | RTA_IFA)
47 
48 int
getifmaddrs(struct ifmaddrs ** pif)49 getifmaddrs(struct ifmaddrs **pif)
50 {
51 	int icnt = 1;
52 	int dcnt = 0;
53 	int ntry = 0;
54 	size_t len;
55 	size_t needed;
56 	int mib[6];
57 	int i;
58 	char *buf;
59 	char *data;
60 	char *next;
61 	char *p;
62 	struct ifma_msghdr *ifmam;
63 	struct ifmaddrs *ifa, *ift;
64 	struct rt_msghdr *rtm;
65 	struct sockaddr *sa;
66 
67 	mib[0] = CTL_NET;
68 	mib[1] = PF_ROUTE;
69 	mib[2] = 0;             /* protocol */
70 	mib[3] = 0;             /* wildcard address family */
71 	mib[4] = NET_RT_IFMALIST;
72 	mib[5] = 0;             /* no flags */
73 	do {
74 		if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
75 			return (-1);
76 		if ((buf = malloc(needed)) == NULL)
77 			return (-1);
78 		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
79 			if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
80 				free(buf);
81 				return (-1);
82 			}
83 			free(buf);
84 			buf = NULL;
85 		}
86 	} while (buf == NULL);
87 
88 	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
89 		rtm = (struct rt_msghdr *)(void *)next;
90 		if (rtm->rtm_version != RTM_VERSION)
91 			continue;
92 		switch (rtm->rtm_type) {
93 		case RTM_NEWMADDR:
94 			ifmam = (struct ifma_msghdr *)(void *)rtm;
95 			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
96 				break;
97 			icnt++;
98 			p = (char *)(ifmam + 1);
99 			for (i = 0; i < RTAX_MAX; i++) {
100 				if ((RTA_MASKS & ifmam->ifmam_addrs &
101 				    (1 << i)) == 0)
102 					continue;
103 				sa = (struct sockaddr *)(void *)p;
104 				len = SA_RLEN(sa);
105 				dcnt += len;
106 				p += len;
107 			}
108 			break;
109 		}
110 	}
111 
112 	data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt);
113 	if (data == NULL) {
114 		free(buf);
115 		return (-1);
116 	}
117 
118 	ifa = (struct ifmaddrs *)(void *)data;
119 	data += sizeof(struct ifmaddrs) * icnt;
120 
121 	memset(ifa, 0, sizeof(struct ifmaddrs) * icnt);
122 	ift = ifa;
123 
124 	for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
125 		rtm = (struct rt_msghdr *)(void *)next;
126 		if (rtm->rtm_version != RTM_VERSION)
127 			continue;
128 
129 		switch (rtm->rtm_type) {
130 		case RTM_NEWMADDR:
131 			ifmam = (struct ifma_msghdr *)(void *)rtm;
132 			if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
133 				break;
134 
135 			p = (char *)(ifmam + 1);
136 			for (i = 0; i < RTAX_MAX; i++) {
137 				if ((RTA_MASKS & ifmam->ifmam_addrs &
138 				    (1 << i)) == 0)
139 					continue;
140 				sa = (struct sockaddr *)(void *)p;
141 				len = SA_RLEN(sa);
142 				switch (i) {
143 				case RTAX_GATEWAY:
144 					ift->ifma_lladdr =
145 					    (struct sockaddr *)(void *)data;
146 					memcpy(data, p, len);
147 					data += len;
148 					break;
149 
150 				case RTAX_IFP:
151 					ift->ifma_name =
152 					    (struct sockaddr *)(void *)data;
153 					memcpy(data, p, len);
154 					data += len;
155 					break;
156 
157 				case RTAX_IFA:
158 					ift->ifma_addr =
159 					    (struct sockaddr *)(void *)data;
160 					memcpy(data, p, len);
161 					data += len;
162 					break;
163 
164 				default:
165 					data += len;
166 					break;
167 				}
168 				p += len;
169 			}
170 			ift->ifma_next = ift + 1;
171 			ift = ift->ifma_next;
172 			break;
173 		}
174 	}
175 
176 	free(buf);
177 
178 	if (ift > ifa) {
179 		ift--;
180 		ift->ifma_next = NULL;
181 		*pif = ifa;
182 	} else {
183 		*pif = NULL;
184 		free(ifa);
185 	}
186 	return (0);
187 }
188 
189 void
freeifmaddrs(struct ifmaddrs * ifmp)190 freeifmaddrs(struct ifmaddrs *ifmp)
191 {
192 
193 	free(ifmp);
194 }
195 
196