[BACK]Return to rtsock.c CVS log [TXT][DIR] Up to [local] / sys / net

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