[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     ! 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