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