1 | /* |
---|
2 | * Copyright (c) 1988, 1991, 1993 |
---|
3 | * The Regents of the University of California. 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 | * 4. Neither the name of the University nor the names of its contributors |
---|
14 | * may be used to endorse or promote products derived from this software |
---|
15 | * without specific prior written permission. |
---|
16 | * |
---|
17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
27 | * SUCH DAMAGE. |
---|
28 | * |
---|
29 | * @(#)rtsock.c 8.7 (Berkeley) 10/12/95 |
---|
30 | * $FreeBSD: src/sys/net/rtsock.c,v 1.122 2005/03/26 21:49:43 sam Exp $ |
---|
31 | */ |
---|
32 | |
---|
33 | |
---|
34 | #ifdef HAVE_CONFIG_H |
---|
35 | #include "config.h" |
---|
36 | #endif |
---|
37 | |
---|
38 | #include <sys/param.h> |
---|
39 | #include <sys/queue.h> |
---|
40 | #include <sys/systm.h> |
---|
41 | #include <sys/kernel.h> |
---|
42 | #include <sys/sysctl.h> |
---|
43 | #include <sys/proc.h> |
---|
44 | #include <sys/mbuf.h> |
---|
45 | #include <sys/socket.h> |
---|
46 | #include <sys/socketvar.h> |
---|
47 | #include <sys/domain.h> |
---|
48 | #include <sys/protosw.h> |
---|
49 | |
---|
50 | #include <net/if.h> |
---|
51 | #include <net/if_var.h> |
---|
52 | #include <net/route.h> |
---|
53 | #include <net/raw_cb.h> |
---|
54 | |
---|
55 | static struct sockaddr route_dst = { 2, PF_ROUTE, { 0 } }; |
---|
56 | static struct sockaddr route_src = { 2, PF_ROUTE, { 0 } }; |
---|
57 | static struct sockaddr sa_zero = { sizeof(sa_zero), AF_INET, { 0 } }; |
---|
58 | static struct sockproto route_proto = { PF_ROUTE, 0 }; |
---|
59 | |
---|
60 | struct walkarg { |
---|
61 | int w_tmemsize; |
---|
62 | int w_op, w_arg; |
---|
63 | caddr_t w_tmem; |
---|
64 | struct sysctl_req *w_req; |
---|
65 | }; |
---|
66 | |
---|
67 | static struct mbuf *rt_msg1(int type, struct rt_addrinfo *rtinfo); |
---|
68 | static int rt_msg2(int type, struct rt_addrinfo *rtinfo, |
---|
69 | caddr_t cp, struct walkarg *w); |
---|
70 | static int rt_xaddrs(caddr_t cp, caddr_t cplim, |
---|
71 | struct rt_addrinfo *rtinfo); |
---|
72 | static int sysctl_dumpentry(struct radix_node *rn, void *vw); |
---|
73 | static int sysctl_iflist(int af, struct walkarg *w); |
---|
74 | static int route_output(struct mbuf *m, struct socket *so); |
---|
75 | static int route_usrreq(struct socket *, |
---|
76 | int, struct mbuf *, struct mbuf *, struct mbuf *); |
---|
77 | static void rt_setmetrics(u_long which, const struct rt_metrics *in, |
---|
78 | struct rt_metrics *out); |
---|
79 | |
---|
80 | /*ARGSUSED*/ |
---|
81 | static int |
---|
82 | route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, |
---|
83 | struct mbuf *control) |
---|
84 | { |
---|
85 | int error = 0; |
---|
86 | struct rawcb *rp = sotorawcb(so); |
---|
87 | int s; |
---|
88 | |
---|
89 | if (req == PRU_ATTACH) { |
---|
90 | MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); |
---|
91 | so->so_pcb = (caddr_t)rp; |
---|
92 | if (so->so_pcb) |
---|
93 | bzero(so->so_pcb, sizeof(*rp)); |
---|
94 | } |
---|
95 | if (req == PRU_DETACH && rp) { |
---|
96 | int af = rp->rcb_proto.sp_protocol; |
---|
97 | if (af == AF_INET) |
---|
98 | route_cb.ip_count--; |
---|
99 | else if (af == AF_IPX) |
---|
100 | route_cb.ipx_count--; |
---|
101 | else if (af == AF_ISO) |
---|
102 | route_cb.iso_count--; |
---|
103 | route_cb.any_count--; |
---|
104 | } |
---|
105 | s = splnet(); |
---|
106 | error = raw_usrreq(so, req, m, nam, control); |
---|
107 | rp = sotorawcb(so); |
---|
108 | if (req == PRU_ATTACH && rp) { |
---|
109 | int af = rp->rcb_proto.sp_protocol; |
---|
110 | if (error) { |
---|
111 | free((caddr_t)rp, M_PCB); |
---|
112 | splx(s); |
---|
113 | return (error); |
---|
114 | } |
---|
115 | if (af == AF_INET) |
---|
116 | route_cb.ip_count++; |
---|
117 | else if (af == AF_IPX) |
---|
118 | route_cb.ipx_count++; |
---|
119 | else if (af == AF_ISO) |
---|
120 | route_cb.iso_count++; |
---|
121 | rp->rcb_faddr = &route_src; |
---|
122 | route_cb.any_count++; |
---|
123 | soisconnected(so); |
---|
124 | so->so_options |= SO_USELOOPBACK; |
---|
125 | } |
---|
126 | splx(s); |
---|
127 | return (error); |
---|
128 | } |
---|
129 | |
---|
130 | /*ARGSUSED*/ |
---|
131 | static int |
---|
132 | route_output(struct mbuf *m, struct socket *so) |
---|
133 | { |
---|
134 | #define sa_equal(a1, a2) (bcmp((a1), (a2), (a1)->sa_len) == 0) |
---|
135 | struct rt_msghdr *rtm = NULL; |
---|
136 | struct rtentry *rt = NULL; |
---|
137 | struct rtentry *saved_nrt = 0; |
---|
138 | struct radix_node_head *rnh; |
---|
139 | struct rt_addrinfo info; |
---|
140 | int len, error = 0; |
---|
141 | struct ifnet *ifp = NULL; |
---|
142 | struct ifaddr *ifa = NULL; |
---|
143 | |
---|
144 | #define senderr(e) { error = e; goto flush;} |
---|
145 | if (m == NULL || ((m->m_len < sizeof(long)) && |
---|
146 | (m = m_pullup(m, sizeof(long))) == NULL)) |
---|
147 | return (ENOBUFS); |
---|
148 | if ((m->m_flags & M_PKTHDR) == 0) |
---|
149 | panic("route_output"); |
---|
150 | len = m->m_pkthdr.len; |
---|
151 | if (len < sizeof(*rtm) || |
---|
152 | len != mtod(m, struct rt_msghdr *)->rtm_msglen) { |
---|
153 | info.rti_info[RTAX_DST] = NULL; |
---|
154 | senderr(EINVAL); |
---|
155 | } |
---|
156 | R_Malloc(rtm, struct rt_msghdr *, len); |
---|
157 | if (rtm == NULL) { |
---|
158 | info.rti_info[RTAX_DST] = NULL; |
---|
159 | senderr(ENOBUFS); |
---|
160 | } |
---|
161 | m_copydata(m, 0, len, (caddr_t)rtm); |
---|
162 | if (rtm->rtm_version != RTM_VERSION) { |
---|
163 | info.rti_info[RTAX_DST] = NULL; |
---|
164 | senderr(EPROTONOSUPPORT); |
---|
165 | } |
---|
166 | info.rti_addrs = rtm->rtm_addrs; |
---|
167 | if (rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info)) { |
---|
168 | info.rti_info[RTAX_DST] = NULL; |
---|
169 | senderr(EINVAL); |
---|
170 | } |
---|
171 | if (info.rti_info[RTAX_DST] == NULL || |
---|
172 | info.rti_info[RTAX_DST]->sa_family >= AF_MAX || |
---|
173 | (info.rti_info[RTAX_GATEWAY] != NULL && |
---|
174 | info.rti_info[RTAX_GATEWAY]->sa_family >= AF_MAX)) |
---|
175 | senderr(EINVAL); |
---|
176 | if (info.rti_info[RTAX_GENMASK]) { |
---|
177 | struct radix_node *t; |
---|
178 | t = rn_addmask((caddr_t) info.rti_info[RTAX_GENMASK], 0, 1); |
---|
179 | if (t != NULL && |
---|
180 | Bcmp(info.rti_info[RTAX_GENMASK], t->rn_key, *(u_char *)info.rti_info[RTAX_GENMASK]) == 0) |
---|
181 | info.rti_info[RTAX_GENMASK] = |
---|
182 | (struct sockaddr *)t->rn_key; |
---|
183 | else |
---|
184 | senderr(ENOBUFS); |
---|
185 | } |
---|
186 | switch (rtm->rtm_type) { |
---|
187 | |
---|
188 | case RTM_ADD: |
---|
189 | if (info.rti_info[RTAX_GATEWAY] == NULL) |
---|
190 | senderr(EINVAL); |
---|
191 | error = rtrequest(RTM_ADD, info.rti_info[RTAX_DST], info.rti_info[RTAX_GATEWAY], info.rti_info[RTAX_NETMASK], |
---|
192 | rtm->rtm_flags, &saved_nrt); |
---|
193 | if (error == 0 && saved_nrt) { |
---|
194 | rt_setmetrics(rtm->rtm_inits, |
---|
195 | &rtm->rtm_rmx, &saved_nrt->rt_rmx); |
---|
196 | saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); |
---|
197 | saved_nrt->rt_rmx.rmx_locks |= |
---|
198 | (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); |
---|
199 | saved_nrt->rt_refcnt--; |
---|
200 | saved_nrt->rt_genmask = info.rti_info[RTAX_GENMASK]; |
---|
201 | } |
---|
202 | break; |
---|
203 | |
---|
204 | case RTM_DELETE: |
---|
205 | error = rtrequest(RTM_DELETE, info.rti_info[RTAX_DST], info.rti_info[RTAX_GATEWAY], info.rti_info[RTAX_NETMASK], |
---|
206 | rtm->rtm_flags, &saved_nrt); |
---|
207 | if (error == 0) { |
---|
208 | if ((rt = saved_nrt)) |
---|
209 | rt->rt_refcnt++; |
---|
210 | goto report; |
---|
211 | } |
---|
212 | break; |
---|
213 | |
---|
214 | case RTM_GET: |
---|
215 | case RTM_CHANGE: |
---|
216 | case RTM_LOCK: |
---|
217 | rnh = rt_tables[info.rti_info[RTAX_DST]->sa_family]; |
---|
218 | if (rnh == NULL) { |
---|
219 | senderr(EAFNOSUPPORT); |
---|
220 | } else if ((rt = (struct rtentry *) |
---|
221 | rnh->rnh_lookup(info.rti_info[RTAX_DST], info.rti_info[RTAX_NETMASK], rnh))) |
---|
222 | rt->rt_refcnt++; |
---|
223 | else |
---|
224 | senderr(ESRCH); |
---|
225 | switch(rtm->rtm_type) { |
---|
226 | |
---|
227 | case RTM_GET: |
---|
228 | report: |
---|
229 | info.rti_info[RTAX_DST] = rt_key(rt); |
---|
230 | info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; |
---|
231 | info.rti_info[RTAX_NETMASK] = rt_mask(rt); |
---|
232 | info.rti_info[RTAX_GENMASK] = rt->rt_genmask; |
---|
233 | if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { |
---|
234 | ifp = rt->rt_ifp; |
---|
235 | if (ifp) { |
---|
236 | info.rti_info[RTAX_IFP] = ifp->if_addrlist->ifa_addr; |
---|
237 | info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; |
---|
238 | rtm->rtm_index = ifp->if_index; |
---|
239 | } else { |
---|
240 | info.rti_info[RTAX_IFP] = NULL; |
---|
241 | info.rti_info[RTAX_IFA] = NULL; |
---|
242 | } |
---|
243 | } |
---|
244 | len = rt_msg2(rtm->rtm_type, &info, NULL, NULL); |
---|
245 | if (len > rtm->rtm_msglen) { |
---|
246 | struct rt_msghdr *new_rtm; |
---|
247 | R_Malloc(new_rtm, struct rt_msghdr *, len); |
---|
248 | if (new_rtm == NULL) { |
---|
249 | senderr(ENOBUFS); |
---|
250 | } |
---|
251 | Bcopy(rtm, new_rtm, rtm->rtm_msglen); |
---|
252 | Free(rtm); rtm = new_rtm; |
---|
253 | } |
---|
254 | (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, NULL); |
---|
255 | rtm->rtm_flags = rt->rt_flags; |
---|
256 | rtm->rtm_rmx = rt->rt_rmx; |
---|
257 | rtm->rtm_addrs = info.rti_addrs; |
---|
258 | break; |
---|
259 | |
---|
260 | case RTM_CHANGE: |
---|
261 | if (info.rti_info[RTAX_GATEWAY] && (error = rt_setgate(rt, rt_key(rt), info.rti_info[RTAX_GATEWAY]))) |
---|
262 | senderr(error); |
---|
263 | |
---|
264 | /* |
---|
265 | * If they tried to change things but didn't specify |
---|
266 | * the required gateway, then just use the old one. |
---|
267 | * This can happen if the user tries to change the |
---|
268 | * flags on the default route without changing the |
---|
269 | * default gateway. Changing flags still doesn't work. |
---|
270 | */ |
---|
271 | if ((rt->rt_flags & RTF_GATEWAY) && !info.rti_info[RTAX_GATEWAY]) |
---|
272 | info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; |
---|
273 | |
---|
274 | /* new gateway could require new ifaddr, ifp; |
---|
275 | flags may also be different; ifp may be specified |
---|
276 | by ll sockaddr when protocol address is ambiguous */ |
---|
277 | if (info.rti_info[RTAX_IFP] && (ifa = ifa_ifwithnet(info.rti_info[RTAX_IFP])) && |
---|
278 | (ifp = ifa->ifa_ifp) && (info.rti_info[RTAX_IFA] || info.rti_info[RTAX_GATEWAY])) |
---|
279 | ifa = ifaof_ifpforaddr(info.rti_info[RTAX_IFA] ? info.rti_info[RTAX_IFA] : info.rti_info[RTAX_GATEWAY], |
---|
280 | ifp); |
---|
281 | else if ((info.rti_info[RTAX_IFA] && (ifa = ifa_ifwithaddr(info.rti_info[RTAX_IFA]))) || |
---|
282 | (info.rti_info[RTAX_GATEWAY] && (ifa = ifa_ifwithroute(rt->rt_flags, |
---|
283 | rt_key(rt), info.rti_info[RTAX_GATEWAY])))) |
---|
284 | ifp = ifa->ifa_ifp; |
---|
285 | if (ifa) { |
---|
286 | struct ifaddr *oifa = rt->rt_ifa; |
---|
287 | if (oifa != ifa) { |
---|
288 | if (oifa && oifa->ifa_rtrequest) |
---|
289 | oifa->ifa_rtrequest(RTM_DELETE, |
---|
290 | rt, info.rti_info[RTAX_GATEWAY]); |
---|
291 | IFAFREE(rt->rt_ifa); |
---|
292 | rt->rt_ifa = ifa; |
---|
293 | ifa->ifa_refcnt++; |
---|
294 | rt->rt_ifp = ifp; |
---|
295 | } |
---|
296 | } |
---|
297 | rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, |
---|
298 | &rt->rt_rmx); |
---|
299 | if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) |
---|
300 | rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, info.rti_info[RTAX_GATEWAY]); |
---|
301 | if (info.rti_info[RTAX_GENMASK]) |
---|
302 | rt->rt_genmask = info.rti_info[RTAX_GENMASK]; |
---|
303 | /* FALLTHROUGH */ |
---|
304 | case RTM_LOCK: |
---|
305 | rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); |
---|
306 | rt->rt_rmx.rmx_locks |= |
---|
307 | (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); |
---|
308 | break; |
---|
309 | } |
---|
310 | break; |
---|
311 | |
---|
312 | default: |
---|
313 | senderr(EOPNOTSUPP); |
---|
314 | } |
---|
315 | |
---|
316 | flush: |
---|
317 | if (rtm) { |
---|
318 | if (error) |
---|
319 | rtm->rtm_errno = error; |
---|
320 | else |
---|
321 | rtm->rtm_flags |= RTF_DONE; |
---|
322 | } |
---|
323 | if (rt) /* XXX can this be true? */ |
---|
324 | rtfree(rt); |
---|
325 | { |
---|
326 | struct rawcb *rp = NULL; |
---|
327 | /* |
---|
328 | * Check to see if we don't want our own messages. |
---|
329 | */ |
---|
330 | if ((so->so_options & SO_USELOOPBACK) == 0) { |
---|
331 | if (route_cb.any_count <= 1) { |
---|
332 | if (rtm) |
---|
333 | Free(rtm); |
---|
334 | m_freem(m); |
---|
335 | return (error); |
---|
336 | } |
---|
337 | /* There is another listener, so construct message */ |
---|
338 | rp = sotorawcb(so); |
---|
339 | } |
---|
340 | if (rtm) { |
---|
341 | m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); |
---|
342 | Free(rtm); |
---|
343 | } |
---|
344 | if (rp) |
---|
345 | rp->rcb_proto.sp_family = 0; /* Avoid us */ |
---|
346 | if (info.rti_info[RTAX_DST]) |
---|
347 | route_proto.sp_protocol = info.rti_info[RTAX_DST]->sa_family; |
---|
348 | raw_input(m, &route_proto, &route_src, &route_dst); |
---|
349 | if (rp) |
---|
350 | rp->rcb_proto.sp_family = PF_ROUTE; |
---|
351 | } |
---|
352 | return (error); |
---|
353 | #undef sa_equal |
---|
354 | } |
---|
355 | |
---|
356 | static void |
---|
357 | rt_setmetrics(u_long which, const struct rt_metrics *in, |
---|
358 | struct rt_metrics *out) |
---|
359 | { |
---|
360 | #define metric(f, e) if (which & (f)) out->e = in->e; |
---|
361 | metric(RTV_RPIPE, rmx_recvpipe); |
---|
362 | metric(RTV_SPIPE, rmx_sendpipe); |
---|
363 | metric(RTV_SSTHRESH, rmx_ssthresh); |
---|
364 | metric(RTV_RTT, rmx_rtt); |
---|
365 | metric(RTV_RTTVAR, rmx_rttvar); |
---|
366 | metric(RTV_HOPCOUNT, rmx_hopcount); |
---|
367 | metric(RTV_MTU, rmx_mtu); |
---|
368 | metric(RTV_EXPIRE, rmx_expire); |
---|
369 | #undef metric |
---|
370 | } |
---|
371 | |
---|
372 | #define ROUNDUP(a) \ |
---|
373 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) |
---|
374 | #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) |
---|
375 | |
---|
376 | |
---|
377 | /* |
---|
378 | * Extract the addresses of the passed sockaddrs. |
---|
379 | * Do a little sanity checking so as to avoid bad memory references. |
---|
380 | * This data is derived straight from userland. |
---|
381 | */ |
---|
382 | static int |
---|
383 | rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) |
---|
384 | { |
---|
385 | struct sockaddr *sa; |
---|
386 | int i; |
---|
387 | |
---|
388 | bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info)); |
---|
389 | for (i = 0; i < RTAX_MAX && cp < cplim; i++) { |
---|
390 | if ((rtinfo->rti_addrs & (1 << i)) == 0) |
---|
391 | continue; |
---|
392 | sa = (struct sockaddr *)cp; |
---|
393 | /* |
---|
394 | * It won't fit. |
---|
395 | */ |
---|
396 | if (cp + sa->sa_len > cplim) |
---|
397 | return (EINVAL); |
---|
398 | /* |
---|
399 | * there are no more.. quit now |
---|
400 | * If there are more bits, they are in error. |
---|
401 | * I've seen this. route(1) can evidently generate these. |
---|
402 | * This causes kernel to core dump. |
---|
403 | * for compatibility, If we see this, point to a safe address. |
---|
404 | */ |
---|
405 | if (sa->sa_len == 0) { |
---|
406 | rtinfo->rti_info[i] = &sa_zero; |
---|
407 | return (0); /* should be EINVAL but for compat */ |
---|
408 | } |
---|
409 | /* accept it */ |
---|
410 | rtinfo->rti_info[i] = sa; |
---|
411 | ADVANCE(cp, sa); |
---|
412 | } |
---|
413 | return (0); |
---|
414 | } |
---|
415 | |
---|
416 | static struct mbuf * |
---|
417 | rt_msg1(int type, struct rt_addrinfo *rtinfo) |
---|
418 | { |
---|
419 | struct rt_msghdr *rtm; |
---|
420 | struct mbuf *m; |
---|
421 | int i; |
---|
422 | struct sockaddr *sa; |
---|
423 | int len, dlen; |
---|
424 | |
---|
425 | m = m_gethdr(M_DONTWAIT, MT_DATA); |
---|
426 | if (m == 0) |
---|
427 | return (m); |
---|
428 | switch (type) { |
---|
429 | |
---|
430 | case RTM_DELADDR: |
---|
431 | case RTM_NEWADDR: |
---|
432 | len = sizeof(struct ifa_msghdr); |
---|
433 | break; |
---|
434 | |
---|
435 | case RTM_IFINFO: |
---|
436 | len = sizeof(struct if_msghdr); |
---|
437 | break; |
---|
438 | |
---|
439 | default: |
---|
440 | len = sizeof(struct rt_msghdr); |
---|
441 | } |
---|
442 | if (len > MHLEN) |
---|
443 | panic("rt_msg1"); |
---|
444 | m->m_pkthdr.len = m->m_len = len; |
---|
445 | m->m_pkthdr.rcvif = NULL; |
---|
446 | rtm = mtod(m, struct rt_msghdr *); |
---|
447 | bzero((caddr_t)rtm, len); |
---|
448 | for (i = 0; i < RTAX_MAX; i++) { |
---|
449 | if ((sa = rtinfo->rti_info[i]) == NULL) |
---|
450 | continue; |
---|
451 | rtinfo->rti_addrs |= (1 << i); |
---|
452 | dlen = ROUNDUP(sa->sa_len); |
---|
453 | m_copyback(m, len, dlen, (caddr_t)sa); |
---|
454 | len += dlen; |
---|
455 | } |
---|
456 | if (m->m_pkthdr.len != len) { |
---|
457 | m_freem(m); |
---|
458 | return (NULL); |
---|
459 | } |
---|
460 | rtm->rtm_msglen = len; |
---|
461 | rtm->rtm_version = RTM_VERSION; |
---|
462 | rtm->rtm_type = type; |
---|
463 | return (m); |
---|
464 | } |
---|
465 | |
---|
466 | static int |
---|
467 | rt_msg2(int type, struct rt_addrinfo *rtinfo, caddr_t cp, struct walkarg *w) |
---|
468 | { |
---|
469 | int i; |
---|
470 | int len, dlen, second_time = 0; |
---|
471 | caddr_t cp0; |
---|
472 | |
---|
473 | rtinfo->rti_addrs = 0; |
---|
474 | again: |
---|
475 | switch (type) { |
---|
476 | |
---|
477 | case RTM_DELADDR: |
---|
478 | case RTM_NEWADDR: |
---|
479 | len = sizeof(struct ifa_msghdr); |
---|
480 | break; |
---|
481 | |
---|
482 | case RTM_IFINFO: |
---|
483 | len = sizeof(struct if_msghdr); |
---|
484 | break; |
---|
485 | |
---|
486 | default: |
---|
487 | len = sizeof(struct rt_msghdr); |
---|
488 | } |
---|
489 | cp0 = cp; |
---|
490 | if (cp0) |
---|
491 | cp += len; |
---|
492 | for (i = 0; i < RTAX_MAX; i++) { |
---|
493 | struct sockaddr *sa; |
---|
494 | |
---|
495 | if ((sa = rtinfo->rti_info[i]) == NULL) |
---|
496 | continue; |
---|
497 | rtinfo->rti_addrs |= (1 << i); |
---|
498 | dlen = ROUNDUP(sa->sa_len); |
---|
499 | if (cp) { |
---|
500 | bcopy((caddr_t)sa, cp, (unsigned)dlen); |
---|
501 | cp += dlen; |
---|
502 | } |
---|
503 | len += dlen; |
---|
504 | } |
---|
505 | if (cp == NULL && w != NULL && !second_time) { |
---|
506 | struct walkarg *rw = w; |
---|
507 | |
---|
508 | if (rw->w_req) { |
---|
509 | if (rw->w_tmemsize < len) { |
---|
510 | if (rw->w_tmem) |
---|
511 | free(rw->w_tmem, M_RTABLE); |
---|
512 | rw->w_tmem = (caddr_t) |
---|
513 | malloc(len, M_RTABLE, M_NOWAIT); |
---|
514 | if (rw->w_tmem) |
---|
515 | rw->w_tmemsize = len; |
---|
516 | } |
---|
517 | if (rw->w_tmem) { |
---|
518 | cp = rw->w_tmem; |
---|
519 | second_time = 1; |
---|
520 | goto again; |
---|
521 | } |
---|
522 | } |
---|
523 | } |
---|
524 | if (cp) { |
---|
525 | struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; |
---|
526 | |
---|
527 | rtm->rtm_version = RTM_VERSION; |
---|
528 | rtm->rtm_type = type; |
---|
529 | rtm->rtm_msglen = len; |
---|
530 | } |
---|
531 | return (len); |
---|
532 | } |
---|
533 | |
---|
534 | /* |
---|
535 | * This routine is called to generate a message from the routing |
---|
536 | * socket indicating that a redirect has occured, a routing lookup |
---|
537 | * has failed, or that a protocol has detected timeouts to a particular |
---|
538 | * destination. |
---|
539 | */ |
---|
540 | void |
---|
541 | rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error) |
---|
542 | { |
---|
543 | struct rt_msghdr *rtm; |
---|
544 | struct mbuf *m; |
---|
545 | struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; |
---|
546 | |
---|
547 | if (route_cb.any_count == 0) |
---|
548 | return; |
---|
549 | m = rt_msg1(type, rtinfo); |
---|
550 | if (m == NULL) |
---|
551 | return; |
---|
552 | rtm = mtod(m, struct rt_msghdr *); |
---|
553 | rtm->rtm_flags = RTF_DONE | flags; |
---|
554 | rtm->rtm_errno = error; |
---|
555 | rtm->rtm_addrs = rtinfo->rti_addrs; |
---|
556 | route_proto.sp_protocol = sa ? sa->sa_family : 0; |
---|
557 | raw_input(m, &route_proto, &route_src, &route_dst); |
---|
558 | } |
---|
559 | |
---|
560 | /* |
---|
561 | * This routine is called to generate a message from the routing |
---|
562 | * socket indicating that the status of a network interface has changed. |
---|
563 | */ |
---|
564 | void |
---|
565 | rt_ifmsg(struct ifnet *ifp) |
---|
566 | { |
---|
567 | struct if_msghdr *ifm; |
---|
568 | struct mbuf *m; |
---|
569 | struct rt_addrinfo info; |
---|
570 | |
---|
571 | if (route_cb.any_count == 0) |
---|
572 | return; |
---|
573 | bzero((caddr_t)&info, sizeof(info)); |
---|
574 | m = rt_msg1(RTM_IFINFO, &info); |
---|
575 | if (m == NULL) |
---|
576 | return; |
---|
577 | ifm = mtod(m, struct if_msghdr *); |
---|
578 | ifm->ifm_index = ifp->if_index; |
---|
579 | ifm->ifm_flags = ifp->if_flags; |
---|
580 | ifm->ifm_data = ifp->if_data; |
---|
581 | ifm->ifm_addrs = 0; |
---|
582 | route_proto.sp_protocol = 0; |
---|
583 | raw_input(m, &route_proto, &route_src, &route_dst); |
---|
584 | } |
---|
585 | |
---|
586 | /* |
---|
587 | * This is called to generate messages from the routing socket |
---|
588 | * indicating a network interface has had addresses associated with it. |
---|
589 | * if we ever reverse the logic and replace messages TO the routing |
---|
590 | * socket indicate a request to configure interfaces, then it will |
---|
591 | * be unnecessary as the routing socket will automatically generate |
---|
592 | * copies of it. |
---|
593 | */ |
---|
594 | void |
---|
595 | rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt) |
---|
596 | { |
---|
597 | struct rt_addrinfo info; |
---|
598 | struct sockaddr *sa = NULL; |
---|
599 | int pass; |
---|
600 | struct mbuf *m = NULL; |
---|
601 | struct ifnet *ifp = ifa->ifa_ifp; |
---|
602 | |
---|
603 | if (route_cb.any_count == 0) |
---|
604 | return; |
---|
605 | for (pass = 1; pass < 3; pass++) { |
---|
606 | bzero((caddr_t)&info, sizeof(info)); |
---|
607 | if ((cmd == RTM_ADD && pass == 1) || |
---|
608 | (cmd == RTM_DELETE && pass == 2)) { |
---|
609 | struct ifa_msghdr *ifam; |
---|
610 | int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; |
---|
611 | |
---|
612 | info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr; |
---|
613 | info.rti_info[RTAX_IFP] = ifp->if_addrlist->ifa_addr; |
---|
614 | info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; |
---|
615 | info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; |
---|
616 | if ((m = rt_msg1(ncmd, &info)) == NULL) |
---|
617 | continue; |
---|
618 | ifam = mtod(m, struct ifa_msghdr *); |
---|
619 | ifam->ifam_index = ifp->if_index; |
---|
620 | ifam->ifam_metric = ifa->ifa_metric; |
---|
621 | ifam->ifam_flags = ifa->ifa_flags; |
---|
622 | ifam->ifam_addrs = info.rti_addrs; |
---|
623 | } |
---|
624 | if ((cmd == RTM_ADD && pass == 2) || |
---|
625 | (cmd == RTM_DELETE && pass == 1)) { |
---|
626 | struct rt_msghdr *rtm; |
---|
627 | |
---|
628 | if (rt == NULL) |
---|
629 | continue; |
---|
630 | info.rti_info[RTAX_NETMASK] = rt_mask(rt); |
---|
631 | info.rti_info[RTAX_DST] = sa = rt_key(rt); |
---|
632 | info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; |
---|
633 | if ((m = rt_msg1(cmd, &info)) == NULL) |
---|
634 | continue; |
---|
635 | rtm = mtod(m, struct rt_msghdr *); |
---|
636 | rtm->rtm_index = ifp->if_index; |
---|
637 | rtm->rtm_flags |= rt->rt_flags; |
---|
638 | rtm->rtm_errno = error; |
---|
639 | rtm->rtm_addrs = info.rti_addrs; |
---|
640 | } |
---|
641 | route_proto.sp_protocol = sa ? sa->sa_family : 0; |
---|
642 | raw_input(m, &route_proto, &route_src, &route_dst); |
---|
643 | } |
---|
644 | } |
---|
645 | |
---|
646 | |
---|
647 | /* |
---|
648 | * This is used in dumping the kernel table via sysctl(). |
---|
649 | */ |
---|
650 | int |
---|
651 | sysctl_dumpentry(struct radix_node *rn, void *vw) |
---|
652 | { |
---|
653 | struct walkarg *w = vw; |
---|
654 | struct rtentry *rt = (struct rtentry *)rn; |
---|
655 | int error = 0, size; |
---|
656 | struct rt_addrinfo info; |
---|
657 | |
---|
658 | if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) |
---|
659 | return 0; |
---|
660 | bzero((caddr_t)&info, sizeof(info)); |
---|
661 | info.rti_info[RTAX_DST] = rt_key(rt); |
---|
662 | info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; |
---|
663 | info.rti_info[RTAX_NETMASK] = rt_mask(rt); |
---|
664 | info.rti_info[RTAX_GENMASK] = rt->rt_genmask; |
---|
665 | size = rt_msg2(RTM_GET, &info, NULL, w); |
---|
666 | if (w->w_req && w->w_tmem) { |
---|
667 | struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; |
---|
668 | |
---|
669 | rtm->rtm_flags = rt->rt_flags; |
---|
670 | rtm->rtm_use = rt->rt_use; |
---|
671 | rtm->rtm_rmx = rt->rt_rmx; |
---|
672 | rtm->rtm_index = rt->rt_ifp->if_index; |
---|
673 | rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; |
---|
674 | rtm->rtm_addrs = info.rti_addrs; |
---|
675 | error = SYSCTL_OUT(w->w_req, (caddr_t)rtm, size); |
---|
676 | return (error); |
---|
677 | } |
---|
678 | return (error); |
---|
679 | } |
---|
680 | |
---|
681 | int |
---|
682 | sysctl_iflist(int af, struct walkarg *w) |
---|
683 | { |
---|
684 | struct ifnet *ifp; |
---|
685 | struct ifaddr *ifa; |
---|
686 | struct rt_addrinfo info; |
---|
687 | int len, error = 0; |
---|
688 | |
---|
689 | bzero((caddr_t)&info, sizeof(info)); |
---|
690 | for (ifp = ifnet; ifp; ifp = ifp->if_next) { |
---|
691 | if (w->w_arg && w->w_arg != ifp->if_index) |
---|
692 | continue; |
---|
693 | ifa = ifp->if_addrlist; |
---|
694 | info.rti_info[RTAX_IFP] = ifa->ifa_addr; |
---|
695 | len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w); |
---|
696 | info.rti_info[RTAX_IFP] = 0; |
---|
697 | if (w->w_req && w->w_tmem) { |
---|
698 | struct if_msghdr *ifm; |
---|
699 | |
---|
700 | ifm = (struct if_msghdr *)w->w_tmem; |
---|
701 | ifm->ifm_index = ifp->if_index; |
---|
702 | ifm->ifm_flags = ifp->if_flags; |
---|
703 | ifm->ifm_data = ifp->if_data; |
---|
704 | ifm->ifm_addrs = info.rti_addrs; |
---|
705 | error = SYSCTL_OUT(w->w_req,(caddr_t)ifm, len); |
---|
706 | if (error) |
---|
707 | return (error); |
---|
708 | } |
---|
709 | while ((ifa = ifa->ifa_next) != 0) { |
---|
710 | if (af && af != ifa->ifa_addr->sa_family) |
---|
711 | continue; |
---|
712 | info.rti_info[RTAX_IFA] = ifa->ifa_addr; |
---|
713 | info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; |
---|
714 | info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; |
---|
715 | len = rt_msg2(RTM_NEWADDR, &info, NULL, w); |
---|
716 | if (w->w_req && w->w_tmem) { |
---|
717 | struct ifa_msghdr *ifam; |
---|
718 | |
---|
719 | ifam = (struct ifa_msghdr *)w->w_tmem; |
---|
720 | ifam->ifam_index = ifa->ifa_ifp->if_index; |
---|
721 | ifam->ifam_flags = ifa->ifa_flags; |
---|
722 | ifam->ifam_metric = ifa->ifa_metric; |
---|
723 | ifam->ifam_addrs = info.rti_addrs; |
---|
724 | error = SYSCTL_OUT(w->w_req, w->w_tmem, len); |
---|
725 | if (error) |
---|
726 | return (error); |
---|
727 | } |
---|
728 | } |
---|
729 | info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] = info.rti_info[RTAX_BRD] = 0; |
---|
730 | } |
---|
731 | return (0); |
---|
732 | } |
---|
733 | |
---|
734 | static int |
---|
735 | sysctl_rtsock(SYSCTL_HANDLER_ARGS) |
---|
736 | { |
---|
737 | int *name = (int *)arg1; |
---|
738 | u_int namelen = arg2; |
---|
739 | struct radix_node_head *rnh; |
---|
740 | int i, s, error = EINVAL; |
---|
741 | u_char af; |
---|
742 | struct walkarg w; |
---|
743 | |
---|
744 | name ++; |
---|
745 | namelen--; |
---|
746 | if (req->newptr) |
---|
747 | return (EPERM); |
---|
748 | if (namelen != 3) |
---|
749 | return (EINVAL); |
---|
750 | af = name[0]; |
---|
751 | Bzero(&w, sizeof(w)); |
---|
752 | w.w_op = name[1]; |
---|
753 | w.w_arg = name[2]; |
---|
754 | w.w_req = req; |
---|
755 | |
---|
756 | s = splnet(); |
---|
757 | switch (w.w_op) { |
---|
758 | |
---|
759 | case NET_RT_DUMP: |
---|
760 | case NET_RT_FLAGS: |
---|
761 | for (i = 1; i <= AF_MAX; i++) |
---|
762 | if ((rnh = rt_tables[i]) && (af == 0 || af == i) && |
---|
763 | (error = rnh->rnh_walktree(rnh, |
---|
764 | sysctl_dumpentry, &w))) |
---|
765 | break; |
---|
766 | break; |
---|
767 | |
---|
768 | case NET_RT_IFLIST: |
---|
769 | error = sysctl_iflist(af, &w); |
---|
770 | } |
---|
771 | splx(s); |
---|
772 | if (w.w_tmem) |
---|
773 | free(w.w_tmem, M_RTABLE); |
---|
774 | return (error); |
---|
775 | } |
---|
776 | |
---|
777 | SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock,""); |
---|
778 | |
---|
779 | /* |
---|
780 | * Definitions of protocols supported in the ROUTE domain. |
---|
781 | */ |
---|
782 | |
---|
783 | extern struct domain routedomain; /* or at least forward */ |
---|
784 | |
---|
785 | static struct protosw routesw[] = { |
---|
786 | { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, |
---|
787 | 0, route_output, raw_ctlinput, 0, |
---|
788 | route_usrreq, |
---|
789 | raw_init, NULL, NULL, NULL, |
---|
790 | NULL |
---|
791 | } |
---|
792 | }; |
---|
793 | |
---|
794 | struct domain routedomain = |
---|
795 | { PF_ROUTE, "route", route_init, 0, 0, |
---|
796 | routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])], |
---|
797 | NULL, NULL, 0, 0 }; |
---|
798 | |
---|
799 | DOMAIN_SET(route); |
---|