Annotation of sys/net/rtsock.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: rtsock.c,v 1.63 2007/02/14 00:53:48 jsg 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
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
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: u_int tableid;
179:
180: va_start(ap, m);
181: so = va_arg(ap, struct socket *);
182: va_end(ap);
183:
184: if (m == 0 || ((m->m_len < sizeof(int32_t)) &&
185: (m = m_pullup(m, sizeof(int32_t))) == 0))
186: return (ENOBUFS);
187: if ((m->m_flags & M_PKTHDR) == 0)
188: panic("route_output");
189: len = m->m_pkthdr.len;
190: if (len < sizeof(*rtm) ||
191: len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
192: dst = 0;
193: error = EINVAL;
194: goto flush;
195: }
196: R_Malloc(rtm, struct rt_msghdr *, len);
197: if (rtm == 0) {
198: dst = 0;
199: error = ENOBUFS;
200: goto flush;
201: }
202: m_copydata(m, 0, len, (caddr_t)rtm);
203: if (rtm->rtm_version != RTM_VERSION) {
204: dst = 0;
205: error = EPROTONOSUPPORT;
206: goto flush;
207: }
208: rtm->rtm_pid = curproc->p_pid;
209:
210: tableid = rtm->rtm_tableid;
211: if (!rtable_exists(tableid)) {
212: if (rtm->rtm_type == RTM_ADD) {
213: if (rtable_add(tableid)) {
214: error = EINVAL;
215: goto flush;
216: }
217: } else {
218: error = EINVAL;
219: goto flush;
220: }
221: }
222:
223: bzero(&info, sizeof(info));
224: info.rti_addrs = rtm->rtm_addrs;
225: rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info);
226: info.rti_flags = rtm->rtm_flags;
227: if (dst == 0 || dst->sa_family >= AF_MAX ||
228: (gate != 0 && gate->sa_family >= AF_MAX)) {
229: error = EINVAL;
230: goto flush;
231: }
232: if (genmask) {
233: struct radix_node *t;
234: t = rn_addmask(genmask, 0, 1);
235: if (t && genmask->sa_len >=
236: ((struct sockaddr *)t->rn_key)->sa_len &&
237: Bcmp((caddr_t *)genmask + 1, (caddr_t *)t->rn_key + 1,
238: ((struct sockaddr *)t->rn_key)->sa_len) - 1)
239: genmask = (struct sockaddr *)(t->rn_key);
240: else {
241: error = ENOBUFS;
242: goto flush;
243: }
244: }
245:
246: /*
247: * Verify that the caller has the appropriate privilege; RTM_GET
248: * is the only operation the non-superuser is allowed.
249: */
250: if (rtm->rtm_type != RTM_GET && suser(curproc, 0) != 0) {
251: error = EACCES;
252: goto flush;
253: }
254:
255: switch (rtm->rtm_type) {
256: case RTM_ADD:
257: if (gate == 0) {
258: error = EINVAL;
259: goto flush;
260: }
261: error = rtrequest1(rtm->rtm_type, &info, &saved_nrt, tableid);
262: if (error == 0 && saved_nrt) {
263: rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
264: &saved_nrt->rt_rmx);
265: saved_nrt->rt_refcnt--;
266: saved_nrt->rt_genmask = genmask;
267: rtm->rtm_index = saved_nrt->rt_ifp->if_index;
268: }
269: break;
270: case RTM_DELETE:
271: error = rtrequest1(rtm->rtm_type, &info, &saved_nrt, tableid);
272: if (error == 0) {
273: (rt = saved_nrt)->rt_refcnt++;
274: goto report;
275: }
276: break;
277: case RTM_GET:
278: case RTM_CHANGE:
279: case RTM_LOCK:
280: if ((rnh = rt_gettable(dst->sa_family, tableid)) == NULL) {
281: error = EAFNOSUPPORT;
282: goto flush;
283: }
284: rn = rt_lookup(dst, netmask, tableid);
285: if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) {
286: error = ESRCH;
287: goto flush;
288: }
289: rt = (struct rtentry *)rn;
290: #ifndef SMALL_KERNEL
291: /*
292: * for RTM_CHANGE/LOCK, if we got multipath routes,
293: * we require users to specify a matching RTAX_GATEWAY.
294: *
295: * for RTM_GET, gate is optional even with multipath.
296: * if gate == NULL the first match is returned.
297: * (no need to call rt_mpath_matchgate if gate == NULL)
298: */
299: if (rn_mpath_capable(rnh) &&
300: (rtm->rtm_type != RTM_GET || gate)) {
301: rt = rt_mpath_matchgate(rt, gate);
302: rn = (struct radix_node *)rt;
303: if (!rt) {
304: error = ESRCH;
305: goto flush;
306: }
307: }
308: #endif
309: rt->rt_refcnt++;
310:
311: /*
312: * RTM_CHANGE/LOCK need a perfect match, rn_lookup()
313: * returns a perfect match in case a netmask is specified.
314: * For host routes only a longest prefix match is returned
315: * so it is necessary to compare the existence of the netmaks.
316: * If both have a netmask rn_lookup() did a perfect match and
317: * if none of them have a netmask both are host routes which is
318: * also a perfect match.
319: */
320: if (rtm->rtm_type != RTM_GET && !rt_mask(rt) != !netmask) {
321: error = ESRCH;
322: goto flush;
323: }
324:
325: switch (rtm->rtm_type) {
326: case RTM_GET:
327: report:
328: dst = rt_key(rt);
329: gate = rt->rt_gateway;
330: netmask = rt_mask(rt);
331: genmask = rt->rt_genmask;
332:
333: if (rt->rt_labelid) {
334: bzero(&sa_rt, sizeof(sa_rt));
335: sa_rt.sr_len = sizeof(sa_rt);
336: label = rtlabel_id2name(rt->rt_labelid);
337: if (label != NULL)
338: strlcpy(sa_rt.sr_label, label,
339: sizeof(sa_rt.sr_label));
340: info.rti_info[RTAX_LABEL] =
341: (struct sockaddr *)&sa_rt;
342: }
343:
344: ifpaddr = 0;
345: ifaaddr = 0;
346: if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA) &&
347: (ifp = rt->rt_ifp) != NULL) {
348: ifpaddr =
349: TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
350: ifaaddr = rt->rt_ifa->ifa_addr;
351: if (ifp->if_flags & IFF_POINTOPOINT)
352: brdaddr = rt->rt_ifa->ifa_dstaddr;
353: else
354: brdaddr = 0;
355: rtm->rtm_index = ifp->if_index;
356: }
357: len = rt_msg2(rtm->rtm_type, &info, NULL, NULL);
358: if (len > rtm->rtm_msglen) {
359: struct rt_msghdr *new_rtm;
360: R_Malloc(new_rtm, struct rt_msghdr *, len);
361: if (new_rtm == 0) {
362: error = ENOBUFS;
363: goto flush;
364: }
365: Bcopy(rtm, new_rtm, rtm->rtm_msglen);
366: Free(rtm); rtm = new_rtm;
367: }
368: rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, NULL);
369: rtm->rtm_flags = rt->rt_flags;
370: rtm->rtm_use = 0;
371: rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
372: rtm->rtm_addrs = info.rti_addrs;
373: break;
374:
375: case RTM_CHANGE:
376: /*
377: * new gateway could require new ifaddr, ifp;
378: * flags may also be different; ifp may be specified
379: * by ll sockaddr when protocol address is ambiguous
380: */
381: if ((error = rt_getifa(&info)) != 0)
382: goto flush;
383: if (gate && rt_setgate(rt, rt_key(rt), gate, tableid)) {
384: error = EDQUOT;
385: goto flush;
386: }
387: if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&
388: (ifp = ifa->ifa_ifp) && (ifaaddr || gate))
389: ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
390: ifp);
391: else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||
392: (gate && (ifa = ifa_ifwithroute(rt->rt_flags,
393: rt_key(rt), gate))))
394: ifp = ifa->ifa_ifp;
395: if (ifa) {
396: struct ifaddr *oifa = rt->rt_ifa;
397: if (oifa != ifa) {
398: if (oifa && oifa->ifa_rtrequest)
399: oifa->ifa_rtrequest(RTM_DELETE, rt,
400: &info);
401: IFAFREE(rt->rt_ifa);
402: rt->rt_ifa = ifa;
403: ifa->ifa_refcnt++;
404: rt->rt_ifp = ifp;
405: }
406: }
407:
408: /* XXX Hack to allow some flags to be toggled */
409: if (rtm->rtm_fmask & RTF_FMASK)
410: rt->rt_flags = (rt->rt_flags &
411: ~rtm->rtm_fmask) |
412: (rtm->rtm_flags & rtm->rtm_fmask);
413:
414: rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
415: &rt->rt_rmx);
416: rtm->rtm_index = rt->rt_ifp->if_index;
417: if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
418: rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info);
419: if (genmask)
420: rt->rt_genmask = genmask;
421: if (info.rti_info[RTAX_LABEL] != NULL) {
422: char *rtlabel = ((struct sockaddr_rtlabel *)
423: info.rti_info[RTAX_LABEL])->sr_label;
424: rtlabel_unref(rt->rt_labelid);
425: rt->rt_labelid =
426: rtlabel_name2id(rtlabel);
427: }
428: if_group_routechange(dst, netmask);
429: /* FALLTHROUGH */
430: case RTM_LOCK:
431: rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
432: rt->rt_rmx.rmx_locks |=
433: (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
434: break;
435: }
436: break;
437:
438: default:
439: error = EOPNOTSUPP;
440: break;
441: }
442:
443: flush:
444: if (rtm) {
445: if (error)
446: rtm->rtm_errno = error;
447: else
448: rtm->rtm_flags |= RTF_DONE;
449: }
450: if (rt)
451: rtfree(rt);
452:
453: /*
454: * Check to see if we don't want our own messages.
455: */
456: if (!(so->so_options & SO_USELOOPBACK)) {
457: if (route_cb.any_count <= 1) {
458: if (rtm)
459: Free(rtm);
460: m_freem(m);
461: return (error);
462: }
463: /* There is another listener, so construct message */
464: rp = sotorawcb(so);
465: }
466: if (rp)
467: rp->rcb_proto.sp_family = 0; /* Avoid us */
468: if (dst)
469: route_proto.sp_protocol = dst->sa_family;
470: if (rtm) {
471: m_copyback(m, 0, rtm->rtm_msglen, rtm);
472: if (m->m_pkthdr.len < rtm->rtm_msglen) {
473: m_freem(m);
474: m = NULL;
475: } else if (m->m_pkthdr.len > rtm->rtm_msglen)
476: m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
477: Free(rtm);
478: }
479: if (m)
480: raw_input(m, &route_proto, &route_src, &route_dst);
481: if (rp)
482: rp->rcb_proto.sp_family = PF_ROUTE;
483:
484: return (error);
485: }
486:
487: void
488: rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_kmetrics *out)
489: {
490: if (which & RTV_MTU)
491: out->rmx_mtu = in->rmx_mtu;
492: if (which & RTV_EXPIRE)
493: out->rmx_expire = in->rmx_expire;
494: }
495:
496: void
497: rt_getmetrics(struct rt_kmetrics *in, struct rt_metrics *out)
498: {
499: bzero(out, sizeof(*out));
500: out->rmx_locks = in->rmx_locks;
501: out->rmx_mtu = in->rmx_mtu;
502: out->rmx_expire = in->rmx_expire;
503: out->rmx_pksent = in->rmx_pksent;
504: }
505:
506: #define ROUNDUP(a) \
507: ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
508: #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
509:
510: static void
511: rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
512: {
513: struct sockaddr *sa;
514: int i;
515:
516: bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
517: for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
518: if ((rtinfo->rti_addrs & (1 << i)) == 0)
519: continue;
520: rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
521: ADVANCE(cp, sa);
522: }
523: }
524:
525: static struct mbuf *
526: rt_msg1(int type, struct rt_addrinfo *rtinfo)
527: {
528: struct rt_msghdr *rtm;
529: struct mbuf *m;
530: int i;
531: struct sockaddr *sa;
532: int len, dlen;
533:
534: switch (type) {
535: case RTM_DELADDR:
536: case RTM_NEWADDR:
537: len = sizeof(struct ifa_msghdr);
538: break;
539: case RTM_IFINFO:
540: len = sizeof(struct if_msghdr);
541: break;
542: case RTM_IFANNOUNCE:
543: len = sizeof(struct if_announcemsghdr);
544: break;
545: default:
546: len = sizeof(struct rt_msghdr);
547: break;
548: }
549: if (len > MCLBYTES)
550: panic("rt_msg1");
551: m = m_gethdr(M_DONTWAIT, MT_DATA);
552: if (m && len > MHLEN) {
553: MCLGET(m, M_DONTWAIT);
554: if ((m->m_flags & M_EXT) == 0) {
555: m_free(m);
556: m = NULL;
557: }
558: }
559: if (m == 0)
560: return (m);
561: m->m_pkthdr.len = m->m_len = len;
562: m->m_pkthdr.rcvif = NULL;
563: rtm = mtod(m, struct rt_msghdr *);
564: bzero(rtm, len);
565: for (i = 0; i < RTAX_MAX; i++) {
566: if ((sa = rtinfo->rti_info[i]) == NULL)
567: continue;
568: rtinfo->rti_addrs |= (1 << i);
569: dlen = ROUNDUP(sa->sa_len);
570: m_copyback(m, len, dlen, sa);
571: len += dlen;
572: }
573: if (m->m_pkthdr.len != len) {
574: m_freem(m);
575: return (NULL);
576: }
577: rtm->rtm_msglen = len;
578: rtm->rtm_version = RTM_VERSION;
579: rtm->rtm_type = type;
580: return (m);
581: }
582:
583: static int
584: rt_msg2(int type, struct rt_addrinfo *rtinfo, caddr_t cp, struct walkarg *w)
585: {
586: int i;
587: int len, dlen, second_time = 0;
588: caddr_t cp0;
589:
590: rtinfo->rti_addrs = 0;
591: again:
592: switch (type) {
593: case RTM_DELADDR:
594: case RTM_NEWADDR:
595: len = sizeof(struct ifa_msghdr);
596: break;
597: case RTM_IFINFO:
598: len = sizeof(struct if_msghdr);
599: break;
600: default:
601: len = sizeof(struct rt_msghdr);
602: break;
603: }
604: if ((cp0 = cp) != NULL)
605: cp += len;
606: for (i = 0; i < RTAX_MAX; i++) {
607: struct sockaddr *sa;
608:
609: if ((sa = rtinfo->rti_info[i]) == 0)
610: continue;
611: rtinfo->rti_addrs |= (1 << i);
612: dlen = ROUNDUP(sa->sa_len);
613: if (cp) {
614: bcopy(sa, cp, (size_t)dlen);
615: cp += dlen;
616: }
617: len += dlen;
618: }
619: if (cp == 0 && w != NULL && !second_time) {
620: struct walkarg *rw = w;
621:
622: rw->w_needed += len;
623: if (rw->w_needed <= 0 && rw->w_where) {
624: if (rw->w_tmemsize < len) {
625: if (rw->w_tmem)
626: free(rw->w_tmem, M_RTABLE);
627: rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT);
628: if (rw->w_tmem)
629: rw->w_tmemsize = len;
630: }
631: if (rw->w_tmem) {
632: cp = rw->w_tmem;
633: second_time = 1;
634: goto again;
635: } else
636: rw->w_where = 0;
637: }
638: }
639: if (cp) {
640: struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
641:
642: rtm->rtm_version = RTM_VERSION;
643: rtm->rtm_type = type;
644: rtm->rtm_msglen = len;
645: }
646: return (len);
647: }
648:
649: /*
650: * This routine is called to generate a message from the routing
651: * socket indicating that a redirect has occurred, a routing lookup
652: * has failed, or that a protocol has detected timeouts to a particular
653: * destination.
654: */
655: void
656: rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags,
657: struct ifnet *ifp, int error, u_int tableid)
658: {
659: struct rt_msghdr *rtm;
660: struct mbuf *m;
661: struct sockaddr *sa = rtinfo->rti_info[RTAX_DST];
662:
663: if (route_cb.any_count == 0)
664: return;
665: m = rt_msg1(type, rtinfo);
666: if (m == 0)
667: return;
668: rtm = mtod(m, struct rt_msghdr *);
669: rtm->rtm_flags = RTF_DONE | flags;
670: rtm->rtm_errno = error;
671: rtm->rtm_tableid = tableid;
672: rtm->rtm_addrs = rtinfo->rti_addrs;
673: if (ifp != NULL)
674: rtm->rtm_index = ifp->if_index;
675: if (sa == NULL)
676: route_proto.sp_protocol = 0;
677: else
678: route_proto.sp_protocol = sa->sa_family;
679: raw_input(m, &route_proto, &route_src, &route_dst);
680: }
681:
682: /*
683: * This routine is called to generate a message from the routing
684: * socket indicating that the status of a network interface has changed.
685: */
686: void
687: rt_ifmsg(struct ifnet *ifp)
688: {
689: struct if_msghdr *ifm;
690: struct mbuf *m;
691: struct rt_addrinfo info;
692:
693: if (route_cb.any_count == 0)
694: return;
695: bzero(&info, sizeof(info));
696: m = rt_msg1(RTM_IFINFO, &info);
697: if (m == 0)
698: return;
699: ifm = mtod(m, struct if_msghdr *);
700: ifm->ifm_index = ifp->if_index;
701: ifm->ifm_flags = ifp->if_flags;
702: ifm->ifm_data = ifp->if_data;
703: ifm->ifm_addrs = 0;
704: route_proto.sp_protocol = 0;
705: raw_input(m, &route_proto, &route_src, &route_dst);
706: }
707:
708: /*
709: * This is called to generate messages from the routing socket
710: * indicating a network interface has had addresses associated with it.
711: * if we ever reverse the logic and replace messages TO the routing
712: * socket indicate a request to configure interfaces, then it will
713: * be unnecessary as the routing socket will automatically generate
714: * copies of it.
715: */
716: void
717: rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
718: {
719: struct rt_addrinfo info;
720: struct sockaddr *sa = NULL;
721: int pass;
722: struct mbuf *m = NULL;
723: struct ifnet *ifp = ifa->ifa_ifp;
724:
725: if (route_cb.any_count == 0)
726: return;
727: for (pass = 1; pass < 3; pass++) {
728: bzero(&info, sizeof(info));
729: if ((cmd == RTM_ADD && pass == 1) ||
730: (cmd == RTM_DELETE && pass == 2)) {
731: struct ifa_msghdr *ifam;
732: int ncmd;
733:
734: if (cmd == RTM_ADD)
735: ncmd = RTM_NEWADDR;
736: else
737: ncmd = RTM_DELADDR;
738:
739: ifaaddr = sa = ifa->ifa_addr;
740: ifpaddr = TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
741: netmask = ifa->ifa_netmask;
742: brdaddr = ifa->ifa_dstaddr;
743: if ((m = rt_msg1(ncmd, &info)) == NULL)
744: continue;
745: ifam = mtod(m, struct ifa_msghdr *);
746: ifam->ifam_index = ifp->if_index;
747: ifam->ifam_metric = ifa->ifa_metric;
748: ifam->ifam_flags = ifa->ifa_flags;
749: ifam->ifam_addrs = info.rti_addrs;
750: }
751: if ((cmd == RTM_ADD && pass == 2) ||
752: (cmd == RTM_DELETE && pass == 1)) {
753: struct rt_msghdr *rtm;
754:
755: if (rt == 0)
756: continue;
757: netmask = rt_mask(rt);
758: dst = sa = rt_key(rt);
759: gate = rt->rt_gateway;
760: if ((m = rt_msg1(cmd, &info)) == NULL)
761: continue;
762: rtm = mtod(m, struct rt_msghdr *);
763: rtm->rtm_index = ifp->if_index;
764: rtm->rtm_flags |= rt->rt_flags;
765: rtm->rtm_errno = error;
766: rtm->rtm_addrs = info.rti_addrs;
767: }
768: if (sa == NULL)
769: route_proto.sp_protocol = 0;
770: else
771: route_proto.sp_protocol = sa->sa_family;
772: raw_input(m, &route_proto, &route_src, &route_dst);
773: }
774: }
775:
776: /*
777: * This is called to generate routing socket messages indicating
778: * network interface arrival and departure.
779: */
780: void
781: rt_ifannouncemsg(struct ifnet *ifp, int what)
782: {
783: struct if_announcemsghdr *ifan;
784: struct mbuf *m;
785: struct rt_addrinfo info;
786:
787: if (route_cb.any_count == 0)
788: return;
789: bzero(&info, sizeof(info));
790: m = rt_msg1(RTM_IFANNOUNCE, &info);
791: if (m == 0)
792: return;
793: ifan = mtod(m, struct if_announcemsghdr *);
794: ifan->ifan_index = ifp->if_index;
795: strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name));
796: ifan->ifan_what = what;
797: route_proto.sp_protocol = 0;
798: raw_input(m, &route_proto, &route_src, &route_dst);
799: }
800:
801: /*
802: * This is used in dumping the kernel table via sysctl().
803: */
804: int
805: sysctl_dumpentry(struct radix_node *rn, void *v)
806: {
807: struct walkarg *w = v;
808: struct rtentry *rt = (struct rtentry *)rn;
809: int error = 0, size;
810: struct rt_addrinfo info;
811: struct sockaddr_rtlabel sa_rt;
812: const char *label;
813:
814: if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
815: return 0;
816: bzero(&info, sizeof(info));
817: dst = rt_key(rt);
818: gate = rt->rt_gateway;
819: netmask = rt_mask(rt);
820: genmask = rt->rt_genmask;
821: if (rt->rt_ifp) {
822: ifpaddr = TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
823: ifaaddr = rt->rt_ifa->ifa_addr;
824: if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
825: brdaddr = rt->rt_ifa->ifa_dstaddr;
826: }
827: if (rt->rt_labelid) {
828: bzero(&sa_rt, sizeof(sa_rt));
829: sa_rt.sr_len = sizeof(sa_rt);
830: label = rtlabel_id2name(rt->rt_labelid);
831: if (label != NULL) {
832: strlcpy(sa_rt.sr_label, label,
833: sizeof(sa_rt.sr_label));
834: info.rti_info[RTAX_LABEL] =
835: (struct sockaddr *)&sa_rt;
836: }
837: }
838:
839: size = rt_msg2(RTM_GET, &info, NULL, w);
840: if (w->w_where && w->w_tmem && w->w_needed <= 0) {
841: struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
842:
843: rtm->rtm_flags = rt->rt_flags;
844: rtm->rtm_use = 0;
845: rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
846: rtm->rtm_rmx.rmx_refcnt = (u_long)rt->rt_refcnt;
847: rtm->rtm_index = rt->rt_ifp->if_index;
848: rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
849: rtm->rtm_addrs = info.rti_addrs;
850: if ((error = copyout(rtm, w->w_where, size)) != 0)
851: w->w_where = NULL;
852: else
853: w->w_where += size;
854: }
855: return (error);
856: }
857:
858: int
859: sysctl_iflist(int af, struct walkarg *w)
860: {
861: struct ifnet *ifp;
862: struct ifaddr *ifa;
863: struct rt_addrinfo info;
864: int len, error = 0;
865:
866: bzero(&info, sizeof(info));
867: TAILQ_FOREACH(ifp, &ifnet, if_list) {
868: if (w->w_arg && w->w_arg != ifp->if_index)
869: continue;
870: ifa = TAILQ_FIRST(&ifp->if_addrlist);
871: if (!ifa)
872: continue;
873: ifpaddr = ifa->ifa_addr;
874: len = rt_msg2(RTM_IFINFO, &info, 0, w);
875: ifpaddr = 0;
876: if (w->w_where && w->w_tmem && w->w_needed <= 0) {
877: struct if_msghdr *ifm;
878:
879: ifm = (struct if_msghdr *)w->w_tmem;
880: ifm->ifm_index = ifp->if_index;
881: ifm->ifm_flags = ifp->if_flags;
882: ifm->ifm_data = ifp->if_data;
883: ifm->ifm_addrs = info.rti_addrs;
884: error = copyout(ifm, w->w_where, len);
885: if (error)
886: return (error);
887: w->w_where += len;
888: }
889: while ((ifa = TAILQ_NEXT(ifa, ifa_list)) !=
890: TAILQ_END(&ifp->if_addrlist)) {
891: if (af && af != ifa->ifa_addr->sa_family)
892: continue;
893: ifaaddr = ifa->ifa_addr;
894: netmask = ifa->ifa_netmask;
895: brdaddr = ifa->ifa_dstaddr;
896: len = rt_msg2(RTM_NEWADDR, &info, 0, w);
897: if (w->w_where && w->w_tmem && w->w_needed <= 0) {
898: struct ifa_msghdr *ifam;
899:
900: ifam = (struct ifa_msghdr *)w->w_tmem;
901: ifam->ifam_index = ifa->ifa_ifp->if_index;
902: ifam->ifam_flags = ifa->ifa_flags;
903: ifam->ifam_metric = ifa->ifa_metric;
904: ifam->ifam_addrs = info.rti_addrs;
905: error = copyout(w->w_tmem, w->w_where, len);
906: if (error)
907: return (error);
908: w->w_where += len;
909: }
910: }
911: ifaaddr = netmask = brdaddr = 0;
912: }
913: return (0);
914: }
915:
916: int
917: sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new,
918: size_t newlen)
919: {
920: struct radix_node_head *rnh;
921: int i, s, error = EINVAL;
922: u_char af;
923: struct walkarg w;
924: u_int tableid = 0;
925:
926: if (new)
927: return (EPERM);
928: if (namelen < 3 || namelen > 4)
929: return (EINVAL);
930: af = name[0];
931: bzero(&w, sizeof(w));
932: w.w_where = where;
933: w.w_given = *given;
934: w.w_needed = 0 - w.w_given;
935: w.w_op = name[1];
936: w.w_arg = name[2];
937:
938: if (namelen == 4) {
939: tableid = name[3];
940: if (!rtable_exists(tableid))
941: return (EINVAL);
942: }
943:
944: s = splsoftnet();
945: switch (w.w_op) {
946:
947: case NET_RT_DUMP:
948: case NET_RT_FLAGS:
949: for (i = 1; i <= AF_MAX; i++)
950: if ((rnh = rt_gettable(i, tableid)) != NULL &&
951: (af == 0 || af == i) &&
952: (error = (*rnh->rnh_walktree)(rnh,
953: sysctl_dumpentry, &w)))
954: break;
955: break;
956:
957: case NET_RT_IFLIST:
958: error = sysctl_iflist(af, &w);
959: break;
960:
961: case NET_RT_STATS:
962: error = sysctl_rdstruct(where, given, new,
963: &rtstat, sizeof(rtstat));
964: splx(s);
965: return (error);
966: }
967: splx(s);
968: if (w.w_tmem)
969: free(w.w_tmem, M_RTABLE);
970: w.w_needed += w.w_given;
971: if (where) {
972: *given = w.w_where - (caddr_t)where;
973: if (*given < w.w_needed)
974: return (ENOMEM);
975: } else
976: *given = (11 * w.w_needed) / 10;
977:
978: return (error);
979: }
980:
981: /*
982: * Definitions of protocols supported in the ROUTE domain.
983: */
984:
985: extern struct domain routedomain; /* or at least forward */
986:
987: struct protosw routesw[] = {
988: { SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR,
989: raw_input, route_output, raw_ctlinput, 0,
990: route_usrreq,
991: raw_init, 0, 0, 0,
992: sysctl_rtable,
993: }
994: };
995:
996: struct domain routedomain =
997: { PF_ROUTE, "route", route_init, 0, 0,
998: routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };
CVSweb