1 /* $OpenBSD: rtsock.c,v 1.48 2005/06/08 06:43:07 henning Exp $ */
2 /* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */
3
4 /*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 /*
34 * Copyright (c) 1988, 1991, 1993
35 * The Regents of the University of California. All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 * @(#)rtsock.c 8.6 (Berkeley) 2/11/95
62 */
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/proc.h>
67 #include <sys/mbuf.h>
68 #include <sys/socket.h>
69 #include <sys/socketvar.h>
70 #include <sys/domain.h>
71 #include <sys/protosw.h>
72
73 #include <uvm/uvm_extern.h>
74 #include <sys/sysctl.h>
75
76 #include <net/if.h>
77 #include <net/route.h>
78 #include <net/raw_cb.h>
79
80 #include <sys/stdarg.h>
81
82 struct sockaddr route_dst = { 2, PF_ROUTE, };
83 struct sockaddr route_src = { 2, PF_ROUTE, };
84 struct sockproto route_proto = { PF_ROUTE, };
85
86 struct walkarg {
87 int w_op, w_arg, w_given, w_needed, w_tmemsize;
88 caddr_t w_where, w_tmem;
89 };
90
91 static struct mbuf
92 *rt_msg1(int, struct rt_addrinfo *);
93 static int rt_msg2(int, struct rt_addrinfo *, caddr_t, struct walkarg *);
94 static void rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
95
96 /* Sleazy use of local variables throughout file, warning!!!! */
97 #define dst info.rti_info[RTAX_DST]
98 #define gate info.rti_info[RTAX_GATEWAY]
99 #define netmask info.rti_info[RTAX_NETMASK]
100 #define genmask info.rti_info[RTAX_GENMASK]
101 #define ifpaddr info.rti_info[RTAX_IFP]
102 #define ifaaddr info.rti_info[RTAX_IFA]
103 #define brdaddr info.rti_info[RTAX_BRD]
104
105 int
route_usrreq(struct socket * so,int req,struct mbuf * m,struct mbuf * nam,struct mbuf * control)106 route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
107 struct mbuf *control)
108 {
109 int error = 0;
110 struct rawcb *rp = sotorawcb(so);
111 int s;
112
113 if (req == PRU_ATTACH) {
114 MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
115 so->so_pcb = rp;
116 bzero(so->so_pcb, sizeof(*rp));
117 }
118 if (req == PRU_DETACH && rp) {
119 int af = rp->rcb_proto.sp_protocol;
120 if (af == AF_INET)
121 route_cb.ip_count--;
122 else if (af == AF_INET6)
123 route_cb.ip6_count--;
124 route_cb.any_count--;
125 }
126 s = splsoftnet();
127 /*
128 * Don't call raw_usrreq() in the attach case, because
129 * we want to allow non-privileged processes to listen on
130 * and send "safe" commands to the routing socket.
131 */
132 if (req == PRU_ATTACH) {
133 if (curproc == 0)
134 error = EACCES;
135 else
136 error = raw_attach(so, (int)(long)nam);
137 } else
138 error = raw_usrreq(so, req, m, nam, control);
139
140 rp = sotorawcb(so);
141 if (req == PRU_ATTACH && rp) {
142 int af = rp->rcb_proto.sp_protocol;
143 if (error) {
144 free(rp, M_PCB);
145 splx(s);
146 return (error);
147 }
148 if (af == AF_INET)
149 route_cb.ip_count++;
150 else if (af == AF_INET6)
151 route_cb.ip6_count++;
152 rp->rcb_faddr = &route_src;
153 route_cb.any_count++;
154 soisconnected(so);
155 so->so_options |= SO_USELOOPBACK;
156 }
157 splx(s);
158 return (error);
159 }
160
161 int
route_output(struct mbuf * m,...)162 route_output(struct mbuf *m, ...)
163 {
164 struct rt_msghdr *rtm = NULL;
165 struct radix_node *rn = NULL;
166 struct rtentry *rt = NULL;
167 struct rtentry *saved_nrt = NULL;
168 struct radix_node_head *rnh;
169 struct rt_addrinfo info;
170 int len, error = 0;
171 struct ifnet *ifp = NULL;
172 struct ifaddr *ifa = NULL;
173 struct socket *so;
174 struct rawcb *rp = NULL;
175 struct sockaddr_rtlabel sa_rt;
176 const char *label;
177 va_list ap;
178
179 va_start(ap, m);
180 so = va_arg(ap, struct socket *);
181 va_end(ap);
182
183 if (m == 0 || ((m->m_len < sizeof(int32_t)) &&
184 (m = m_pullup(m, sizeof(int32_t))) == 0))
185 return (ENOBUFS);
186 if ((m->m_flags & M_PKTHDR) == 0)
187 panic("route_output");
188 len = m->m_pkthdr.len;
189 if (len < sizeof(*rtm) ||
190 len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
191 dst = 0;
192 error = EINVAL;
193 goto flush;
194 }
195 R_Malloc(rtm, struct rt_msghdr *, len);
196 if (rtm == 0) {
197 dst = 0;
198 error = ENOBUFS;
199 goto flush;
200 }
201 m_copydata(m, 0, len, (caddr_t)rtm);
202 if (rtm->rtm_version != RTM_VERSION) {
203 dst = 0;
204 error = EPROTONOSUPPORT;
205 goto flush;
206 }
207 rtm->rtm_pid = curproc->p_pid;
208
209 bzero(&info, sizeof(info));
210 info.rti_addrs = rtm->rtm_addrs;
211 rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info);
212 info.rti_flags = rtm->rtm_flags;
213 if (dst == 0 || dst->sa_family >= AF_MAX ||
214 (gate != 0 && gate->sa_family >= AF_MAX)) {
215 error = EINVAL;
216 goto flush;
217 }
218 if (genmask) {
219 struct radix_node *t;
220 t = rn_addmask(genmask, 0, 1);
221 if (t && genmask->sa_len >=
222 ((struct sockaddr *)t->rn_key)->sa_len &&
223 Bcmp((caddr_t *)genmask + 1, (caddr_t *)t->rn_key + 1,
224 ((struct sockaddr *)t->rn_key)->sa_len) - 1)
225 genmask = (struct sockaddr *)(t->rn_key);
226 else {
227 error = ENOBUFS;
228 goto flush;
229 }
230 }
231
232 /*
233 * Verify that the caller has the appropriate privilege; RTM_GET
234 * is the only operation the non-superuser is allowed.
235 */
236 if (rtm->rtm_type != RTM_GET && suser(curproc, 0) != 0) {
237 error = EACCES;
238 goto flush;
239 }
240
241 switch (rtm->rtm_type) {
242 case RTM_ADD:
243 if (gate == 0) {
244 error = EINVAL;
245 goto flush;
246 }
247 error = rtrequest1(rtm->rtm_type, &info, &saved_nrt);
248 if (error == 0 && saved_nrt) {
249 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
250 &saved_nrt->rt_rmx);
251 saved_nrt->rt_refcnt--;
252 saved_nrt->rt_genmask = genmask;
253 }
254 break;
255 case RTM_DELETE:
256 error = rtrequest1(rtm->rtm_type, &info, &saved_nrt);
257 if (error == 0) {
258 (rt = saved_nrt)->rt_refcnt++;
259 goto report;
260 }
261 break;
262 case RTM_GET:
263 case RTM_CHANGE:
264 case RTM_LOCK:
265 if ((rnh = rt_tables[dst->sa_family]) == 0) {
266 error = EAFNOSUPPORT;
267 goto flush;
268 }
269 rn = rnh->rnh_lookup(dst, netmask, rnh);
270 if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) {
271 error = ESRCH;
272 goto flush;
273 }
274 rt = (struct rtentry *)rn;
275 #ifndef SMALL_KERNEL
276 /*
277 * for RTM_CHANGE/LOCK, if we got multipath routes,
278 * we require users to specify a matching RTAX_GATEWAY.
279 *
280 * for RTM_GET, gate is optional even with multipath.
281 * if gate == NULL the first match is returned.
282 * (no need to call rt_mpath_matchgate if gate == NULL)
283 */
284 if (rn_mpath_capable(rnh) &&
285 (rtm->rtm_type != RTM_GET || gate)) {
286 rt = rt_mpath_matchgate(rt, gate);
287 rn = (struct radix_node *)rt;
288 if (!rt) {
289 error = ESRCH;
290 goto flush;
291 }
292 }
293 #endif
294 rt->rt_refcnt++;
295
296 /*
297 * RTM_CHANGE/LOCK need a perfect match, rn_lookup()
298 * returns a perfect match in case a netmask is specified.
299 * For host routes only a longest prefix match is returned
300 * so it is necessary to compare the existence of the netmaks.
301 * If both have a netmask rn_lookup() did a perfect match and
302 * if non of them have a netmask both are host routes which is
303 * also a perfect match.
304 */
305 if (rtm->rtm_type != RTM_GET && !rt_mask(rt) != !netmask) {
306 error = ESRCH;
307 goto flush;
308 }
309
310 switch (rtm->rtm_type) {
311 case RTM_GET:
312 report:
313 dst = rt_key(rt);
314 gate = rt->rt_gateway;
315 netmask = rt_mask(rt);
316 genmask = rt->rt_genmask;
317
318 if (rt->rt_labelid) {
319 bzero(&sa_rt, sizeof(sa_rt));
320 sa_rt.sr_len = sizeof(sa_rt);
321 label = rtlabel_id2name(rt->rt_labelid);
322 if (label != NULL)
323 strlcpy(sa_rt.sr_label, label,
324 sizeof(sa_rt.sr_label));
325 info.rti_info[RTAX_LABEL] =
326 (struct sockaddr *)&sa_rt;
327 }
328
329 ifpaddr = 0;
330 ifaaddr = 0;
331 if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA) &&
332 (ifp = rt->rt_ifp) != NULL) {
333 ifpaddr =
334 TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
335 ifaaddr = rt->rt_ifa->ifa_addr;
336 if (ifp->if_flags & IFF_POINTOPOINT)
337 brdaddr = rt->rt_ifa->ifa_dstaddr;
338 else
339 brdaddr = 0;
340 rtm->rtm_index = ifp->if_index;
341 }
342 len = rt_msg2(rtm->rtm_type, &info, NULL, NULL);
343 if (len > rtm->rtm_msglen) {
344 struct rt_msghdr *new_rtm;
345 R_Malloc(new_rtm, struct rt_msghdr *, len);
346 if (new_rtm == 0) {
347 error = ENOBUFS;
348 goto flush;
349 }
350 Bcopy(rtm, new_rtm, rtm->rtm_msglen);
351 Free(rtm); rtm = new_rtm;
352 }
353 rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, NULL);
354 rtm->rtm_flags = rt->rt_flags;
355 rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
356 rtm->rtm_addrs = info.rti_addrs;
357 break;
358
359 case RTM_CHANGE:
360 /*
361 * new gateway could require new ifaddr, ifp;
362 * flags may also be different; ifp may be specified
363 * by ll sockaddr when protocol address is ambiguous
364 */
365 if ((error = rt_getifa(&info)) != 0)
366 goto flush;
367 if (gate && rt_setgate(rt, rt_key(rt), gate)) {
368 error = EDQUOT;
369 goto flush;
370 }
371 if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&
372 (ifp = ifa->ifa_ifp) && (ifaaddr || gate))
373 ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
374 ifp);
375 else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||
376 (gate && (ifa = ifa_ifwithroute(rt->rt_flags,
377 rt_key(rt), gate))))
378 ifp = ifa->ifa_ifp;
379 if (ifa) {
380 struct ifaddr *oifa = rt->rt_ifa;
381 if (oifa != ifa) {
382 if (oifa && oifa->ifa_rtrequest)
383 oifa->ifa_rtrequest(RTM_DELETE, rt,
384 &info);
385 IFAFREE(rt->rt_ifa);
386 rt->rt_ifa = ifa;
387 ifa->ifa_refcnt++;
388 rt->rt_ifp = ifp;
389 }
390 }
391
392 /* XXX Hack to allow the jumbo flag to be toggled */
393 if (rtm->rtm_use & RTF_JUMBO)
394 rt->rt_flags = (rt->rt_flags &
395 ~rtm->rtm_fmask) |
396 (rtm->rtm_flags & rtm->rtm_fmask);
397
398 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
399 &rt->rt_rmx);
400 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
401 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info);
402 if (genmask)
403 rt->rt_genmask = genmask;
404 if (info.rti_info[RTAX_LABEL] != NULL) {
405 char *rtlabel = ((struct sockaddr_rtlabel *)
406 info.rti_info[RTAX_LABEL])->sr_label;
407 rtlabel_unref(rt->rt_labelid);
408 rt->rt_labelid =
409 rtlabel_name2id(rtlabel);
410 }
411 /* fallthrough */
412 case RTM_LOCK:
413 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
414 rt->rt_rmx.rmx_locks |=
415 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
416 break;
417 }
418 break;
419
420 default:
421 error = EOPNOTSUPP;
422 break;
423 }
424
425 flush:
426 if (rtm) {
427 if (error)
428 rtm->rtm_errno = error;
429 else
430 rtm->rtm_flags |= RTF_DONE;
431 }
432 if (rt)
433 rtfree(rt);
434
435 /*
436 * Check to see if we don't want our own messages.
437 */
438 if (!(so->so_options & SO_USELOOPBACK)) {
439 if (route_cb.any_count <= 1) {
440 if (rtm)
441 Free(rtm);
442 m_freem(m);
443 return (error);
444 }
445 /* There is another listener, so construct message */
446 rp = sotorawcb(so);
447 }
448 if (rp)
449 rp->rcb_proto.sp_family = 0; /* Avoid us */
450 if (dst)
451 route_proto.sp_protocol = dst->sa_family;
452 if (rtm) {
453 m_copyback(m, 0, rtm->rtm_msglen, rtm);
454 if (m->m_pkthdr.len < rtm->rtm_msglen) {
455 m_freem(m);
456 m = NULL;
457 } else if (m->m_pkthdr.len > rtm->rtm_msglen)
458 m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
459 Free(rtm);
460 }
461 if (m)
462 raw_input(m, &route_proto, &route_src, &route_dst);
463 if (rp)
464 rp->rcb_proto.sp_family = PF_ROUTE;
465
466 return (error);
467 }
468
469 void
rt_setmetrics(u_long which,struct rt_metrics * in,struct rt_kmetrics * out)470 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_kmetrics *out)
471 {
472 if (which & RTV_MTU)
473 out->rmx_mtu = in->rmx_mtu;
474 if (which & RTV_EXPIRE)
475 out->rmx_expire = in->rmx_expire;
476 }
477
478 void
rt_getmetrics(struct rt_kmetrics * in,struct rt_metrics * out)479 rt_getmetrics(struct rt_kmetrics *in, struct rt_metrics *out)
480 {
481 bzero(out, sizeof(*out));
482 out->rmx_locks = in->rmx_locks;
483 out->rmx_mtu = in->rmx_mtu;
484 out->rmx_expire = in->rmx_expire;
485 out->rmx_pksent = in->rmx_pksent;
486 }
487
488 #define ROUNDUP(a) \
489 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
490 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
491
492 static void
rt_xaddrs(caddr_t cp,caddr_t cplim,struct rt_addrinfo * rtinfo)493 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
494 {
495 struct sockaddr *sa;
496 int i;
497
498 bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
499 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
500 if ((rtinfo->rti_addrs & (1 << i)) == 0)
501 continue;
502 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
503 ADVANCE(cp, sa);
504 }
505 }
506
507 static struct mbuf *
rt_msg1(int type,struct rt_addrinfo * rtinfo)508 rt_msg1(int type, struct rt_addrinfo *rtinfo)
509 {
510 struct rt_msghdr *rtm;
511 struct mbuf *m;
512 int i;
513 struct sockaddr *sa;
514 int len, dlen;
515
516 switch (type) {
517 case RTM_DELADDR:
518 case RTM_NEWADDR:
519 len = sizeof(struct ifa_msghdr);
520 break;
521 case RTM_IFINFO:
522 len = sizeof(struct if_msghdr);
523 break;
524 case RTM_IFANNOUNCE:
525 len = sizeof(struct if_announcemsghdr);
526 break;
527 default:
528 len = sizeof(struct rt_msghdr);
529 break;
530 }
531 if (len > MCLBYTES)
532 panic("rt_msg1");
533 m = m_gethdr(M_DONTWAIT, MT_DATA);
534 if (m && len > MHLEN) {
535 MCLGET(m, M_DONTWAIT);
536 if ((m->m_flags & M_EXT) == 0) {
537 m_free(m);
538 m = NULL;
539 }
540 }
541 if (m == 0)
542 return (m);
543 m->m_pkthdr.len = m->m_len = len;
544 m->m_pkthdr.rcvif = NULL;
545 rtm = mtod(m, struct rt_msghdr *);
546 bzero(rtm, len);
547 for (i = 0; i < RTAX_MAX; i++) {
548 if ((sa = rtinfo->rti_info[i]) == NULL)
549 continue;
550 rtinfo->rti_addrs |= (1 << i);
551 dlen = ROUNDUP(sa->sa_len);
552 m_copyback(m, len, dlen, sa);
553 len += dlen;
554 }
555 if (m->m_pkthdr.len != len) {
556 m_freem(m);
557 return (NULL);
558 }
559 rtm->rtm_msglen = len;
560 rtm->rtm_version = RTM_VERSION;
561 rtm->rtm_type = type;
562 return (m);
563 }
564
565 static int
rt_msg2(int type,struct rt_addrinfo * rtinfo,caddr_t cp,struct walkarg * w)566 rt_msg2(int type, struct rt_addrinfo *rtinfo, caddr_t cp, struct walkarg *w)
567 {
568 int i;
569 int len, dlen, second_time = 0;
570 caddr_t cp0;
571
572 rtinfo->rti_addrs = 0;
573 again:
574 switch (type) {
575 case RTM_DELADDR:
576 case RTM_NEWADDR:
577 len = sizeof(struct ifa_msghdr);
578 break;
579 case RTM_IFINFO:
580 len = sizeof(struct if_msghdr);
581 break;
582 default:
583 len = sizeof(struct rt_msghdr);
584 break;
585 }
586 if ((cp0 = cp) != NULL)
587 cp += len;
588 for (i = 0; i < RTAX_MAX; i++) {
589 struct sockaddr *sa;
590
591 if ((sa = rtinfo->rti_info[i]) == 0)
592 continue;
593 rtinfo->rti_addrs |= (1 << i);
594 dlen = ROUNDUP(sa->sa_len);
595 if (cp) {
596 bcopy(sa, cp, (size_t)dlen);
597 cp += dlen;
598 }
599 len += dlen;
600 }
601 if (cp == 0 && w != NULL && !second_time) {
602 struct walkarg *rw = w;
603
604 rw->w_needed += len;
605 if (rw->w_needed <= 0 && rw->w_where) {
606 if (rw->w_tmemsize < len) {
607 if (rw->w_tmem)
608 free(rw->w_tmem, M_RTABLE);
609 rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT);
610 if (rw->w_tmem)
611 rw->w_tmemsize = len;
612 }
613 if (rw->w_tmem) {
614 cp = rw->w_tmem;
615 second_time = 1;
616 goto again;
617 } else
618 rw->w_where = 0;
619 }
620 }
621 if (cp) {
622 struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
623
624 rtm->rtm_version = RTM_VERSION;
625 rtm->rtm_type = type;
626 rtm->rtm_msglen = len;
627 }
628 return (len);
629 }
630
631 /*
632 * This routine is called to generate a message from the routing
633 * socket indicating that a redirect has occurred, a routing lookup
634 * has failed, or that a protocol has detected timeouts to a particular
635 * destination.
636 */
637 void
rt_missmsg(int type,struct rt_addrinfo * rtinfo,int flags,int error)638 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error)
639 {
640 struct rt_msghdr *rtm;
641 struct mbuf *m;
642 struct sockaddr *sa = rtinfo->rti_info[RTAX_DST];
643
644 if (route_cb.any_count == 0)
645 return;
646 m = rt_msg1(type, rtinfo);
647 if (m == 0)
648 return;
649 rtm = mtod(m, struct rt_msghdr *);
650 rtm->rtm_flags = RTF_DONE | flags;
651 rtm->rtm_errno = error;
652 rtm->rtm_addrs = rtinfo->rti_addrs;
653 if (sa == NULL)
654 route_proto.sp_protocol = 0;
655 else
656 route_proto.sp_protocol = sa->sa_family;
657 raw_input(m, &route_proto, &route_src, &route_dst);
658 }
659
660 /*
661 * This routine is called to generate a message from the routing
662 * socket indicating that the status of a network interface has changed.
663 */
664 void
rt_ifmsg(struct ifnet * ifp)665 rt_ifmsg(struct ifnet *ifp)
666 {
667 struct if_msghdr *ifm;
668 struct mbuf *m;
669 struct rt_addrinfo info;
670
671 if (route_cb.any_count == 0)
672 return;
673 bzero(&info, sizeof(info));
674 m = rt_msg1(RTM_IFINFO, &info);
675 if (m == 0)
676 return;
677 ifm = mtod(m, struct if_msghdr *);
678 ifm->ifm_index = ifp->if_index;
679 ifm->ifm_flags = ifp->if_flags;
680 ifm->ifm_data = ifp->if_data;
681 ifm->ifm_addrs = 0;
682 route_proto.sp_protocol = 0;
683 raw_input(m, &route_proto, &route_src, &route_dst);
684 }
685
686 /*
687 * This is called to generate messages from the routing socket
688 * indicating a network interface has had addresses associated with it.
689 * if we ever reverse the logic and replace messages TO the routing
690 * socket indicate a request to configure interfaces, then it will
691 * be unnecessary as the routing socket will automatically generate
692 * copies of it.
693 */
694 void
rt_newaddrmsg(int cmd,struct ifaddr * ifa,int error,struct rtentry * rt)695 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
696 {
697 struct rt_addrinfo info;
698 struct sockaddr *sa = NULL;
699 int pass;
700 struct mbuf *m = NULL;
701 struct ifnet *ifp = ifa->ifa_ifp;
702
703 if (route_cb.any_count == 0)
704 return;
705 for (pass = 1; pass < 3; pass++) {
706 bzero(&info, sizeof(info));
707 if ((cmd == RTM_ADD && pass == 1) ||
708 (cmd == RTM_DELETE && pass == 2)) {
709 struct ifa_msghdr *ifam;
710 int ncmd;
711
712 if (cmd == RTM_ADD)
713 ncmd = RTM_NEWADDR;
714 else
715 ncmd = RTM_DELADDR;
716
717 ifaaddr = sa = ifa->ifa_addr;
718 ifpaddr = TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
719 netmask = ifa->ifa_netmask;
720 brdaddr = ifa->ifa_dstaddr;
721 if ((m = rt_msg1(ncmd, &info)) == NULL)
722 continue;
723 ifam = mtod(m, struct ifa_msghdr *);
724 ifam->ifam_index = ifp->if_index;
725 ifam->ifam_metric = ifa->ifa_metric;
726 ifam->ifam_flags = ifa->ifa_flags;
727 ifam->ifam_addrs = info.rti_addrs;
728 }
729 if ((cmd == RTM_ADD && pass == 2) ||
730 (cmd == RTM_DELETE && pass == 1)) {
731 struct rt_msghdr *rtm;
732
733 if (rt == 0)
734 continue;
735 netmask = rt_mask(rt);
736 dst = sa = rt_key(rt);
737 gate = rt->rt_gateway;
738 if ((m = rt_msg1(cmd, &info)) == NULL)
739 continue;
740 rtm = mtod(m, struct rt_msghdr *);
741 rtm->rtm_index = ifp->if_index;
742 rtm->rtm_flags |= rt->rt_flags;
743 rtm->rtm_errno = error;
744 rtm->rtm_addrs = info.rti_addrs;
745 }
746 if (sa == NULL)
747 route_proto.sp_protocol = 0;
748 else
749 route_proto.sp_protocol = sa->sa_family;
750 raw_input(m, &route_proto, &route_src, &route_dst);
751 }
752 }
753
754 /*
755 * This is called to generate routing socket messages indicating
756 * network interface arrival and departure.
757 */
758 void
rt_ifannouncemsg(struct ifnet * ifp,int what)759 rt_ifannouncemsg(struct ifnet *ifp, int what)
760 {
761 struct if_announcemsghdr *ifan;
762 struct mbuf *m;
763 struct rt_addrinfo info;
764
765 if (route_cb.any_count == 0)
766 return;
767 bzero(&info, sizeof(info));
768 m = rt_msg1(RTM_IFANNOUNCE, &info);
769 if (m == 0)
770 return;
771 ifan = mtod(m, struct if_announcemsghdr *);
772 ifan->ifan_index = ifp->if_index;
773 strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name));
774 ifan->ifan_what = what;
775 route_proto.sp_protocol = 0;
776 raw_input(m, &route_proto, &route_src, &route_dst);
777 }
778
779 /*
780 * This is used in dumping the kernel table via sysctl().
781 */
782 int
sysctl_dumpentry(struct radix_node * rn,void * v)783 sysctl_dumpentry(struct radix_node *rn, void *v)
784 {
785 struct walkarg *w = v;
786 struct rtentry *rt = (struct rtentry *)rn;
787 int error = 0, size;
788 struct rt_addrinfo info;
789
790 if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
791 return 0;
792 bzero(&info, sizeof(info));
793 dst = rt_key(rt);
794 gate = rt->rt_gateway;
795 netmask = rt_mask(rt);
796 genmask = rt->rt_genmask;
797 if (rt->rt_ifp) {
798 ifpaddr = TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
799 ifaaddr = rt->rt_ifa->ifa_addr;
800 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
801 brdaddr = rt->rt_ifa->ifa_dstaddr;
802 }
803 size = rt_msg2(RTM_GET, &info, NULL, w);
804 if (w->w_where && w->w_tmem && w->w_needed <= 0) {
805 struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
806
807 rtm->rtm_flags = rt->rt_flags;
808 rtm->rtm_use = rt->rt_use;
809 rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
810 rtm->rtm_index = rt->rt_ifp->if_index;
811 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
812 rtm->rtm_addrs = info.rti_addrs;
813 if ((error = copyout(rtm, w->w_where, size)) != 0)
814 w->w_where = NULL;
815 else
816 w->w_where += size;
817 }
818 return (error);
819 }
820
821 int
sysctl_iflist(int af,struct walkarg * w)822 sysctl_iflist(int af, struct walkarg *w)
823 {
824 struct ifnet *ifp;
825 struct ifaddr *ifa;
826 struct rt_addrinfo info;
827 int len, error = 0;
828
829 bzero(&info, sizeof(info));
830 TAILQ_FOREACH(ifp, &ifnet, if_list) {
831 if (w->w_arg && w->w_arg != ifp->if_index)
832 continue;
833 ifa = TAILQ_FIRST(&ifp->if_addrlist);
834 if (!ifa)
835 continue;
836 ifpaddr = ifa->ifa_addr;
837 len = rt_msg2(RTM_IFINFO, &info, 0, w);
838 ifpaddr = 0;
839 if (w->w_where && w->w_tmem && w->w_needed <= 0) {
840 struct if_msghdr *ifm;
841
842 ifm = (struct if_msghdr *)w->w_tmem;
843 ifm->ifm_index = ifp->if_index;
844 ifm->ifm_flags = ifp->if_flags;
845 ifm->ifm_data = ifp->if_data;
846 ifm->ifm_addrs = info.rti_addrs;
847 error = copyout(ifm, w->w_where, len);
848 if (error)
849 return (error);
850 w->w_where += len;
851 }
852 while ((ifa = TAILQ_NEXT(ifa, ifa_list)) !=
853 TAILQ_END(&ifp->if_addrlist)) {
854 if (af && af != ifa->ifa_addr->sa_family)
855 continue;
856 ifaaddr = ifa->ifa_addr;
857 netmask = ifa->ifa_netmask;
858 brdaddr = ifa->ifa_dstaddr;
859 len = rt_msg2(RTM_NEWADDR, &info, 0, w);
860 if (w->w_where && w->w_tmem && w->w_needed <= 0) {
861 struct ifa_msghdr *ifam;
862
863 ifam = (struct ifa_msghdr *)w->w_tmem;
864 ifam->ifam_index = ifa->ifa_ifp->if_index;
865 ifam->ifam_flags = ifa->ifa_flags;
866 ifam->ifam_metric = ifa->ifa_metric;
867 ifam->ifam_addrs = info.rti_addrs;
868 error = copyout(w->w_tmem, w->w_where, len);
869 if (error)
870 return (error);
871 w->w_where += len;
872 }
873 }
874 ifaaddr = netmask = brdaddr = 0;
875 }
876 return (0);
877 }
878
879 int
sysctl_rtable(int * name,u_int namelen,void * where,size_t * given,void * new,size_t newlen)880 sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new,
881 size_t newlen)
882 {
883 struct radix_node_head *rnh;
884 int i, s, error = EINVAL;
885 u_char af;
886 struct walkarg w;
887
888 if (new)
889 return (EPERM);
890 if (namelen != 3)
891 return (EINVAL);
892 af = name[0];
893 bzero(&w, sizeof(w));
894 w.w_where = where;
895 w.w_given = *given;
896 w.w_needed = 0 - w.w_given;
897 w.w_op = name[1];
898 w.w_arg = name[2];
899
900 s = splsoftnet();
901 switch (w.w_op) {
902
903 case NET_RT_DUMP:
904 case NET_RT_FLAGS:
905 for (i = 1; i <= AF_MAX; i++)
906 if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
907 (error = (*rnh->rnh_walktree)(rnh,
908 sysctl_dumpentry, &w)))
909 break;
910 break;
911
912 case NET_RT_IFLIST:
913 error = sysctl_iflist(af, &w);
914 }
915 splx(s);
916 if (w.w_tmem)
917 free(w.w_tmem, M_RTABLE);
918 w.w_needed += w.w_given;
919 if (where) {
920 *given = w.w_where - (caddr_t)where;
921 if (*given < w.w_needed)
922 return (ENOMEM);
923 } else
924 *given = (11 * w.w_needed) / 10;
925
926 return (error);
927 }
928
929 /*
930 * Definitions of protocols supported in the ROUTE domain.
931 */
932
933 extern struct domain routedomain; /* or at least forward */
934
935 struct protosw routesw[] = {
936 { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR,
937 raw_input, route_output, raw_ctlinput, 0,
938 route_usrreq,
939 raw_init, 0, 0, 0,
940 sysctl_rtable,
941 }
942 };
943
944 struct domain routedomain =
945 { PF_ROUTE, "route", route_init, 0, 0,
946 routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };
947