Commit | Line | Data |
---|---|---|
f3ed2586 JH |
1 | /* |
2 | * Copyright (c) 2004, 2005 The DragonFly Project. All rights reserved. | |
3 | * | |
4 | * This code is derived from software contributed to The DragonFly Project | |
5 | * by Jeffrey M. Hsu. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of The DragonFly Project nor the names of its | |
16 | * contributors may be used to endorse or promote products derived | |
17 | * from this software without specific, prior written permission. | |
18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
22 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
23 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
24 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
25 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
27 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
29 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
30 | * SUCH DAMAGE. | |
31 | */ | |
32 | ||
33 | /* | |
34 | * Copyright (c) 2004, 2005 Jeffrey M. Hsu. All rights reserved. | |
35 | * | |
36 | * License terms: all terms for the DragonFly license above plus the following: | |
37 | * | |
38 | * 4. All advertising materials mentioning features or use of this software | |
39 | * must display the following acknowledgement: | |
40 | * | |
41 | * This product includes software developed by Jeffrey M. Hsu | |
42 | * for the DragonFly Project. | |
43 | * | |
44 | * This requirement may be waived with permission from Jeffrey Hsu. | |
45 | * Permission will be granted to any DragonFly user for free. | |
46 | * This requirement will sunset and may be removed on Jan 31, 2006, | |
47 | * after which the standard DragonFly license (as shown above) will | |
48 | * apply. | |
49 | */ | |
50 | ||
984263bc MD |
51 | /* |
52 | * Copyright (c) 1988, 1991, 1993 | |
53 | * The Regents of the University of California. All rights reserved. | |
54 | * | |
55 | * Redistribution and use in source and binary forms, with or without | |
56 | * modification, are permitted provided that the following conditions | |
57 | * are met: | |
58 | * 1. Redistributions of source code must retain the above copyright | |
59 | * notice, this list of conditions and the following disclaimer. | |
60 | * 2. Redistributions in binary form must reproduce the above copyright | |
61 | * notice, this list of conditions and the following disclaimer in the | |
62 | * documentation and/or other materials provided with the distribution. | |
63 | * 3. All advertising materials mentioning features or use of this software | |
64 | * must display the following acknowledgement: | |
65 | * This product includes software developed by the University of | |
66 | * California, Berkeley and its contributors. | |
67 | * 4. Neither the name of the University nor the names of its contributors | |
68 | * may be used to endorse or promote products derived from this software | |
69 | * without specific prior written permission. | |
70 | * | |
71 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
72 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
73 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
74 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
75 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
76 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
77 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
78 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
79 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
80 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
81 | * SUCH DAMAGE. | |
82 | * | |
83 | * @(#)rtsock.c 8.7 (Berkeley) 10/12/95 | |
84 | * $FreeBSD: src/sys/net/rtsock.c,v 1.44.2.11 2002/12/04 14:05:41 ru Exp $ | |
8e63efec | 85 | * $DragonFly: src/sys/net/rtsock.c,v 1.24 2005/03/04 03:37:43 hsu Exp $ |
984263bc MD |
86 | */ |
87 | ||
984263bc MD |
88 | #include <sys/param.h> |
89 | #include <sys/systm.h> | |
90 | #include <sys/kernel.h> | |
91 | #include <sys/sysctl.h> | |
92 | #include <sys/proc.h> | |
93 | #include <sys/malloc.h> | |
94 | #include <sys/mbuf.h> | |
47e78ae8 | 95 | #include <sys/protosw.h> |
984263bc MD |
96 | #include <sys/socket.h> |
97 | #include <sys/socketvar.h> | |
98 | #include <sys/domain.h> | |
984263bc | 99 | |
deffea2e JS |
100 | #include <machine/stdarg.h> |
101 | ||
984263bc MD |
102 | #include <net/if.h> |
103 | #include <net/route.h> | |
104 | #include <net/raw_cb.h> | |
105 | ||
106 | MALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables"); | |
107 | ||
f23061d4 JH |
108 | static struct route_cb { |
109 | int ip_count; | |
110 | int ip6_count; | |
111 | int ipx_count; | |
112 | int ns_count; | |
113 | int any_count; | |
114 | } route_cb; | |
115 | ||
590b8cd4 | 116 | static const struct sockaddr route_src = { 2, PF_ROUTE, }; |
984263bc MD |
117 | |
118 | struct walkarg { | |
119 | int w_tmemsize; | |
120 | int w_op, w_arg; | |
8e63efec | 121 | void *w_tmem; |
984263bc MD |
122 | struct sysctl_req *w_req; |
123 | }; | |
124 | ||
125 | static struct mbuf * | |
590b8cd4 JH |
126 | rt_msg_mbuf (int, struct rt_addrinfo *); |
127 | static void rt_msg_buffer (int, struct rt_addrinfo *, void *buf, int len); | |
128 | static int rt_msgsize (int type, struct rt_addrinfo *rtinfo); | |
ef87f48d | 129 | static int rt_xaddrs (char *, char *, struct rt_addrinfo *); |
158abb01 RG |
130 | static int sysctl_dumpentry (struct radix_node *rn, void *vw); |
131 | static int sysctl_iflist (int af, struct walkarg *w); | |
deffea2e | 132 | static int route_output(struct mbuf *, struct socket *, ...); |
47e78ae8 | 133 | static void rt_setmetrics (u_long, struct rt_metrics *, |
f23061d4 | 134 | struct rt_metrics *); |
984263bc | 135 | |
984263bc MD |
136 | /* |
137 | * It really doesn't make any sense at all for this code to share much | |
138 | * with raw_usrreq.c, since its functionality is so restricted. XXX | |
139 | */ | |
140 | static int | |
141 | rts_abort(struct socket *so) | |
142 | { | |
143 | int s, error; | |
f23061d4 | 144 | |
984263bc MD |
145 | s = splnet(); |
146 | error = raw_usrreqs.pru_abort(so); | |
147 | splx(s); | |
148 | return error; | |
149 | } | |
150 | ||
151 | /* pru_accept is EOPNOTSUPP */ | |
152 | ||
153 | static int | |
e4700d00 | 154 | rts_attach(struct socket *so, int proto, struct pru_attach_info *ai) |
984263bc MD |
155 | { |
156 | struct rawcb *rp; | |
157 | int s, error; | |
158 | ||
ef87f48d | 159 | if (sotorawcb(so) != NULL) |
984263bc | 160 | return EISCONN; /* XXX panic? */ |
f23061d4 | 161 | |
590b8cd4 | 162 | rp = malloc(sizeof *rp, M_PCB, M_WAITOK | M_ZERO); |
ef87f48d | 163 | if (rp == NULL) |
984263bc MD |
164 | return ENOBUFS; |
165 | ||
166 | /* | |
167 | * The splnet() is necessary to block protocols from sending | |
168 | * error notifications (like RTM_REDIRECT or RTM_LOSING) while | |
169 | * this PCB is extant but incompletely initialized. | |
170 | * Probably we should try to do more of this work beforehand and | |
171 | * eliminate the spl. | |
172 | */ | |
173 | s = splnet(); | |
ef87f48d | 174 | so->so_pcb = rp; |
e4700d00 | 175 | error = raw_attach(so, proto, ai->sb_rlimit); |
984263bc MD |
176 | rp = sotorawcb(so); |
177 | if (error) { | |
178 | splx(s); | |
179 | free(rp, M_PCB); | |
180 | return error; | |
181 | } | |
182 | switch(rp->rcb_proto.sp_protocol) { | |
183 | case AF_INET: | |
184 | route_cb.ip_count++; | |
185 | break; | |
186 | case AF_INET6: | |
187 | route_cb.ip6_count++; | |
188 | break; | |
189 | case AF_IPX: | |
190 | route_cb.ipx_count++; | |
191 | break; | |
192 | case AF_NS: | |
193 | route_cb.ns_count++; | |
194 | break; | |
195 | } | |
196 | rp->rcb_faddr = &route_src; | |
197 | route_cb.any_count++; | |
198 | soisconnected(so); | |
199 | so->so_options |= SO_USELOOPBACK; | |
200 | splx(s); | |
201 | return 0; | |
202 | } | |
203 | ||
204 | static int | |
dadab5e9 | 205 | rts_bind(struct socket *so, struct sockaddr *nam, struct thread *td) |
984263bc MD |
206 | { |
207 | int s, error; | |
f23061d4 | 208 | |
984263bc | 209 | s = splnet(); |
dadab5e9 | 210 | error = raw_usrreqs.pru_bind(so, nam, td); /* xxx just EINVAL */ |
984263bc MD |
211 | splx(s); |
212 | return error; | |
213 | } | |
214 | ||
215 | static int | |
dadab5e9 | 216 | rts_connect(struct socket *so, struct sockaddr *nam, struct thread *td) |
984263bc MD |
217 | { |
218 | int s, error; | |
f23061d4 | 219 | |
984263bc | 220 | s = splnet(); |
dadab5e9 | 221 | error = raw_usrreqs.pru_connect(so, nam, td); /* XXX just EINVAL */ |
984263bc MD |
222 | splx(s); |
223 | return error; | |
224 | } | |
225 | ||
226 | /* pru_connect2 is EOPNOTSUPP */ | |
227 | /* pru_control is EOPNOTSUPP */ | |
228 | ||
229 | static int | |
230 | rts_detach(struct socket *so) | |
231 | { | |
232 | struct rawcb *rp = sotorawcb(so); | |
233 | int s, error; | |
234 | ||
235 | s = splnet(); | |
ef87f48d | 236 | if (rp != NULL) { |
984263bc MD |
237 | switch(rp->rcb_proto.sp_protocol) { |
238 | case AF_INET: | |
239 | route_cb.ip_count--; | |
240 | break; | |
241 | case AF_INET6: | |
242 | route_cb.ip6_count--; | |
243 | break; | |
244 | case AF_IPX: | |
245 | route_cb.ipx_count--; | |
246 | break; | |
247 | case AF_NS: | |
248 | route_cb.ns_count--; | |
249 | break; | |
250 | } | |
251 | route_cb.any_count--; | |
252 | } | |
253 | error = raw_usrreqs.pru_detach(so); | |
254 | splx(s); | |
255 | return error; | |
256 | } | |
257 | ||
258 | static int | |
259 | rts_disconnect(struct socket *so) | |
260 | { | |
261 | int s, error; | |
f23061d4 | 262 | |
984263bc MD |
263 | s = splnet(); |
264 | error = raw_usrreqs.pru_disconnect(so); | |
265 | splx(s); | |
266 | return error; | |
267 | } | |
268 | ||
269 | /* pru_listen is EOPNOTSUPP */ | |
270 | ||
271 | static int | |
272 | rts_peeraddr(struct socket *so, struct sockaddr **nam) | |
273 | { | |
274 | int s, error; | |
f23061d4 | 275 | |
984263bc MD |
276 | s = splnet(); |
277 | error = raw_usrreqs.pru_peeraddr(so, nam); | |
278 | splx(s); | |
279 | return error; | |
280 | } | |
281 | ||
282 | /* pru_rcvd is EOPNOTSUPP */ | |
283 | /* pru_rcvoob is EOPNOTSUPP */ | |
284 | ||
285 | static int | |
286 | rts_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, | |
dadab5e9 | 287 | struct mbuf *control, struct thread *td) |
984263bc MD |
288 | { |
289 | int s, error; | |
f23061d4 | 290 | |
984263bc | 291 | s = splnet(); |
dadab5e9 | 292 | error = raw_usrreqs.pru_send(so, flags, m, nam, control, td); |
984263bc MD |
293 | splx(s); |
294 | return error; | |
295 | } | |
296 | ||
297 | /* pru_sense is null */ | |
298 | ||
299 | static int | |
300 | rts_shutdown(struct socket *so) | |
301 | { | |
302 | int s, error; | |
f23061d4 | 303 | |
984263bc MD |
304 | s = splnet(); |
305 | error = raw_usrreqs.pru_shutdown(so); | |
306 | splx(s); | |
307 | return error; | |
308 | } | |
309 | ||
310 | static int | |
311 | rts_sockaddr(struct socket *so, struct sockaddr **nam) | |
312 | { | |
313 | int s, error; | |
f23061d4 | 314 | |
984263bc MD |
315 | s = splnet(); |
316 | error = raw_usrreqs.pru_sockaddr(so, nam); | |
317 | splx(s); | |
318 | return error; | |
319 | } | |
320 | ||
321 | static struct pr_usrreqs route_usrreqs = { | |
322 | rts_abort, pru_accept_notsupp, rts_attach, rts_bind, rts_connect, | |
323 | pru_connect2_notsupp, pru_control_notsupp, rts_detach, rts_disconnect, | |
324 | pru_listen_notsupp, rts_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp, | |
325 | rts_send, pru_sense_null, rts_shutdown, rts_sockaddr, | |
326 | sosend, soreceive, sopoll | |
327 | }; | |
328 | ||
590b8cd4 JH |
329 | static __inline sa_family_t |
330 | familyof(struct sockaddr *sa) | |
331 | { | |
332 | return (sa != NULL ? sa->sa_family : 0); | |
333 | } | |
334 | ||
335 | static void | |
336 | rts_input(struct mbuf *m, sa_family_t family) | |
337 | { | |
338 | static const struct sockaddr route_dst = { 2, PF_ROUTE, }; | |
339 | struct sockproto route_proto = { PF_ROUTE, family }; | |
340 | ||
341 | raw_input(m, &route_proto, &route_src, &route_dst); | |
342 | } | |
343 | ||
344 | static void * | |
345 | reallocbuf(void *ptr, size_t len, size_t olen) | |
346 | { | |
347 | void *newptr; | |
348 | ||
349 | newptr = malloc(len, M_RTABLE, M_INTWAIT | M_NULLOK); | |
350 | if (newptr == NULL) | |
351 | return NULL; | |
352 | bcopy(ptr, newptr, olen); | |
353 | free(ptr, M_RTABLE); | |
354 | return (newptr); | |
355 | } | |
356 | ||
8e63efec JH |
357 | /* |
358 | * Internal helper routine for route_output(). | |
359 | */ | |
590b8cd4 JH |
360 | static int |
361 | fillrtmsg(struct rt_msghdr **prtm, struct rtentry *rt, | |
362 | struct rt_addrinfo *rtinfo) | |
363 | { | |
364 | int msglen; | |
365 | struct rt_msghdr *rtm = *prtm; | |
366 | ||
367 | /* Fill in rt_addrinfo for call to rt_msg_buffer(). */ | |
368 | rtinfo->rti_dst = rt_key(rt); | |
369 | rtinfo->rti_gateway = rt->rt_gateway; | |
370 | rtinfo->rti_netmask = rt_mask(rt); /* might be NULL */ | |
371 | rtinfo->rti_genmask = rt->rt_genmask; /* might be NULL */ | |
372 | if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { | |
373 | if (rt->rt_ifp != NULL) { | |
374 | rtinfo->rti_ifpaddr = | |
375 | TAILQ_FIRST(&rt->rt_ifp->if_addrhead)->ifa_addr; | |
376 | rtinfo->rti_ifaaddr = rt->rt_ifa->ifa_addr; | |
377 | if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) | |
378 | rtinfo->rti_bcastaddr = rt->rt_ifa->ifa_dstaddr; | |
379 | rtm->rtm_index = rt->rt_ifp->if_index; | |
380 | } else { | |
381 | rtinfo->rti_ifpaddr = NULL; | |
382 | rtinfo->rti_ifaaddr = NULL; | |
383 | } | |
384 | } | |
385 | ||
386 | msglen = rt_msgsize(rtm->rtm_type, rtinfo); | |
387 | if (rtm->rtm_msglen < msglen) { | |
388 | rtm = reallocbuf(rtm, msglen, rtm->rtm_msglen); | |
389 | if (rtm == NULL) | |
390 | return (ENOBUFS); | |
391 | *prtm = rtm; | |
392 | } | |
393 | rt_msg_buffer(rtm->rtm_type, rtinfo, rtm, msglen); | |
394 | ||
395 | rtm->rtm_flags = rt->rt_flags; | |
396 | rtm->rtm_rmx = rt->rt_rmx; | |
397 | rtm->rtm_addrs = rtinfo->rti_addrs; | |
398 | ||
399 | return (0); | |
400 | } | |
401 | ||
984263bc MD |
402 | /*ARGSUSED*/ |
403 | static int | |
deffea2e | 404 | route_output(struct mbuf *m, struct socket *so, ...) |
984263bc | 405 | { |
2e9572df JH |
406 | struct rt_msghdr *rtm = NULL; |
407 | struct rtentry *rt = NULL; | |
408 | struct rtentry *saved_nrt = NULL; | |
984263bc | 409 | struct radix_node_head *rnh; |
2e9572df | 410 | struct ifaddr *ifa = NULL; |
f23061d4 | 411 | struct rawcb *rp = NULL; |
deffea2e | 412 | struct pr_output_info *oi; |
590b8cd4 | 413 | struct rt_addrinfo rtinfo; |
ef87f48d | 414 | int len, error = 0; |
deffea2e JS |
415 | __va_list ap; |
416 | ||
417 | __va_start(ap, so); | |
418 | oi = __va_arg(ap, struct pr_output_info *); | |
419 | __va_end(ap); | |
984263bc | 420 | |
ef87f48d | 421 | #define gotoerr(e) { error = e; goto flush;} |
590b8cd4 JH |
422 | |
423 | if (m == NULL || | |
424 | (m->m_len < sizeof(long) && | |
425 | (m = m_pullup(m, sizeof(long))) == NULL)) | |
984263bc | 426 | return (ENOBUFS); |
ef87f48d | 427 | if (!(m->m_flags & M_PKTHDR)) |
984263bc MD |
428 | panic("route_output"); |
429 | len = m->m_pkthdr.len; | |
590b8cd4 | 430 | if (len < sizeof(struct rt_msghdr) || |
984263bc | 431 | len != mtod(m, struct rt_msghdr *)->rtm_msglen) { |
590b8cd4 | 432 | rtinfo.rti_dst = NULL; |
ef87f48d | 433 | gotoerr(EINVAL); |
984263bc | 434 | } |
590b8cd4 | 435 | rtm = malloc(len, M_RTABLE, M_INTWAIT | M_NULLOK); |
ef87f48d | 436 | if (rtm == NULL) { |
590b8cd4 | 437 | rtinfo.rti_dst = NULL; |
ef87f48d | 438 | gotoerr(ENOBUFS); |
984263bc MD |
439 | } |
440 | m_copydata(m, 0, len, (caddr_t)rtm); | |
441 | if (rtm->rtm_version != RTM_VERSION) { | |
590b8cd4 | 442 | rtinfo.rti_dst = NULL; |
ef87f48d | 443 | gotoerr(EPROTONOSUPPORT); |
984263bc | 444 | } |
47e78ae8 | 445 | rtm->rtm_pid = oi->p_pid; |
590b8cd4 JH |
446 | bzero(&rtinfo, sizeof(struct rt_addrinfo)); |
447 | rtinfo.rti_addrs = rtm->rtm_addrs; | |
448 | if (rt_xaddrs((char *)(rtm + 1), (char *)rtm + len, &rtinfo) != 0) { | |
449 | rtinfo.rti_dst = NULL; | |
ef87f48d | 450 | gotoerr(EINVAL); |
984263bc | 451 | } |
590b8cd4 JH |
452 | rtinfo.rti_flags = rtm->rtm_flags; |
453 | if (rtinfo.rti_dst == NULL || rtinfo.rti_dst->sa_family >= AF_MAX || | |
454 | (rtinfo.rti_gateway && rtinfo.rti_gateway->sa_family >= AF_MAX)) | |
ef87f48d JH |
455 | gotoerr(EINVAL); |
456 | ||
590b8cd4 JH |
457 | if (rtinfo.rti_genmask != NULL) { |
458 | struct radix_node *n; | |
ef87f48d | 459 | |
590b8cd4 JH |
460 | #define clen(s) (*(u_char *)(s)) |
461 | n = rn_addmask((char *)rtinfo.rti_genmask, TRUE, 1); | |
462 | if (n != NULL && | |
463 | rtinfo.rti_genmask->sa_len >= clen(n->rn_key) && | |
464 | bcmp((char *)rtinfo.rti_genmask + 1, | |
465 | (char *)n->rn_key + 1, clen(n->rn_key) - 1) == 0) | |
466 | rtinfo.rti_genmask = (struct sockaddr *)n->rn_key; | |
984263bc | 467 | else |
ef87f48d | 468 | gotoerr(ENOBUFS); |
984263bc MD |
469 | } |
470 | ||
471 | /* | |
472 | * Verify that the caller has the appropriate privilege; RTM_GET | |
473 | * is the only operation the non-superuser is allowed. | |
474 | */ | |
dadab5e9 | 475 | if (rtm->rtm_type != RTM_GET && suser_cred(so->so_cred, 0) != 0) |
ef87f48d | 476 | gotoerr(EPERM); |
984263bc MD |
477 | |
478 | switch (rtm->rtm_type) { | |
984263bc | 479 | case RTM_ADD: |
590b8cd4 | 480 | if (rtinfo.rti_gateway == NULL) |
ef87f48d | 481 | gotoerr(EINVAL); |
590b8cd4 | 482 | error = rtrequest1(RTM_ADD, &rtinfo, &saved_nrt); |
ef87f48d | 483 | if (error == 0 && saved_nrt != NULL) { |
590b8cd4 JH |
484 | rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, |
485 | &saved_nrt->rt_rmx); | |
984263bc MD |
486 | saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); |
487 | saved_nrt->rt_rmx.rmx_locks |= | |
590b8cd4 JH |
488 | (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); |
489 | --saved_nrt->rt_refcnt; | |
490 | saved_nrt->rt_genmask = rtinfo.rti_genmask; | |
984263bc MD |
491 | } |
492 | break; | |
984263bc | 493 | case RTM_DELETE: |
590b8cd4 | 494 | error = rtrequest1(RTM_DELETE, &rtinfo, &saved_nrt); |
984263bc MD |
495 | if (error == 0) { |
496 | if ((rt = saved_nrt)) | |
497 | rt->rt_refcnt++; | |
590b8cd4 JH |
498 | if (fillrtmsg(&rtm, rt, &rtinfo) != 0) |
499 | gotoerr(ENOBUFS); | |
984263bc MD |
500 | } |
501 | break; | |
984263bc MD |
502 | case RTM_GET: |
503 | case RTM_CHANGE: | |
504 | case RTM_LOCK: | |
590b8cd4 | 505 | if ((rnh = rt_tables[rtinfo.rti_dst->sa_family]) == NULL) |
ef87f48d | 506 | gotoerr(EAFNOSUPPORT); |
590b8cd4 JH |
507 | rt = (struct rtentry *) |
508 | rnh->rnh_lookup((char *)rtinfo.rti_dst, | |
509 | (char *)rtinfo.rti_netmask, rnh); | |
510 | if (rt == NULL) | |
ef87f48d | 511 | gotoerr(ESRCH); |
590b8cd4 | 512 | rt->rt_refcnt++; |
984263bc | 513 | |
590b8cd4 | 514 | switch(rtm->rtm_type) { |
984263bc | 515 | case RTM_GET: |
590b8cd4 JH |
516 | if (fillrtmsg(&rtm, rt, &rtinfo) != 0) |
517 | gotoerr(ENOBUFS); | |
984263bc | 518 | break; |
984263bc | 519 | case RTM_CHANGE: |
ef87f48d JH |
520 | /* |
521 | * new gateway could require new ifaddr, ifp; | |
522 | * flags may also be different; ifp may be specified | |
523 | * by ll sockaddr when protocol address is ambiguous | |
524 | */ | |
525 | if (((rt->rt_flags & RTF_GATEWAY) && | |
590b8cd4 JH |
526 | rtinfo.rti_gateway != NULL) || |
527 | rtinfo.rti_ifpaddr != NULL || | |
528 | (rtinfo.rti_ifaaddr != NULL && | |
529 | sa_equal(rtinfo.rti_ifaaddr, | |
530 | rt->rt_ifa->ifa_addr))) { | |
531 | error = rt_getifa(&rtinfo); | |
532 | if (error != 0) | |
ef87f48d | 533 | gotoerr(error); |
984263bc | 534 | } |
590b8cd4 JH |
535 | if (rtinfo.rti_gateway != NULL) { |
536 | error = rt_setgate(rt, rt_key(rt), | |
537 | rtinfo.rti_gateway); | |
538 | if (error != 0) | |
539 | gotoerr(error); | |
540 | } | |
541 | if ((ifa = rtinfo.rti_ifa) != NULL) { | |
82ed7fc2 | 542 | struct ifaddr *oifa = rt->rt_ifa; |
ef87f48d | 543 | |
984263bc | 544 | if (oifa != ifa) { |
f23061d4 JH |
545 | if (oifa && oifa->ifa_rtrequest) |
546 | oifa->ifa_rtrequest(RTM_DELETE, | |
590b8cd4 | 547 | rt, &rtinfo); |
f23061d4 | 548 | IFAFREE(rt->rt_ifa); |
f23061d4 | 549 | IFAREF(ifa); |
590b8cd4 JH |
550 | rt->rt_ifa = ifa; |
551 | rt->rt_ifp = rtinfo.rti_ifp; | |
984263bc MD |
552 | } |
553 | } | |
554 | rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, | |
590b8cd4 | 555 | &rt->rt_rmx); |
984263bc | 556 | if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) |
590b8cd4 JH |
557 | rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &rtinfo); |
558 | if (rtinfo.rti_genmask != NULL) | |
559 | rt->rt_genmask = rtinfo.rti_genmask; | |
984263bc MD |
560 | /* |
561 | * Fall into | |
562 | */ | |
563 | case RTM_LOCK: | |
564 | rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); | |
565 | rt->rt_rmx.rmx_locks |= | |
566 | (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); | |
567 | break; | |
568 | } | |
984263bc | 569 | |
590b8cd4 | 570 | break; |
984263bc | 571 | default: |
ef87f48d | 572 | gotoerr(EOPNOTSUPP); |
984263bc MD |
573 | } |
574 | ||
575 | flush: | |
590b8cd4 JH |
576 | if (rtm != NULL) { |
577 | if (error != 0) | |
984263bc MD |
578 | rtm->rtm_errno = error; |
579 | else | |
580 | rtm->rtm_flags |= RTF_DONE; | |
581 | } | |
590b8cd4 | 582 | if (rt != NULL) |
984263bc | 583 | rtfree(rt); |
984263bc MD |
584 | /* |
585 | * Check to see if we don't want our own messages. | |
586 | */ | |
ef87f48d | 587 | if (!(so->so_options & SO_USELOOPBACK)) { |
984263bc | 588 | if (route_cb.any_count <= 1) { |
590b8cd4 JH |
589 | if (rtm != NULL) |
590 | free(rtm, M_RTABLE); | |
984263bc MD |
591 | m_freem(m); |
592 | return (error); | |
593 | } | |
594 | /* There is another listener, so construct message */ | |
595 | rp = sotorawcb(so); | |
596 | } | |
590b8cd4 | 597 | if (rtm != NULL) { |
984263bc MD |
598 | m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); |
599 | if (m->m_pkthdr.len < rtm->rtm_msglen) { | |
600 | m_freem(m); | |
601 | m = NULL; | |
602 | } else if (m->m_pkthdr.len > rtm->rtm_msglen) | |
603 | m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); | |
590b8cd4 | 604 | free(rtm, M_RTABLE); |
984263bc | 605 | } |
ef87f48d | 606 | if (rp != NULL) |
984263bc | 607 | rp->rcb_proto.sp_family = 0; /* Avoid us */ |
ef87f48d | 608 | if (m != NULL) |
590b8cd4 | 609 | rts_input(m, familyof(rtinfo.rti_dst)); |
ef87f48d | 610 | if (rp != NULL) |
984263bc | 611 | rp->rcb_proto.sp_family = PF_ROUTE; |
984263bc MD |
612 | return (error); |
613 | } | |
614 | ||
615 | static void | |
ef87f48d | 616 | rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_metrics *out) |
984263bc | 617 | { |
2e9572df JH |
618 | #define setmetric(flag, elt) if (which & (flag)) out->elt = in->elt; |
619 | setmetric(RTV_RPIPE, rmx_recvpipe); | |
620 | setmetric(RTV_SPIPE, rmx_sendpipe); | |
621 | setmetric(RTV_SSTHRESH, rmx_ssthresh); | |
622 | setmetric(RTV_RTT, rmx_rtt); | |
623 | setmetric(RTV_RTTVAR, rmx_rttvar); | |
624 | setmetric(RTV_HOPCOUNT, rmx_hopcount); | |
625 | setmetric(RTV_MTU, rmx_mtu); | |
626 | setmetric(RTV_EXPIRE, rmx_expire); | |
627 | #undef setmetric | |
984263bc MD |
628 | } |
629 | ||
630 | #define ROUNDUP(a) \ | |
631 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) | |
984263bc | 632 | |
984263bc MD |
633 | /* |
634 | * Extract the addresses of the passed sockaddrs. | |
635 | * Do a little sanity checking so as to avoid bad memory references. | |
636 | * This data is derived straight from userland. | |
637 | */ | |
638 | static int | |
ef87f48d | 639 | rt_xaddrs(char *cp, char *cplim, struct rt_addrinfo *rtinfo) |
984263bc | 640 | { |
82ed7fc2 RG |
641 | struct sockaddr *sa; |
642 | int i; | |
984263bc MD |
643 | |
644 | for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { | |
645 | if ((rtinfo->rti_addrs & (1 << i)) == 0) | |
646 | continue; | |
647 | sa = (struct sockaddr *)cp; | |
648 | /* | |
649 | * It won't fit. | |
650 | */ | |
0c3c561c | 651 | if ((cp + sa->sa_len) > cplim) { |
984263bc MD |
652 | return (EINVAL); |
653 | } | |
654 | ||
655 | /* | |
ef87f48d | 656 | * There are no more... Quit now. |
984263bc | 657 | * If there are more bits, they are in error. |
ef87f48d | 658 | * I've seen this. route(1) can evidently generate these. |
984263bc | 659 | * This causes kernel to core dump. |
ef87f48d | 660 | * For compatibility, if we see this, point to a safe address. |
984263bc MD |
661 | */ |
662 | if (sa->sa_len == 0) { | |
590b8cd4 JH |
663 | static struct sockaddr sa_zero = { |
664 | sizeof sa_zero, AF_INET, | |
665 | }; | |
666 | ||
984263bc MD |
667 | rtinfo->rti_info[i] = &sa_zero; |
668 | return (0); /* should be EINVAL but for compat */ | |
669 | } | |
670 | ||
ef87f48d | 671 | /* Accept the sockaddr. */ |
984263bc | 672 | rtinfo->rti_info[i] = sa; |
590b8cd4 | 673 | cp += ROUNDUP(sa->sa_len); |
984263bc MD |
674 | } |
675 | return (0); | |
676 | } | |
677 | ||
590b8cd4 JH |
678 | static int |
679 | rt_msghdrsize(int type) | |
984263bc | 680 | { |
984263bc | 681 | switch (type) { |
984263bc MD |
682 | case RTM_DELADDR: |
683 | case RTM_NEWADDR: | |
590b8cd4 | 684 | return sizeof(struct ifa_msghdr); |
984263bc MD |
685 | case RTM_DELMADDR: |
686 | case RTM_NEWMADDR: | |
590b8cd4 | 687 | return sizeof(struct ifma_msghdr); |
984263bc | 688 | case RTM_IFINFO: |
590b8cd4 | 689 | return sizeof(struct if_msghdr); |
984263bc | 690 | case RTM_IFANNOUNCE: |
590b8cd4 | 691 | return sizeof(struct if_announcemsghdr); |
984263bc | 692 | default: |
590b8cd4 | 693 | return sizeof(struct rt_msghdr); |
984263bc | 694 | } |
590b8cd4 JH |
695 | } |
696 | ||
697 | static int | |
698 | rt_msgsize(int type, struct rt_addrinfo *rtinfo) | |
699 | { | |
700 | int len, i; | |
701 | ||
702 | len = rt_msghdrsize(type); | |
703 | for (i = 0; i < RTAX_MAX; i++) { | |
704 | if (rtinfo->rti_info[i] != NULL) | |
705 | len += ROUNDUP(rtinfo->rti_info[i]->sa_len); | |
984263bc | 706 | } |
590b8cd4 JH |
707 | len = ALIGN(len); |
708 | return len; | |
709 | } | |
710 | ||
711 | /* | |
712 | * Build a routing message in a buffer. | |
713 | * Copy the addresses in the rtinfo->rti_info[] sockaddr array | |
714 | * to the end of the buffer after the message header. | |
715 | * | |
716 | * Set the rtinfo->rti_addrs bitmask of addresses present in rtinfo->rti_info[]. | |
717 | * This side-effect can be avoided if we reorder the addrs bitmask field in all | |
718 | * the route messages to line up so we can set it here instead of back in the | |
719 | * calling routine. | |
720 | */ | |
721 | static void | |
722 | rt_msg_buffer(int type, struct rt_addrinfo *rtinfo, void *buf, int msglen) | |
723 | { | |
724 | struct rt_msghdr *rtm; | |
725 | char *cp; | |
726 | int dlen, i; | |
727 | ||
728 | rtm = (struct rt_msghdr *) buf; | |
729 | rtm->rtm_version = RTM_VERSION; | |
730 | rtm->rtm_type = type; | |
731 | rtm->rtm_msglen = msglen; | |
732 | ||
733 | cp = (char *)buf + rt_msghdrsize(type); | |
734 | rtinfo->rti_addrs = 0; | |
984263bc | 735 | for (i = 0; i < RTAX_MAX; i++) { |
590b8cd4 JH |
736 | struct sockaddr *sa; |
737 | ||
984263bc MD |
738 | if ((sa = rtinfo->rti_info[i]) == NULL) |
739 | continue; | |
740 | rtinfo->rti_addrs |= (1 << i); | |
741 | dlen = ROUNDUP(sa->sa_len); | |
590b8cd4 JH |
742 | bcopy(sa, cp, dlen); |
743 | cp += dlen; | |
984263bc | 744 | } |
984263bc MD |
745 | } |
746 | ||
590b8cd4 JH |
747 | /* |
748 | * Build a routing message in a mbuf chain. | |
749 | * Copy the addresses in the rtinfo->rti_info[] sockaddr array | |
750 | * to the end of the mbuf after the message header. | |
751 | * | |
752 | * Set the rtinfo->rti_addrs bitmask of addresses present in rtinfo->rti_info[]. | |
753 | * This side-effect can be avoided if we reorder the addrs bitmask field in all | |
754 | * the route messages to line up so we can set it here instead of back in the | |
755 | * calling routine. | |
756 | */ | |
757 | static struct mbuf * | |
758 | rt_msg_mbuf(int type, struct rt_addrinfo *rtinfo) | |
984263bc | 759 | { |
590b8cd4 JH |
760 | struct mbuf *m; |
761 | struct rt_msghdr *rtm; | |
762 | int hlen, len; | |
82ed7fc2 | 763 | int i; |
984263bc | 764 | |
590b8cd4 JH |
765 | hlen = rt_msghdrsize(type); |
766 | KASSERT(hlen <= MCLBYTES, ("rt_msg_mbuf: hlen %d doesn't fit", hlen)); | |
984263bc | 767 | |
590b8cd4 JH |
768 | m = m_gethdr(MB_DONTWAIT, MT_DATA); |
769 | if (m == NULL) | |
770 | return (NULL); | |
771 | if (hlen > MHLEN) { | |
772 | MCLGET(m, MB_DONTWAIT); | |
773 | if (!(m->m_flags & M_EXT)) { | |
774 | m_free(m); | |
775 | return (NULL); | |
776 | } | |
984263bc | 777 | } |
590b8cd4 JH |
778 | m->m_pkthdr.len = m->m_len = hlen; |
779 | m->m_pkthdr.rcvif = NULL; | |
780 | rtinfo->rti_addrs = 0; | |
781 | len = hlen; | |
984263bc | 782 | for (i = 0; i < RTAX_MAX; i++) { |
82ed7fc2 | 783 | struct sockaddr *sa; |
590b8cd4 | 784 | int dlen; |
984263bc | 785 | |
ef87f48d | 786 | if ((sa = rtinfo->rti_info[i]) == NULL) |
984263bc MD |
787 | continue; |
788 | rtinfo->rti_addrs |= (1 << i); | |
789 | dlen = ROUNDUP(sa->sa_len); | |
590b8cd4 | 790 | m_copyback(m, len, dlen, (caddr_t)sa); /* can grow mbuf chain */ |
984263bc MD |
791 | len += dlen; |
792 | } | |
590b8cd4 JH |
793 | if (m->m_pkthdr.len != len) { /* one of the m_copyback() calls failed */ |
794 | m_freem(m); | |
795 | return (NULL); | |
984263bc | 796 | } |
590b8cd4 JH |
797 | rtm = mtod(m, struct rt_msghdr *); |
798 | bzero(rtm, hlen); | |
799 | rtm->rtm_msglen = len; | |
800 | rtm->rtm_version = RTM_VERSION; | |
801 | rtm->rtm_type = type; | |
802 | return (m); | |
984263bc MD |
803 | } |
804 | ||
805 | /* | |
806 | * This routine is called to generate a message from the routing | |
f23061d4 | 807 | * socket indicating that a redirect has occurred, a routing lookup |
984263bc MD |
808 | * has failed, or that a protocol has detected timeouts to a particular |
809 | * destination. | |
810 | */ | |
811 | void | |
f23061d4 | 812 | rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error) |
984263bc | 813 | { |
0c3c561c | 814 | struct sockaddr *dst = rtinfo->rti_info[RTAX_DST]; |
82ed7fc2 RG |
815 | struct rt_msghdr *rtm; |
816 | struct mbuf *m; | |
984263bc MD |
817 | |
818 | if (route_cb.any_count == 0) | |
819 | return; | |
590b8cd4 | 820 | m = rt_msg_mbuf(type, rtinfo); |
ef87f48d | 821 | if (m == NULL) |
984263bc MD |
822 | return; |
823 | rtm = mtod(m, struct rt_msghdr *); | |
824 | rtm->rtm_flags = RTF_DONE | flags; | |
825 | rtm->rtm_errno = error; | |
826 | rtm->rtm_addrs = rtinfo->rti_addrs; | |
590b8cd4 | 827 | rts_input(m, familyof(dst)); |
984263bc MD |
828 | } |
829 | ||
f3ed2586 JH |
830 | void |
831 | rt_dstmsg(int type, struct sockaddr *dst, int error) | |
832 | { | |
833 | struct rt_msghdr *rtm; | |
834 | struct rt_addrinfo addrs; | |
835 | struct mbuf *m; | |
836 | ||
837 | if (route_cb.any_count == 0) | |
838 | return; | |
839 | bzero(&addrs, sizeof(struct rt_addrinfo)); | |
840 | addrs.rti_info[RTAX_DST] = dst; | |
590b8cd4 | 841 | m = rt_msg_mbuf(type, &addrs); |
f3ed2586 JH |
842 | if (m == NULL) |
843 | return; | |
844 | rtm = mtod(m, struct rt_msghdr *); | |
845 | rtm->rtm_flags = RTF_DONE; | |
846 | rtm->rtm_errno = error; | |
847 | rtm->rtm_addrs = addrs.rti_addrs; | |
590b8cd4 | 848 | rts_input(m, familyof(dst)); |
f3ed2586 JH |
849 | } |
850 | ||
984263bc MD |
851 | /* |
852 | * This routine is called to generate a message from the routing | |
853 | * socket indicating that the status of a network interface has changed. | |
854 | */ | |
855 | void | |
0c3c561c | 856 | rt_ifmsg(struct ifnet *ifp) |
984263bc | 857 | { |
82ed7fc2 | 858 | struct if_msghdr *ifm; |
984263bc | 859 | struct mbuf *m; |
590b8cd4 | 860 | struct rt_addrinfo rtinfo; |
984263bc MD |
861 | |
862 | if (route_cb.any_count == 0) | |
863 | return; | |
590b8cd4 JH |
864 | bzero(&rtinfo, sizeof(struct rt_addrinfo)); |
865 | m = rt_msg_mbuf(RTM_IFINFO, &rtinfo); | |
ef87f48d | 866 | if (m == NULL) |
984263bc MD |
867 | return; |
868 | ifm = mtod(m, struct if_msghdr *); | |
869 | ifm->ifm_index = ifp->if_index; | |
870 | ifm->ifm_flags = (u_short)ifp->if_flags; | |
871 | ifm->ifm_data = ifp->if_data; | |
590b8cd4 JH |
872 | ifm->ifm_addrs = 0; |
873 | rts_input(m, 0); | |
984263bc MD |
874 | } |
875 | ||
372316d9 JH |
876 | static void |
877 | rt_ifamsg(int cmd, struct ifaddr *ifa) | |
878 | { | |
879 | struct ifa_msghdr *ifam; | |
590b8cd4 | 880 | struct rt_addrinfo rtinfo; |
372316d9 | 881 | struct mbuf *m; |
372316d9 JH |
882 | struct ifnet *ifp = ifa->ifa_ifp; |
883 | ||
590b8cd4 JH |
884 | bzero(&rtinfo, sizeof(struct rt_addrinfo)); |
885 | rtinfo.rti_ifaaddr = ifa->ifa_addr; | |
886 | rtinfo.rti_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr; | |
887 | rtinfo.rti_netmask = ifa->ifa_netmask; | |
888 | rtinfo.rti_bcastaddr = ifa->ifa_dstaddr; | |
f23061d4 | 889 | |
590b8cd4 | 890 | m = rt_msg_mbuf(cmd, &rtinfo); |
f23061d4 | 891 | if (m == NULL) |
372316d9 | 892 | return; |
f23061d4 | 893 | |
372316d9 JH |
894 | ifam = mtod(m, struct ifa_msghdr *); |
895 | ifam->ifam_index = ifp->if_index; | |
896 | ifam->ifam_metric = ifa->ifa_metric; | |
897 | ifam->ifam_flags = ifa->ifa_flags; | |
590b8cd4 | 898 | ifam->ifam_addrs = rtinfo.rti_addrs; |
f23061d4 | 899 | |
590b8cd4 | 900 | rts_input(m, familyof(ifa->ifa_addr)); |
372316d9 JH |
901 | } |
902 | ||
f3ed2586 JH |
903 | void |
904 | rt_rtmsg(int cmd, struct rtentry *rt, struct ifnet *ifp, int error) | |
372316d9 JH |
905 | { |
906 | struct rt_msghdr *rtm; | |
590b8cd4 | 907 | struct rt_addrinfo rtinfo; |
372316d9 | 908 | struct mbuf *m; |
f3ed2586 | 909 | struct sockaddr *dst; |
372316d9 JH |
910 | |
911 | if (rt == NULL) | |
912 | return; | |
f23061d4 | 913 | |
590b8cd4 JH |
914 | bzero(&rtinfo, sizeof(struct rt_addrinfo)); |
915 | rtinfo.rti_dst = dst = rt_key(rt); | |
916 | rtinfo.rti_gateway = rt->rt_gateway; | |
917 | rtinfo.rti_netmask = rt_mask(rt); | |
f3ed2586 | 918 | if (ifp != NULL) |
590b8cd4 JH |
919 | rtinfo.rti_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr; |
920 | rtinfo.rti_ifaaddr = rt->rt_ifa->ifa_addr; | |
f23061d4 | 921 | |
590b8cd4 | 922 | m = rt_msg_mbuf(cmd, &rtinfo); |
f23061d4 | 923 | if (m == NULL) |
372316d9 | 924 | return; |
f23061d4 | 925 | |
372316d9 | 926 | rtm = mtod(m, struct rt_msghdr *); |
f3ed2586 JH |
927 | if (ifp != NULL) |
928 | rtm->rtm_index = ifp->if_index; | |
372316d9 JH |
929 | rtm->rtm_flags |= rt->rt_flags; |
930 | rtm->rtm_errno = error; | |
590b8cd4 | 931 | rtm->rtm_addrs = rtinfo.rti_addrs; |
f23061d4 | 932 | |
590b8cd4 | 933 | rts_input(m, familyof(dst)); |
372316d9 JH |
934 | } |
935 | ||
984263bc MD |
936 | /* |
937 | * This is called to generate messages from the routing socket | |
938 | * indicating a network interface has had addresses associated with it. | |
939 | * if we ever reverse the logic and replace messages TO the routing | |
940 | * socket indicate a request to configure interfaces, then it will | |
941 | * be unnecessary as the routing socket will automatically generate | |
942 | * copies of it. | |
943 | */ | |
944 | void | |
0c3c561c | 945 | rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt) |
984263bc | 946 | { |
984263bc MD |
947 | if (route_cb.any_count == 0) |
948 | return; | |
984263bc | 949 | |
372316d9 JH |
950 | if (cmd == RTM_ADD) { |
951 | rt_ifamsg(RTM_NEWADDR, ifa); | |
f3ed2586 | 952 | rt_rtmsg(RTM_ADD, rt, ifa->ifa_ifp, error); |
372316d9 JH |
953 | } else { |
954 | KASSERT((cmd == RTM_DELETE), ("unknown cmd %d", cmd)); | |
f3ed2586 | 955 | rt_rtmsg(RTM_DELETE, rt, ifa->ifa_ifp, error); |
372316d9 | 956 | rt_ifamsg(RTM_DELADDR, ifa); |
984263bc MD |
957 | } |
958 | } | |
959 | ||
960 | /* | |
961 | * This is the analogue to the rt_newaddrmsg which performs the same | |
962 | * function but for multicast group memberhips. This is easier since | |
963 | * there is no route state to worry about. | |
964 | */ | |
965 | void | |
0c3c561c | 966 | rt_newmaddrmsg(int cmd, struct ifmultiaddr *ifma) |
984263bc | 967 | { |
590b8cd4 | 968 | struct rt_addrinfo rtinfo; |
ef87f48d | 969 | struct mbuf *m = NULL; |
984263bc MD |
970 | struct ifnet *ifp = ifma->ifma_ifp; |
971 | struct ifma_msghdr *ifmam; | |
972 | ||
973 | if (route_cb.any_count == 0) | |
974 | return; | |
975 | ||
590b8cd4 JH |
976 | bzero(&rtinfo, sizeof(struct rt_addrinfo)); |
977 | rtinfo.rti_ifaaddr = ifma->ifma_addr; | |
5480c2a2 | 978 | if (ifp != NULL && TAILQ_FIRST(&ifp->if_addrhead) != NULL) |
590b8cd4 | 979 | rtinfo.rti_ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr; |
984263bc | 980 | else |
590b8cd4 | 981 | rtinfo.rti_ifpaddr = NULL; |
984263bc MD |
982 | /* |
983 | * If a link-layer address is present, present it as a ``gateway'' | |
984 | * (similarly to how ARP entries, e.g., are presented). | |
985 | */ | |
590b8cd4 | 986 | rtinfo.rti_gateway = ifma->ifma_lladdr; |
f23061d4 | 987 | |
590b8cd4 | 988 | m = rt_msg_mbuf(cmd, &rtinfo); |
f23061d4 | 989 | if (m == NULL) |
984263bc | 990 | return; |
f23061d4 | 991 | |
984263bc MD |
992 | ifmam = mtod(m, struct ifma_msghdr *); |
993 | ifmam->ifmam_index = ifp->if_index; | |
590b8cd4 | 994 | ifmam->ifmam_addrs = rtinfo.rti_addrs; |
f23061d4 | 995 | |
590b8cd4 | 996 | rts_input(m, familyof(ifma->ifma_addr)); |
984263bc MD |
997 | } |
998 | ||
999 | /* | |
1000 | * This is called to generate routing socket messages indicating | |
1001 | * network interface arrival and departure. | |
1002 | */ | |
1003 | void | |
590b8cd4 | 1004 | rt_ifannouncemsg(struct ifnet *ifp, int what) |
984263bc | 1005 | { |
590b8cd4 | 1006 | struct rt_addrinfo addrinfo; |
984263bc | 1007 | struct mbuf *m; |
590b8cd4 | 1008 | struct if_announcemsghdr *ifan; |
984263bc MD |
1009 | |
1010 | if (route_cb.any_count == 0) | |
1011 | return; | |
f23061d4 | 1012 | |
590b8cd4 JH |
1013 | bzero(&addrinfo, sizeof addrinfo); |
1014 | m = rt_msg_mbuf(RTM_IFANNOUNCE, &addrinfo); | |
984263bc MD |
1015 | if (m == NULL) |
1016 | return; | |
f23061d4 | 1017 | |
984263bc MD |
1018 | ifan = mtod(m, struct if_announcemsghdr *); |
1019 | ifan->ifan_index = ifp->if_index; | |
5fe66e68 | 1020 | strlcpy(ifan->ifan_name, ifp->if_xname, sizeof ifan->ifan_name); |
984263bc | 1021 | ifan->ifan_what = what; |
f23061d4 | 1022 | |
590b8cd4 JH |
1023 | rts_input(m, 0); |
1024 | } | |
f23061d4 | 1025 | |
590b8cd4 JH |
1026 | static int |
1027 | resizewalkarg(struct walkarg *w, int len) | |
1028 | { | |
1029 | void *newptr; | |
1030 | ||
1031 | newptr = malloc(len, M_RTABLE, M_INTWAIT | M_NULLOK); | |
1032 | if (newptr == NULL) | |
1033 | return (ENOMEM); | |
1034 | if (w->w_tmem != NULL) | |
1035 | free(w->w_tmem, M_RTABLE); | |
1036 | w->w_tmem = newptr; | |
1037 | w->w_tmemsize = len; | |
1038 | return (0); | |
1039 | } | |
984263bc MD |
1040 | |
1041 | /* | |
1042 | * This is used in dumping the kernel table via sysctl(). | |
1043 | */ | |
1044 | int | |
590b8cd4 | 1045 | sysctl_dumpentry(struct radix_node *rn, void *vw) |
984263bc | 1046 | { |
82ed7fc2 RG |
1047 | struct walkarg *w = vw; |
1048 | struct rtentry *rt = (struct rtentry *)rn; | |
590b8cd4 JH |
1049 | struct rt_addrinfo rtinfo; |
1050 | int error, msglen; | |
984263bc MD |
1051 | |
1052 | if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) | |
1053 | return 0; | |
f23061d4 | 1054 | |
590b8cd4 JH |
1055 | bzero(&rtinfo, sizeof(struct rt_addrinfo)); |
1056 | rtinfo.rti_dst = rt_key(rt); | |
1057 | rtinfo.rti_gateway = rt->rt_gateway; | |
1058 | rtinfo.rti_netmask = rt_mask(rt); | |
1059 | rtinfo.rti_genmask = rt->rt_genmask; | |
ef87f48d | 1060 | if (rt->rt_ifp != NULL) { |
590b8cd4 | 1061 | rtinfo.rti_ifpaddr = |
ef87f48d | 1062 | TAILQ_FIRST(&rt->rt_ifp->if_addrhead)->ifa_addr; |
590b8cd4 | 1063 | rtinfo.rti_ifaaddr = rt->rt_ifa->ifa_addr; |
984263bc | 1064 | if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) |
590b8cd4 | 1065 | rtinfo.rti_bcastaddr = rt->rt_ifa->ifa_dstaddr; |
984263bc | 1066 | } |
590b8cd4 JH |
1067 | msglen = rt_msgsize(RTM_GET, &rtinfo); |
1068 | if (w->w_tmemsize < msglen && resizewalkarg(w, msglen) != 0) | |
1069 | return (ENOMEM); | |
1070 | rt_msg_buffer(RTM_GET, &rtinfo, w->w_tmem, msglen); | |
1071 | if (w->w_req != NULL) { | |
8e63efec | 1072 | struct rt_msghdr *rtm = w->w_tmem; |
984263bc MD |
1073 | |
1074 | rtm->rtm_flags = rt->rt_flags; | |
1075 | rtm->rtm_use = rt->rt_use; | |
1076 | rtm->rtm_rmx = rt->rt_rmx; | |
1077 | rtm->rtm_index = rt->rt_ifp->if_index; | |
1078 | rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; | |
590b8cd4 JH |
1079 | rtm->rtm_addrs = rtinfo.rti_addrs; |
1080 | error = SYSCTL_OUT(w->w_req, rtm, msglen); | |
984263bc MD |
1081 | return (error); |
1082 | } | |
590b8cd4 | 1083 | return (0); |
984263bc MD |
1084 | } |
1085 | ||
590b8cd4 JH |
1086 | static int |
1087 | sysctl_iflist(int af, struct walkarg *w) | |
984263bc | 1088 | { |
82ed7fc2 RG |
1089 | struct ifnet *ifp; |
1090 | struct ifaddr *ifa; | |
590b8cd4 JH |
1091 | struct rt_addrinfo rtinfo; |
1092 | int msglen, error; | |
984263bc | 1093 | |
590b8cd4 | 1094 | bzero(&rtinfo, sizeof(struct rt_addrinfo)); |
984263bc MD |
1095 | TAILQ_FOREACH(ifp, &ifnet, if_link) { |
1096 | if (w->w_arg && w->w_arg != ifp->if_index) | |
1097 | continue; | |
1098 | ifa = TAILQ_FIRST(&ifp->if_addrhead); | |
590b8cd4 JH |
1099 | rtinfo.rti_ifpaddr = ifa->ifa_addr; |
1100 | msglen = rt_msgsize(RTM_IFINFO, &rtinfo); | |
1101 | if (w->w_tmemsize < msglen && resizewalkarg(w, msglen) != 0) | |
1102 | return (ENOMEM); | |
1103 | rt_msg_buffer(RTM_IFINFO, &rtinfo, w->w_tmem, msglen); | |
1104 | rtinfo.rti_ifpaddr = NULL; | |
ef87f48d | 1105 | if (w->w_req != NULL && w->w_tmem != NULL) { |
8e63efec | 1106 | struct if_msghdr *ifm = w->w_tmem; |
984263bc | 1107 | |
984263bc MD |
1108 | ifm->ifm_index = ifp->if_index; |
1109 | ifm->ifm_flags = (u_short)ifp->if_flags; | |
1110 | ifm->ifm_data = ifp->if_data; | |
590b8cd4 JH |
1111 | ifm->ifm_addrs = rtinfo.rti_addrs; |
1112 | error = SYSCTL_OUT(w->w_req, ifm, msglen); | |
984263bc MD |
1113 | if (error) |
1114 | return (error); | |
1115 | } | |
ef87f48d | 1116 | while ((ifa = TAILQ_NEXT(ifa, ifa_link)) != NULL) { |
984263bc MD |
1117 | if (af && af != ifa->ifa_addr->sa_family) |
1118 | continue; | |
590b8cd4 JH |
1119 | if (curproc->p_ucred->cr_prison && |
1120 | prison_if(curthread, ifa->ifa_addr)) | |
984263bc | 1121 | continue; |
590b8cd4 JH |
1122 | rtinfo.rti_ifaaddr = ifa->ifa_addr; |
1123 | rtinfo.rti_netmask = ifa->ifa_netmask; | |
1124 | rtinfo.rti_bcastaddr = ifa->ifa_dstaddr; | |
1125 | msglen = rt_msgsize(RTM_NEWADDR, &rtinfo); | |
1126 | if (w->w_tmemsize < msglen && | |
1127 | resizewalkarg(w, msglen) != 0) | |
1128 | return (ENOMEM); | |
1129 | rt_msg_buffer(RTM_NEWADDR, &rtinfo, w->w_tmem, msglen); | |
1130 | if (w->w_req != NULL) { | |
8e63efec | 1131 | struct ifa_msghdr *ifam = w->w_tmem; |
984263bc | 1132 | |
984263bc MD |
1133 | ifam->ifam_index = ifa->ifa_ifp->if_index; |
1134 | ifam->ifam_flags = ifa->ifa_flags; | |
1135 | ifam->ifam_metric = ifa->ifa_metric; | |
590b8cd4 JH |
1136 | ifam->ifam_addrs = rtinfo.rti_addrs; |
1137 | error = SYSCTL_OUT(w->w_req, w->w_tmem, msglen); | |
984263bc MD |
1138 | if (error) |
1139 | return (error); | |
1140 | } | |
1141 | } | |
590b8cd4 JH |
1142 | rtinfo.rti_netmask = NULL; |
1143 | rtinfo.rti_ifaaddr = NULL; | |
1144 | rtinfo.rti_bcastaddr = NULL; | |
984263bc MD |
1145 | } |
1146 | return (0); | |
1147 | } | |
1148 | ||
1149 | static int | |
1150 | sysctl_rtsock(SYSCTL_HANDLER_ARGS) | |
1151 | { | |
1152 | int *name = (int *)arg1; | |
1153 | u_int namelen = arg2; | |
82ed7fc2 | 1154 | struct radix_node_head *rnh; |
984263bc MD |
1155 | int i, s, error = EINVAL; |
1156 | u_char af; | |
1157 | struct walkarg w; | |
1158 | ||
1159 | name ++; | |
1160 | namelen--; | |
1161 | if (req->newptr) | |
1162 | return (EPERM); | |
1163 | if (namelen != 3) | |
1164 | return (EINVAL); | |
1165 | af = name[0]; | |
5fe66e68 | 1166 | bzero(&w, sizeof w); |
984263bc MD |
1167 | w.w_op = name[1]; |
1168 | w.w_arg = name[2]; | |
1169 | w.w_req = req; | |
1170 | ||
1171 | s = splnet(); | |
1172 | switch (w.w_op) { | |
1173 | ||
1174 | case NET_RT_DUMP: | |
1175 | case NET_RT_FLAGS: | |
1176 | for (i = 1; i <= AF_MAX; i++) | |
1177 | if ((rnh = rt_tables[i]) && (af == 0 || af == i) && | |
1178 | (error = rnh->rnh_walktree(rnh, | |
f23061d4 | 1179 | sysctl_dumpentry, &w))) |
984263bc MD |
1180 | break; |
1181 | break; | |
1182 | ||
1183 | case NET_RT_IFLIST: | |
1184 | error = sysctl_iflist(af, &w); | |
1185 | } | |
1186 | splx(s); | |
590b8cd4 | 1187 | if (w.w_tmem != NULL) |
984263bc MD |
1188 | free(w.w_tmem, M_RTABLE); |
1189 | return (error); | |
1190 | } | |
1191 | ||
1192 | SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, ""); | |
1193 | ||
1194 | /* | |
1195 | * Definitions of protocols supported in the ROUTE domain. | |
1196 | */ | |
1197 | ||
1198 | extern struct domain routedomain; /* or at least forward */ | |
1199 | ||
1200 | static struct protosw routesw[] = { | |
1201 | { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR, | |
1202 | 0, route_output, raw_ctlinput, 0, | |
9eeaa8a9 | 1203 | cpu0_soport, |
984263bc MD |
1204 | raw_init, 0, 0, 0, |
1205 | &route_usrreqs | |
1206 | } | |
1207 | }; | |
1208 | ||
9c70fe43 JH |
1209 | static struct domain routedomain = { |
1210 | PF_ROUTE, "route", NULL, NULL, NULL, | |
1211 | routesw, &routesw[(sizeof routesw)/(sizeof routesw[0])], | |
1212 | }; | |
984263bc MD |
1213 | |
1214 | DOMAIN_SET(route); |