Annotation of sys/net/rtsock.c, Revision 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