1 /* $NetBSD: darwin_route.c,v 1.14 2008/04/28 20:23:41 martin Exp $ */
2
3 /*-
4 * Copyright (c) 2004 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: darwin_route.c,v 1.14 2008/04/28 20:23:41 martin Exp $");
34
35 #include <sys/errno.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38
39 #include <net/if.h>
40
41 #include <compat/darwin/darwin_socket.h>
42 #include <compat/darwin/darwin_route.h>
43
44 static int darwin_copyout_sockaddr(struct sockaddr *, char **, size_t *, size_t);
45
46 #define ALIGN(a) (((a) + 3) & ~0x3UL)
47 int
48 darwin_ifaddrs(int af, char *dst, size_t *sizep)
49 {
50 struct darwin_if_msghdr dim;
51 struct ifnet *ifp;
52 int error;
53 int index = 1;
54 size_t size = 0;
55 size_t maxsize = *sizep;
56 uint8_t family;
57
58 af = darwin_to_native_af[af];
59
60 IFNET_FOREACH(ifp) {
61 struct ifaddr *ifa;
62 struct sockaddr *laddr = NULL;
63
64 /*
65 * Find the link layer info as it is needed
66 * for computing darwin_if_msghdr's dim_len
67 */
68 IFADDR_FOREACH(ifa, ifp) {
69 if ((ifa->ifa_addr) &&
70 (ifa->ifa_addr->sa_family == AF_LINK)) {
71 laddr = (struct sockaddr *)ifa->ifa_addr;
72 break;
73 }
74 }
75
76 if (laddr == NULL) {
77 #ifdef DEBUG_DARWIN
78 printf("darwin_ifaddrs: cannot find link address\n");
79 #endif
80 continue;
81 }
82
83 dim.dim_len = sizeof(dim) + ALIGN(laddr->sa_len);
84 dim.dim_vers = DARWIN_RTM_VERSION;
85 dim.dim_type = DARWIN_RTM_IFINFO;
86 dim.dim_addrs = DARWIN_RTA_IFP;
87 dim.dim_flags = ifp->if_flags & 0xffff;
88 dim.dim_index = index++;
89
90 dim.dim_data.did_type = ifp->if_data.ifi_type; /* XXX */
91 dim.dim_data.did_typelen = 0 ;/* XXX */
92 dim.dim_data.did_physical = 0; /* XXX */
93 dim.dim_data.did_addrlen = ifp->if_data.ifi_addrlen;
94 dim.dim_data.did_hdrlen = ifp->if_data.ifi_hdrlen;
95 dim.dim_data.did_recquota = 0; /* XXX */
96 dim.dim_data.did_xmitquota = 0; /* XXX */
97 dim.dim_data.did_mtu = ifp->if_data.ifi_mtu;
98 dim.dim_data.did_metric = ifp->if_data.ifi_metric;
99 dim.dim_data.did_baudrate = ifp->if_data.ifi_baudrate;
100 dim.dim_data.did_ipackets = ifp->if_data.ifi_ipackets;
101 dim.dim_data.did_ierrors = ifp->if_data.ifi_ierrors;
102 dim.dim_data.did_opackets = ifp->if_data.ifi_opackets;
103 dim.dim_data.did_oerrors = ifp->if_data.ifi_oerrors;
104 dim.dim_data.did_collisions = ifp->if_data.ifi_collisions;
105 dim.dim_data.did_ibytes = ifp->if_data.ifi_ibytes;
106 dim.dim_data.did_obytes = ifp->if_data.ifi_obytes;
107 dim.dim_data.did_imcasts = ifp->if_data.ifi_imcasts;
108 dim.dim_data.did_omcasts = ifp->if_data.ifi_omcasts;
109 dim.dim_data.did_iqdrops = ifp->if_data.ifi_iqdrops;
110 dim.dim_data.did_noproto = ifp->if_data.ifi_noproto;
111 dim.dim_data.did_lastchange.tv_sec =
112 ifp->if_data.ifi_lastchange.tv_sec;
113 dim.dim_data.did_lastchange.tv_usec =
114 ifp->if_data.ifi_lastchange.tv_usec;
115 dim.dim_data.did_default_proto = 0; /* XXX */
116 dim.dim_data.did_hwassist = 0; /* XXX */
117
118 size += sizeof(dim);
119 if (dst && (size <= maxsize)) {
120 if ((error = copyout(&dim, dst, sizeof(dim))) != 0)
121 return error;
122 dst += sizeof(dim);
123 }
124
125 /* Copy the link sockaddr. */
126 size += ALIGN(laddr->sa_len);
127 if (dst && (size <= maxsize)) {
128 if ((error = copyout(laddr, dst, laddr->sa_len)) != 0)
129 return error;
130 family = native_to_darwin_af[laddr->sa_family];
131 error = copyout(&family,
132 &((struct sockaddr *)dst)->sa_family, 1);
133 if (error != 0)
134 return error;
135 dst += ALIGN(laddr->sa_len);
136 }
137
138 IFADDR_FOREACH(ifa, ifp) {
139 struct darwin_ifa_msghdr diam;
140 int iaf;
141
142 if (ifa->ifa_addr) {
143 iaf = ifa->ifa_addr->sa_family;
144 if ((af != 0) && (iaf != af))
145 continue;
146 if (iaf > AF_MAX)
147 continue;
148 if (iaf == 0)
149 continue;
150 if (native_to_darwin_af[iaf] == 0)
151 continue;
152 /* Already handled earlier */
153 if (iaf == AF_LINK)
154 continue;
155 }
156
157 bzero(&diam, sizeof(diam));
158
159 diam.diam_len = sizeof(diam);
160 diam.diam_vers = DARWIN_RTM_VERSION;
161 diam.diam_type = DARWIN_RTM_NEWADDR;
162
163 /*
164 * XXX the following code assumes that
165 * Darwin sockaddr have the same size as
166 * the original.
167 */
168 if (ifa->ifa_addr) {
169 diam.diam_addrs |= DARWIN_RTA_IFA;
170 diam.diam_len += ALIGN(ifa->ifa_addr->sa_len);
171 }
172 if (ifa->ifa_netmask) {
173 diam.diam_addrs |= DARWIN_RTA_NETMASK;
174 diam.diam_len +=
175 ALIGN(ifa->ifa_netmask->sa_len);
176 }
177 if ((ifa->ifa_dstaddr != NULL) &&
178 (ifp->if_flags & IFF_POINTOPOINT)) {
179 diam.diam_addrs |= DARWIN_RTA_DST;
180 diam.diam_len +=
181 ALIGN(ifa->ifa_dstaddr->sa_len);
182 }
183 if ((ifa->ifa_broadaddr != NULL) &&
184 (ifp->if_flags & IFF_BROADCAST)) {
185 diam.diam_addrs |= DARWIN_RTA_BRD;
186 diam.diam_len +=
187 ALIGN(ifa->ifa_broadaddr->sa_len);
188 }
189
190 diam.diam_flags = (int)ifa->ifa_flags;
191 diam.diam_index = dim.dim_index;
192 diam.diam_metric = ifa->ifa_metric;
193
194 size += sizeof(diam);
195 if (dst && (size <= maxsize)) {
196 error = copyout(&diam, dst, sizeof(diam));
197 if (error != 0)
198 return error;
199 dst += sizeof(diam);
200 }
201
202 /*
203 * Interface netmask
204 * We sometime lack the af in native version:
205 * copy it from ifa_addr.
206 */
207 if (diam.diam_addrs & DARWIN_RTA_NETMASK) {
208 struct sockaddr_storage ss;
209
210 memcpy(&ss, ifa->ifa_netmask,
211 ifa->ifa_netmask->sa_len);
212 if ((ss.ss_family == 0) &&
213 (ifa->ifa_addr != NULL) &&
214 (ifa->ifa_addr->sa_family != 0))
215 ss.ss_family =
216 ifa->ifa_addr->sa_family;
217
218 if ((error = darwin_copyout_sockaddr(
219 (struct sockaddr *)&ss, &dst,
220 &size, maxsize)) != 0)
221 return error;
222 }
223
224 /* Interface address */
225 if (diam.diam_addrs & DARWIN_RTA_IFA)
226 if ((error = darwin_copyout_sockaddr(ifa->ifa_addr,
227 &dst, &size, maxsize)) != 0)
228 return error;
229
230 /* Interface remote address */
231 if (diam.diam_addrs & DARWIN_RTA_DST)
232 if ((error = darwin_copyout_sockaddr(ifa->ifa_dstaddr,
233 &dst, &size, maxsize)) != 0)
234 return error;
235
236 /* Interface broadcast address */
237 if (diam.diam_addrs & DARWIN_RTA_BRD)
238 if ((error =
239 darwin_copyout_sockaddr(ifa->ifa_broadaddr,
240 &dst, &size, maxsize)) != 0)
241 return error;
242 }
243 }
244
245 *sizep = size;
246
247 if (dst && (size > maxsize))
248 return ENOMEM;
249
250 return 0;
251 }
252
253
254 static int
255 darwin_copyout_sockaddr(struct sockaddr *sap, char **dstp, size_t *sizep, size_t maxsize)
256 {
257 size_t len;
258 int error;
259 uint8_t family;
260
261 len = sap->sa_len;
262
263 *sizep += ALIGN(len);
264 if (*dstp && (*sizep <= maxsize)) {
265 if ((error = copyout(sap, *dstp, len)) != 0)
266 return error;
267 family = native_to_darwin_af[sap->sa_family];
268 error = copyout(&family,
269 &((struct sockaddr *)*dstp)->sa_family, 1);
270 if (error != 0)
271 return error;
272 *dstp += ALIGN(len);
273 }
274
275 return 0;
276 }
Cache object: a5679e0eda8dc6f5a1e9461d65689634
|