The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/rtsock.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2004, 2005 The DragonFly Project.  All rights reserved.
    3  *
    4  * This code is derived from software contributed to The DragonFly Project
    5  * by Jeffrey M. Hsu.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of The DragonFly Project nor the names of its
   16  *    contributors may be used to endorse or promote products derived
   17  *    from this software without specific, prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
   23  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   24  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
   25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   29  * 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.7 (Berkeley) 10/12/95
   62  * $FreeBSD: src/sys/net/rtsock.c,v 1.44.2.11 2002/12/04 14:05:41 ru Exp $
   63  */
   64 
   65 #include "opt_sctp.h"
   66 
   67 #include <sys/param.h>
   68 #include <sys/systm.h>
   69 #include <sys/kernel.h>
   70 #include <sys/sysctl.h>
   71 #include <sys/proc.h>
   72 #include <sys/priv.h>
   73 #include <sys/malloc.h>
   74 #include <sys/mbuf.h>
   75 #include <sys/protosw.h>
   76 #include <sys/socket.h>
   77 #include <sys/socketvar.h>
   78 #include <sys/domain.h>
   79 
   80 #include <sys/thread2.h>
   81 #include <sys/socketvar2.h>
   82 
   83 #include <net/if.h>
   84 #include <net/route.h>
   85 #include <net/raw_cb.h>
   86 #include <net/netmsg2.h>
   87 #include <net/netisr2.h>
   88 
   89 #ifdef SCTP
   90 extern void sctp_add_ip_address(struct ifaddr *ifa);
   91 extern void sctp_delete_ip_address(struct ifaddr *ifa);
   92 #endif /* SCTP */
   93 
   94 MALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables");
   95 
   96 static struct route_cb {
   97         int     ip_count;
   98         int     ip6_count;
   99         int     ipx_count;
  100         int     ns_count;
  101         int     any_count;
  102 } route_cb;
  103 
  104 static const struct sockaddr route_src = { 2, PF_ROUTE, };
  105 
  106 struct walkarg {
  107         int     w_tmemsize;
  108         int     w_op, w_arg;
  109         void    *w_tmem;
  110         struct sysctl_req *w_req;
  111 };
  112 
  113 static struct mbuf *
  114                 rt_msg_mbuf (int, struct rt_addrinfo *);
  115 static void     rt_msg_buffer (int, struct rt_addrinfo *, void *buf, int len);
  116 static int      rt_msgsize (int type, struct rt_addrinfo *rtinfo);
  117 static int      rt_xaddrs (char *, char *, struct rt_addrinfo *);
  118 static int      sysctl_dumpentry (struct radix_node *rn, void *vw);
  119 static int      sysctl_iflist (int af, struct walkarg *w);
  120 static int      route_output(struct mbuf *, struct socket *, ...);
  121 static void     rt_setmetrics (u_long, struct rt_metrics *,
  122                                struct rt_metrics *);
  123 
  124 /*
  125  * It really doesn't make any sense at all for this code to share much
  126  * with raw_usrreq.c, since its functionality is so restricted.  XXX
  127  */
  128 static void
  129 rts_abort(netmsg_t msg)
  130 {
  131         crit_enter();
  132         raw_usrreqs.pru_abort(msg);
  133         /* msg invalid now */
  134         crit_exit();
  135 }
  136 
  137 /* pru_accept is EOPNOTSUPP */
  138 
  139 static void
  140 rts_attach(netmsg_t msg)
  141 {
  142         struct socket *so = msg->base.nm_so;
  143         struct pru_attach_info *ai = msg->attach.nm_ai;
  144         struct rawcb *rp;
  145         int proto = msg->attach.nm_proto;
  146         int error;
  147 
  148         crit_enter();
  149         if (sotorawcb(so) != NULL) {
  150                 error = EISCONN;
  151                 goto done;
  152         }
  153 
  154         rp = kmalloc(sizeof *rp, M_PCB, M_WAITOK | M_ZERO);
  155 
  156         /*
  157          * The critical section is necessary to block protocols from sending
  158          * error notifications (like RTM_REDIRECT or RTM_LOSING) while
  159          * this PCB is extant but incompletely initialized.
  160          * Probably we should try to do more of this work beforehand and
  161          * eliminate the critical section.
  162          */
  163         so->so_pcb = rp;
  164         soreference(so);        /* so_pcb assignment */
  165         error = raw_attach(so, proto, ai->sb_rlimit);
  166         rp = sotorawcb(so);
  167         if (error) {
  168                 kfree(rp, M_PCB);
  169                 goto done;
  170         }
  171         switch(rp->rcb_proto.sp_protocol) {
  172         case AF_INET:
  173                 route_cb.ip_count++;
  174                 break;
  175         case AF_INET6:
  176                 route_cb.ip6_count++;
  177                 break;
  178         case AF_IPX:
  179                 route_cb.ipx_count++;
  180                 break;
  181         case AF_NS:
  182                 route_cb.ns_count++;
  183                 break;
  184         }
  185         rp->rcb_faddr = &route_src;
  186         route_cb.any_count++;
  187         soisconnected(so);
  188         so->so_options |= SO_USELOOPBACK;
  189         error = 0;
  190 done:
  191         crit_exit();
  192         lwkt_replymsg(&msg->lmsg, error);
  193 }
  194 
  195 static void
  196 rts_bind(netmsg_t msg)
  197 {
  198         crit_enter();
  199         raw_usrreqs.pru_bind(msg); /* xxx just EINVAL */
  200         /* msg invalid now */
  201         crit_exit();
  202 }
  203 
  204 static void
  205 rts_connect(netmsg_t msg)
  206 {
  207         crit_enter();
  208         raw_usrreqs.pru_connect(msg); /* XXX just EINVAL */
  209         /* msg invalid now */
  210         crit_exit();
  211 }
  212 
  213 /* pru_connect2 is EOPNOTSUPP */
  214 /* pru_control is EOPNOTSUPP */
  215 
  216 static void
  217 rts_detach(netmsg_t msg)
  218 {
  219         struct socket *so = msg->base.nm_so;
  220         struct rawcb *rp = sotorawcb(so);
  221 
  222         crit_enter();
  223         if (rp != NULL) {
  224                 switch(rp->rcb_proto.sp_protocol) {
  225                 case AF_INET:
  226                         route_cb.ip_count--;
  227                         break;
  228                 case AF_INET6:
  229                         route_cb.ip6_count--;
  230                         break;
  231                 case AF_IPX:
  232                         route_cb.ipx_count--;
  233                         break;
  234                 case AF_NS:
  235                         route_cb.ns_count--;
  236                         break;
  237                 }
  238                 route_cb.any_count--;
  239         }
  240         raw_usrreqs.pru_detach(msg);
  241         /* msg invalid now */
  242         crit_exit();
  243 }
  244 
  245 static void
  246 rts_disconnect(netmsg_t msg)
  247 {
  248         crit_enter();
  249         raw_usrreqs.pru_disconnect(msg);
  250         /* msg invalid now */
  251         crit_exit();
  252 }
  253 
  254 /* pru_listen is EOPNOTSUPP */
  255 
  256 static void
  257 rts_peeraddr(netmsg_t msg)
  258 {
  259         crit_enter();
  260         raw_usrreqs.pru_peeraddr(msg);
  261         /* msg invalid now */
  262         crit_exit();
  263 }
  264 
  265 /* pru_rcvd is EOPNOTSUPP */
  266 /* pru_rcvoob is EOPNOTSUPP */
  267 
  268 static void
  269 rts_send(netmsg_t msg)
  270 {
  271         crit_enter();
  272         raw_usrreqs.pru_send(msg);
  273         /* msg invalid now */
  274         crit_exit();
  275 }
  276 
  277 /* pru_sense is null */
  278 
  279 static void
  280 rts_shutdown(netmsg_t msg)
  281 {
  282         crit_enter();
  283         raw_usrreqs.pru_shutdown(msg);
  284         /* msg invalid now */
  285         crit_exit();
  286 }
  287 
  288 static void
  289 rts_sockaddr(netmsg_t msg)
  290 {
  291         crit_enter();
  292         raw_usrreqs.pru_sockaddr(msg);
  293         /* msg invalid now */
  294         crit_exit();
  295 }
  296 
  297 static struct pr_usrreqs route_usrreqs = {
  298         .pru_abort = rts_abort,
  299         .pru_accept = pr_generic_notsupp,
  300         .pru_attach = rts_attach,
  301         .pru_bind = rts_bind,
  302         .pru_connect = rts_connect,
  303         .pru_connect2 = pr_generic_notsupp,
  304         .pru_control = pr_generic_notsupp,
  305         .pru_detach = rts_detach,
  306         .pru_disconnect = rts_disconnect,
  307         .pru_listen = pr_generic_notsupp,
  308         .pru_peeraddr = rts_peeraddr,
  309         .pru_rcvd = pr_generic_notsupp,
  310         .pru_rcvoob = pr_generic_notsupp,
  311         .pru_send = rts_send,
  312         .pru_sense = pru_sense_null,
  313         .pru_shutdown = rts_shutdown,
  314         .pru_sockaddr = rts_sockaddr,
  315         .pru_sosend = sosend,
  316         .pru_soreceive = soreceive
  317 };
  318 
  319 static __inline sa_family_t
  320 familyof(struct sockaddr *sa)
  321 {
  322         return (sa != NULL ? sa->sa_family : 0);
  323 }
  324 
  325 /*
  326  * Routing socket input function.  The packet must be serialized onto cpu 0.
  327  * We use the cpu0_soport() netisr processing loop to handle it.
  328  *
  329  * This looks messy but it means that anyone, including interrupt code,
  330  * can send a message to the routing socket.
  331  */
  332 static void
  333 rts_input_handler(netmsg_t msg)
  334 {
  335         static const struct sockaddr route_dst = { 2, PF_ROUTE, };
  336         struct sockproto route_proto;
  337         struct netmsg_packet *pmsg = &msg->packet;
  338         struct mbuf *m;
  339         sa_family_t family;
  340         struct rawcb *skip;
  341 
  342         family = pmsg->base.lmsg.u.ms_result;
  343         route_proto.sp_family = PF_ROUTE;
  344         route_proto.sp_protocol = family;
  345 
  346         m = pmsg->nm_packet;
  347         M_ASSERTPKTHDR(m);
  348 
  349         skip = m->m_pkthdr.header;
  350         m->m_pkthdr.header = NULL;
  351 
  352         raw_input(m, &route_proto, &route_src, &route_dst, skip);
  353 }
  354 
  355 static void
  356 rts_input_skip(struct mbuf *m, sa_family_t family, struct rawcb *skip)
  357 {
  358         struct netmsg_packet *pmsg;
  359         lwkt_port_t port;
  360 
  361         M_ASSERTPKTHDR(m);
  362 
  363         port = netisr_cpuport(0);       /* XXX same as for routing socket */
  364         pmsg = &m->m_hdr.mh_netmsg;
  365         netmsg_init(&pmsg->base, NULL, &netisr_apanic_rport,
  366                     0, rts_input_handler);
  367         pmsg->nm_packet = m;
  368         pmsg->base.lmsg.u.ms_result = family;
  369         m->m_pkthdr.header = skip; /* XXX steal field in pkthdr */
  370         lwkt_sendmsg(port, &pmsg->base.lmsg);
  371 }
  372 
  373 static __inline void
  374 rts_input(struct mbuf *m, sa_family_t family)
  375 {
  376         rts_input_skip(m, family, NULL);
  377 }
  378 
  379 static void *
  380 reallocbuf_nofree(void *ptr, size_t len, size_t olen)
  381 {
  382         void *newptr;
  383 
  384         newptr = kmalloc(len, M_RTABLE, M_INTWAIT | M_NULLOK);
  385         if (newptr == NULL)
  386                 return NULL;
  387         bcopy(ptr, newptr, olen);
  388         return (newptr);
  389 }
  390 
  391 /*
  392  * Internal helper routine for route_output().
  393  */
  394 static int
  395 _fillrtmsg(struct rt_msghdr **prtm, struct rtentry *rt,
  396            struct rt_addrinfo *rtinfo)
  397 {
  398         int msglen;
  399         struct rt_msghdr *rtm = *prtm;
  400 
  401         /* Fill in rt_addrinfo for call to rt_msg_buffer(). */
  402         rtinfo->rti_dst = rt_key(rt);
  403         rtinfo->rti_gateway = rt->rt_gateway;
  404         rtinfo->rti_netmask = rt_mask(rt);              /* might be NULL */
  405         rtinfo->rti_genmask = rt->rt_genmask;           /* might be NULL */
  406         if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
  407                 if (rt->rt_ifp != NULL) {
  408                         rtinfo->rti_ifpaddr =
  409                             TAILQ_FIRST(&rt->rt_ifp->if_addrheads[mycpuid])
  410                             ->ifa->ifa_addr;
  411                         rtinfo->rti_ifaaddr = rt->rt_ifa->ifa_addr;
  412                         if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
  413                                 rtinfo->rti_bcastaddr = rt->rt_ifa->ifa_dstaddr;
  414                         rtm->rtm_index = rt->rt_ifp->if_index;
  415                 } else {
  416                         rtinfo->rti_ifpaddr = NULL;
  417                         rtinfo->rti_ifaaddr = NULL;
  418                 }
  419         } else if (rt->rt_ifp != NULL) {
  420                 rtm->rtm_index = rt->rt_ifp->if_index;
  421         }
  422 
  423         msglen = rt_msgsize(rtm->rtm_type, rtinfo);
  424         if (rtm->rtm_msglen < msglen) {
  425                 /* NOTE: Caller will free the old rtm accordingly */
  426                 rtm = reallocbuf_nofree(rtm, msglen, rtm->rtm_msglen);
  427                 if (rtm == NULL)
  428                         return (ENOBUFS);
  429                 *prtm = rtm;
  430         }
  431         rt_msg_buffer(rtm->rtm_type, rtinfo, rtm, msglen);
  432 
  433         rtm->rtm_flags = rt->rt_flags;
  434         rtm->rtm_rmx = rt->rt_rmx;
  435         rtm->rtm_addrs = rtinfo->rti_addrs;
  436 
  437         return (0);
  438 }
  439 
  440 struct rtm_arg {
  441         struct rt_msghdr        *bak_rtm;
  442         struct rt_msghdr        *new_rtm;
  443 };
  444 
  445 static int
  446 fillrtmsg(struct rtm_arg *arg, struct rtentry *rt,
  447           struct rt_addrinfo *rtinfo)
  448 {
  449         struct rt_msghdr *rtm = arg->new_rtm;
  450         int error;
  451 
  452         error = _fillrtmsg(&rtm, rt, rtinfo);
  453         if (!error) {
  454                 if (arg->new_rtm != rtm) {
  455                         /*
  456                          * _fillrtmsg() just allocated a new rtm;
  457                          * if the previously allocated rtm is not
  458                          * the backing rtm, it should be freed.
  459                          */
  460                         if (arg->new_rtm != arg->bak_rtm)
  461                                 kfree(arg->new_rtm, M_RTABLE);
  462                         arg->new_rtm = rtm;
  463                 }
  464         }
  465         return error;
  466 }
  467 
  468 static void route_output_add_callback(int, int, struct rt_addrinfo *,
  469                                         struct rtentry *, void *);
  470 static void route_output_delete_callback(int, int, struct rt_addrinfo *,
  471                                         struct rtentry *, void *);
  472 static int route_output_get_callback(int, struct rt_addrinfo *,
  473                                      struct rtentry *, void *, int);
  474 static int route_output_change_callback(int, struct rt_addrinfo *,
  475                                         struct rtentry *, void *, int);
  476 static int route_output_lock_callback(int, struct rt_addrinfo *,
  477                                       struct rtentry *, void *, int);
  478 
  479 /*ARGSUSED*/
  480 static int
  481 route_output(struct mbuf *m, struct socket *so, ...)
  482 {
  483         struct rtm_arg arg;
  484         struct rt_msghdr *rtm = NULL;
  485         struct rawcb *rp = NULL;
  486         struct pr_output_info *oi;
  487         struct rt_addrinfo rtinfo;
  488         sa_family_t family;
  489         int len, error = 0;
  490         __va_list ap;
  491 
  492         M_ASSERTPKTHDR(m);
  493 
  494         __va_start(ap, so);
  495         oi = __va_arg(ap, struct pr_output_info *);
  496         __va_end(ap);
  497 
  498         family = familyof(NULL);
  499 
  500 #define gotoerr(e) { error = e; goto flush;}
  501 
  502         if (m == NULL ||
  503             (m->m_len < sizeof(long) &&
  504              (m = m_pullup(m, sizeof(long))) == NULL))
  505                 return (ENOBUFS);
  506         len = m->m_pkthdr.len;
  507         if (len < sizeof(struct rt_msghdr) ||
  508             len != mtod(m, struct rt_msghdr *)->rtm_msglen)
  509                 gotoerr(EINVAL);
  510 
  511         rtm = kmalloc(len, M_RTABLE, M_INTWAIT | M_NULLOK);
  512         if (rtm == NULL)
  513                 gotoerr(ENOBUFS);
  514 
  515         m_copydata(m, 0, len, (caddr_t)rtm);
  516         if (rtm->rtm_version != RTM_VERSION)
  517                 gotoerr(EPROTONOSUPPORT);
  518 
  519         rtm->rtm_pid = oi->p_pid;
  520         bzero(&rtinfo, sizeof(struct rt_addrinfo));
  521         rtinfo.rti_addrs = rtm->rtm_addrs;
  522         if (rt_xaddrs((char *)(rtm + 1), (char *)rtm + len, &rtinfo) != 0)
  523                 gotoerr(EINVAL);
  524 
  525         rtinfo.rti_flags = rtm->rtm_flags;
  526         if (rtinfo.rti_dst == NULL || rtinfo.rti_dst->sa_family >= AF_MAX ||
  527             (rtinfo.rti_gateway && rtinfo.rti_gateway->sa_family >= AF_MAX))
  528                 gotoerr(EINVAL);
  529 
  530         family = familyof(rtinfo.rti_dst);
  531 
  532         /*
  533          * Verify that the caller has the appropriate privilege; RTM_GET
  534          * is the only operation the non-superuser is allowed.
  535          */
  536         if (rtm->rtm_type != RTM_GET &&
  537             priv_check_cred(so->so_cred, PRIV_ROOT, 0) != 0)
  538                 gotoerr(EPERM);
  539 
  540         if (rtinfo.rti_genmask != NULL) {
  541                 error = rtmask_add_global(rtinfo.rti_genmask,
  542                     rtm->rtm_type != RTM_GET ?
  543                     RTREQ_PRIO_HIGH : RTREQ_PRIO_NORM);
  544                 if (error)
  545                         goto flush;
  546         }
  547 
  548         switch (rtm->rtm_type) {
  549         case RTM_ADD:
  550                 if (rtinfo.rti_gateway == NULL) {
  551                         error = EINVAL;
  552                 } else {
  553                         error = rtrequest1_global(RTM_ADD, &rtinfo,
  554                             route_output_add_callback, rtm, RTREQ_PRIO_HIGH);
  555                 }
  556                 break;
  557         case RTM_DELETE:
  558                 /*
  559                  * Backing rtm (bak_rtm) could _not_ be freed during
  560                  * rtrequest1_global or rtsearch_global, even if the
  561                  * callback reallocates the rtm due to its size changes,
  562                  * since rtinfo points to the backing rtm's memory area.
  563                  * After rtrequest1_global or rtsearch_global returns,
  564                  * it is safe to free the backing rtm, since rtinfo will
  565                  * not be used anymore.
  566                  *
  567                  * new_rtm will be used to save the new rtm allocated
  568                  * by rtrequest1_global or rtsearch_global.
  569                  */
  570                 arg.bak_rtm = rtm;
  571                 arg.new_rtm = rtm;
  572                 error = rtrequest1_global(RTM_DELETE, &rtinfo,
  573                     route_output_delete_callback, &arg, RTREQ_PRIO_HIGH);
  574                 rtm = arg.new_rtm;
  575                 if (rtm != arg.bak_rtm)
  576                         kfree(arg.bak_rtm, M_RTABLE);
  577                 break;
  578         case RTM_GET:
  579                 /* See the comment in RTM_DELETE */
  580                 arg.bak_rtm = rtm;
  581                 arg.new_rtm = rtm;
  582                 error = rtsearch_global(RTM_GET, &rtinfo,
  583                     route_output_get_callback, &arg, RTS_NOEXACTMATCH,
  584                     RTREQ_PRIO_NORM);
  585                 rtm = arg.new_rtm;
  586                 if (rtm != arg.bak_rtm)
  587                         kfree(arg.bak_rtm, M_RTABLE);
  588                 break;
  589         case RTM_CHANGE:
  590                 error = rtsearch_global(RTM_CHANGE, &rtinfo,
  591                     route_output_change_callback, rtm, RTS_EXACTMATCH,
  592                     RTREQ_PRIO_HIGH);
  593                 break;
  594         case RTM_LOCK:
  595                 error = rtsearch_global(RTM_LOCK, &rtinfo,
  596                     route_output_lock_callback, rtm, RTS_EXACTMATCH,
  597                     RTREQ_PRIO_HIGH);
  598                 break;
  599         default:
  600                 error = EOPNOTSUPP;
  601                 break;
  602         }
  603 flush:
  604         if (rtm != NULL) {
  605                 if (error != 0)
  606                         rtm->rtm_errno = error;
  607                 else
  608                         rtm->rtm_flags |= RTF_DONE;
  609         }
  610 
  611         /*
  612          * Check to see if we don't want our own messages.
  613          */
  614         if (!(so->so_options & SO_USELOOPBACK)) {
  615                 if (route_cb.any_count <= 1) {
  616                         if (rtm != NULL)
  617                                 kfree(rtm, M_RTABLE);
  618                         m_freem(m);
  619                         return (error);
  620                 }
  621                 /* There is another listener, so construct message */
  622                 rp = sotorawcb(so);
  623         }
  624         if (rtm != NULL) {
  625                 m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
  626                 if (m->m_pkthdr.len < rtm->rtm_msglen) {
  627                         m_freem(m);
  628                         m = NULL;
  629                 } else if (m->m_pkthdr.len > rtm->rtm_msglen)
  630                         m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
  631                 kfree(rtm, M_RTABLE);
  632         }
  633         if (m != NULL)
  634                 rts_input_skip(m, family, rp);
  635         return (error);
  636 }
  637 
  638 static void
  639 route_output_add_callback(int cmd, int error, struct rt_addrinfo *rtinfo,
  640                           struct rtentry *rt, void *arg)
  641 {
  642         struct rt_msghdr *rtm = arg;
  643 
  644         if (error == 0 && rt != NULL) {
  645                 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
  646                     &rt->rt_rmx);
  647                 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
  648                 rt->rt_rmx.rmx_locks |=
  649                     (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
  650                 if (rtinfo->rti_genmask != NULL) {
  651                         rt->rt_genmask = rtmask_purelookup(rtinfo->rti_genmask);
  652                         if (rt->rt_genmask == NULL) {
  653                                 /*
  654                                  * This should not happen, since we
  655                                  * have already installed genmask
  656                                  * on each CPU before we reach here.
  657                                  */
  658                                 panic("genmask is gone!?");
  659                         }
  660                 } else {
  661                         rt->rt_genmask = NULL;
  662                 }
  663                 rtm->rtm_index = rt->rt_ifp->if_index;
  664         }
  665 }
  666 
  667 static void
  668 route_output_delete_callback(int cmd, int error, struct rt_addrinfo *rtinfo,
  669                           struct rtentry *rt, void *arg)
  670 {
  671         if (error == 0 && rt) {
  672                 ++rt->rt_refcnt;
  673                 if (fillrtmsg(arg, rt, rtinfo) != 0) {
  674                         error = ENOBUFS;
  675                         /* XXX no way to return the error */
  676                 }
  677                 --rt->rt_refcnt;
  678         }
  679         if (rt && rt->rt_refcnt == 0) {
  680                 ++rt->rt_refcnt;
  681                 rtfree(rt);
  682         }
  683 }
  684 
  685 static int
  686 route_output_get_callback(int cmd, struct rt_addrinfo *rtinfo,
  687                           struct rtentry *rt, void *arg, int found_cnt)
  688 {
  689         int error, found = 0;
  690 
  691         if (((rtinfo->rti_flags ^ rt->rt_flags) & RTF_HOST) == 0)
  692                 found = 1;
  693 
  694         error = fillrtmsg(arg, rt, rtinfo);
  695         if (!error && found) {
  696                 /* Got the exact match, we could return now! */
  697                 error = EJUSTRETURN;
  698         }
  699         return error;
  700 }
  701 
  702 static int
  703 route_output_change_callback(int cmd, struct rt_addrinfo *rtinfo,
  704                              struct rtentry *rt, void *arg, int found_cnt)
  705 {
  706         struct rt_msghdr *rtm = arg;
  707         struct ifaddr *ifa;
  708         int error = 0;
  709 
  710         /*
  711          * new gateway could require new ifaddr, ifp;
  712          * flags may also be different; ifp may be specified
  713          * by ll sockaddr when protocol address is ambiguous
  714          */
  715         if (((rt->rt_flags & RTF_GATEWAY) && rtinfo->rti_gateway != NULL) ||
  716             rtinfo->rti_ifpaddr != NULL ||
  717             (rtinfo->rti_ifaaddr != NULL &&
  718              !sa_equal(rtinfo->rti_ifaaddr, rt->rt_ifa->ifa_addr))) {
  719                 error = rt_getifa(rtinfo);
  720                 if (error != 0)
  721                         goto done;
  722         }
  723         if (rtinfo->rti_gateway != NULL) {
  724                 /*
  725                  * We only need to generate rtmsg upon the
  726                  * first route to be changed.
  727                  */
  728                 error = rt_setgate(rt, rt_key(rt), rtinfo->rti_gateway,
  729                         found_cnt == 1 ? RTL_REPORTMSG : RTL_DONTREPORT);
  730                 if (error != 0)
  731                         goto done;
  732         }
  733         if ((ifa = rtinfo->rti_ifa) != NULL) {
  734                 struct ifaddr *oifa = rt->rt_ifa;
  735 
  736                 if (oifa != ifa) {
  737                         if (oifa && oifa->ifa_rtrequest)
  738                                 oifa->ifa_rtrequest(RTM_DELETE, rt);
  739                         IFAFREE(rt->rt_ifa);
  740                         IFAREF(ifa);
  741                         rt->rt_ifa = ifa;
  742                         rt->rt_ifp = rtinfo->rti_ifp;
  743                 }
  744         }
  745         rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &rt->rt_rmx);
  746         if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
  747                 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt);
  748         if (rtinfo->rti_genmask != NULL) {
  749                 rt->rt_genmask = rtmask_purelookup(rtinfo->rti_genmask);
  750                 if (rt->rt_genmask == NULL) {
  751                         /*
  752                          * This should not happen, since we
  753                          * have already installed genmask
  754                          * on each CPU before we reach here.
  755                          */
  756                         panic("genmask is gone!?");
  757                 }
  758         }
  759         rtm->rtm_index = rt->rt_ifp->if_index;
  760 done:
  761         return error;
  762 }
  763 
  764 static int
  765 route_output_lock_callback(int cmd, struct rt_addrinfo *rtinfo,
  766                            struct rtentry *rt, void *arg,
  767                            int found_cnt __unused)
  768 {
  769         struct rt_msghdr *rtm = arg;
  770 
  771         rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
  772         rt->rt_rmx.rmx_locks |=
  773                 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
  774         return 0;
  775 }
  776 
  777 static void
  778 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_metrics *out)
  779 {
  780 #define setmetric(flag, elt) if (which & (flag)) out->elt = in->elt;
  781         setmetric(RTV_RPIPE, rmx_recvpipe);
  782         setmetric(RTV_SPIPE, rmx_sendpipe);
  783         setmetric(RTV_SSTHRESH, rmx_ssthresh);
  784         setmetric(RTV_RTT, rmx_rtt);
  785         setmetric(RTV_RTTVAR, rmx_rttvar);
  786         setmetric(RTV_HOPCOUNT, rmx_hopcount);
  787         setmetric(RTV_MTU, rmx_mtu);
  788         setmetric(RTV_EXPIRE, rmx_expire);
  789         setmetric(RTV_MSL, rmx_msl);
  790         setmetric(RTV_IWMAXSEGS, rmx_iwmaxsegs);
  791         setmetric(RTV_IWCAPSEGS, rmx_iwcapsegs);
  792 #undef setmetric
  793 }
  794 
  795 #define ROUNDUP(a) \
  796         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
  797 
  798 /*
  799  * Extract the addresses of the passed sockaddrs.
  800  * Do a little sanity checking so as to avoid bad memory references.
  801  * This data is derived straight from userland.
  802  */
  803 static int
  804 rt_xaddrs(char *cp, char *cplim, struct rt_addrinfo *rtinfo)
  805 {
  806         struct sockaddr *sa;
  807         int i;
  808 
  809         for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
  810                 if ((rtinfo->rti_addrs & (1 << i)) == 0)
  811                         continue;
  812                 sa = (struct sockaddr *)cp;
  813                 /*
  814                  * It won't fit.
  815                  */
  816                 if ((cp + sa->sa_len) > cplim) {
  817                         return (EINVAL);
  818                 }
  819 
  820                 /*
  821                  * There are no more...  Quit now.
  822                  * If there are more bits, they are in error.
  823                  * I've seen this.  route(1) can evidently generate these. 
  824                  * This causes kernel to core dump.
  825                  * For compatibility, if we see this, point to a safe address.
  826                  */
  827                 if (sa->sa_len == 0) {
  828                         static struct sockaddr sa_zero = {
  829                                 sizeof sa_zero, AF_INET,
  830                         };
  831 
  832                         rtinfo->rti_info[i] = &sa_zero;
  833                         kprintf("rtsock: received more addr bits than sockaddrs.\n");
  834                         return (0); /* should be EINVAL but for compat */
  835                 }
  836 
  837                 /* Accept the sockaddr. */
  838                 rtinfo->rti_info[i] = sa;
  839                 cp += ROUNDUP(sa->sa_len);
  840         }
  841         return (0);
  842 }
  843 
  844 static int
  845 rt_msghdrsize(int type)
  846 {
  847         switch (type) {
  848         case RTM_DELADDR:
  849         case RTM_NEWADDR:
  850                 return sizeof(struct ifa_msghdr);
  851         case RTM_DELMADDR:
  852         case RTM_NEWMADDR:
  853                 return sizeof(struct ifma_msghdr);
  854         case RTM_IFINFO:
  855                 return sizeof(struct if_msghdr);
  856         case RTM_IFANNOUNCE:
  857         case RTM_IEEE80211:
  858                 return sizeof(struct if_announcemsghdr);
  859         default:
  860                 return sizeof(struct rt_msghdr);
  861         }
  862 }
  863 
  864 static int
  865 rt_msgsize(int type, struct rt_addrinfo *rtinfo)
  866 {
  867         int len, i;
  868 
  869         len = rt_msghdrsize(type);
  870         for (i = 0; i < RTAX_MAX; i++) {
  871                 if (rtinfo->rti_info[i] != NULL)
  872                         len += ROUNDUP(rtinfo->rti_info[i]->sa_len);
  873         }
  874         len = ALIGN(len);
  875         return len;
  876 }
  877 
  878 /*
  879  * Build a routing message in a buffer.
  880  * Copy the addresses in the rtinfo->rti_info[] sockaddr array
  881  * to the end of the buffer after the message header.
  882  *
  883  * Set the rtinfo->rti_addrs bitmask of addresses present in rtinfo->rti_info[].
  884  * This side-effect can be avoided if we reorder the addrs bitmask field in all
  885  * the route messages to line up so we can set it here instead of back in the
  886  * calling routine.
  887  */
  888 static void
  889 rt_msg_buffer(int type, struct rt_addrinfo *rtinfo, void *buf, int msglen)
  890 {
  891         struct rt_msghdr *rtm;
  892         char *cp;
  893         int dlen, i;
  894 
  895         rtm = (struct rt_msghdr *) buf;
  896         rtm->rtm_version = RTM_VERSION;
  897         rtm->rtm_type = type;
  898         rtm->rtm_msglen = msglen;
  899 
  900         cp = (char *)buf + rt_msghdrsize(type);
  901         rtinfo->rti_addrs = 0;
  902         for (i = 0; i < RTAX_MAX; i++) {
  903                 struct sockaddr *sa;
  904 
  905                 if ((sa = rtinfo->rti_info[i]) == NULL)
  906                         continue;
  907                 rtinfo->rti_addrs |= (1 << i);
  908                 dlen = ROUNDUP(sa->sa_len);
  909                 bcopy(sa, cp, dlen);
  910                 cp += dlen;
  911         }
  912 }
  913 
  914 /*
  915  * Build a routing message in a mbuf chain.
  916  * Copy the addresses in the rtinfo->rti_info[] sockaddr array
  917  * to the end of the mbuf after the message header.
  918  *
  919  * Set the rtinfo->rti_addrs bitmask of addresses present in rtinfo->rti_info[].
  920  * This side-effect can be avoided if we reorder the addrs bitmask field in all
  921  * the route messages to line up so we can set it here instead of back in the
  922  * calling routine.
  923  */
  924 static struct mbuf *
  925 rt_msg_mbuf(int type, struct rt_addrinfo *rtinfo)
  926 {
  927         struct mbuf *m;
  928         struct rt_msghdr *rtm;
  929         int hlen, len;
  930         int i;
  931 
  932         hlen = rt_msghdrsize(type);
  933         KASSERT(hlen <= MCLBYTES, ("rt_msg_mbuf: hlen %d doesn't fit", hlen));
  934 
  935         m = m_getl(hlen, MB_DONTWAIT, MT_DATA, M_PKTHDR, NULL);
  936         if (m == NULL)
  937                 return (NULL);
  938         mbuftrackid(m, 32);
  939         m->m_pkthdr.len = m->m_len = hlen;
  940         m->m_pkthdr.rcvif = NULL;
  941         rtinfo->rti_addrs = 0;
  942         len = hlen;
  943         for (i = 0; i < RTAX_MAX; i++) {
  944                 struct sockaddr *sa;
  945                 int dlen;
  946 
  947                 if ((sa = rtinfo->rti_info[i]) == NULL)
  948                         continue;
  949                 rtinfo->rti_addrs |= (1 << i);
  950                 dlen = ROUNDUP(sa->sa_len);
  951                 m_copyback(m, len, dlen, (caddr_t)sa); /* can grow mbuf chain */
  952                 len += dlen;
  953         }
  954         if (m->m_pkthdr.len != len) { /* one of the m_copyback() calls failed */
  955                 m_freem(m);
  956                 return (NULL);
  957         }
  958         rtm = mtod(m, struct rt_msghdr *);
  959         bzero(rtm, hlen);
  960         rtm->rtm_msglen = len;
  961         rtm->rtm_version = RTM_VERSION;
  962         rtm->rtm_type = type;
  963         return (m);
  964 }
  965 
  966 /*
  967  * This routine is called to generate a message from the routing
  968  * socket indicating that a redirect has occurred, a routing lookup
  969  * has failed, or that a protocol has detected timeouts to a particular
  970  * destination.
  971  */
  972 void
  973 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error)
  974 {
  975         struct sockaddr *dst = rtinfo->rti_info[RTAX_DST];
  976         struct rt_msghdr *rtm;
  977         struct mbuf *m;
  978 
  979         if (route_cb.any_count == 0)
  980                 return;
  981         m = rt_msg_mbuf(type, rtinfo);
  982         if (m == NULL)
  983                 return;
  984         rtm = mtod(m, struct rt_msghdr *);
  985         rtm->rtm_flags = RTF_DONE | flags;
  986         rtm->rtm_errno = error;
  987         rtm->rtm_addrs = rtinfo->rti_addrs;
  988         rts_input(m, familyof(dst));
  989 }
  990 
  991 void
  992 rt_dstmsg(int type, struct sockaddr *dst, int error)
  993 {
  994         struct rt_msghdr *rtm;
  995         struct rt_addrinfo addrs;
  996         struct mbuf *m;
  997 
  998         if (route_cb.any_count == 0)
  999                 return;
 1000         bzero(&addrs, sizeof(struct rt_addrinfo));
 1001         addrs.rti_info[RTAX_DST] = dst;
 1002         m = rt_msg_mbuf(type, &addrs);
 1003         if (m == NULL)
 1004                 return;
 1005         rtm = mtod(m, struct rt_msghdr *);
 1006         rtm->rtm_flags = RTF_DONE;
 1007         rtm->rtm_errno = error;
 1008         rtm->rtm_addrs = addrs.rti_addrs;
 1009         rts_input(m, familyof(dst));
 1010 }
 1011 
 1012 /*
 1013  * This routine is called to generate a message from the routing
 1014  * socket indicating that the status of a network interface has changed.
 1015  */
 1016 void
 1017 rt_ifmsg(struct ifnet *ifp)
 1018 {
 1019         struct if_msghdr *ifm;
 1020         struct mbuf *m;
 1021         struct rt_addrinfo rtinfo;
 1022 
 1023         if (route_cb.any_count == 0)
 1024                 return;
 1025         bzero(&rtinfo, sizeof(struct rt_addrinfo));
 1026         m = rt_msg_mbuf(RTM_IFINFO, &rtinfo);
 1027         if (m == NULL)
 1028                 return;
 1029         ifm = mtod(m, struct if_msghdr *);
 1030         ifm->ifm_index = ifp->if_index;
 1031         ifm->ifm_flags = ifp->if_flags;
 1032         ifm->ifm_data = ifp->if_data;
 1033         ifm->ifm_addrs = 0;
 1034         rts_input(m, 0);
 1035 }
 1036 
 1037 static void
 1038 rt_ifamsg(int cmd, struct ifaddr *ifa)
 1039 {
 1040         struct ifa_msghdr *ifam;
 1041         struct rt_addrinfo rtinfo;
 1042         struct mbuf *m;
 1043         struct ifnet *ifp = ifa->ifa_ifp;
 1044 
 1045         bzero(&rtinfo, sizeof(struct rt_addrinfo));
 1046         rtinfo.rti_ifaaddr = ifa->ifa_addr;
 1047         rtinfo.rti_ifpaddr =
 1048                 TAILQ_FIRST(&ifp->if_addrheads[mycpuid])->ifa->ifa_addr;
 1049         rtinfo.rti_netmask = ifa->ifa_netmask;
 1050         rtinfo.rti_bcastaddr = ifa->ifa_dstaddr;
 1051 
 1052         m = rt_msg_mbuf(cmd, &rtinfo);
 1053         if (m == NULL)
 1054                 return;
 1055 
 1056         ifam = mtod(m, struct ifa_msghdr *);
 1057         ifam->ifam_index = ifp->if_index;
 1058         ifam->ifam_metric = ifa->ifa_metric;
 1059         ifam->ifam_flags = ifa->ifa_flags;
 1060         ifam->ifam_addrs = rtinfo.rti_addrs;
 1061 
 1062         rts_input(m, familyof(ifa->ifa_addr));
 1063 }
 1064 
 1065 void
 1066 rt_rtmsg(int cmd, struct rtentry *rt, struct ifnet *ifp, int error)
 1067 {
 1068         struct rt_msghdr *rtm;
 1069         struct rt_addrinfo rtinfo;
 1070         struct mbuf *m;
 1071         struct sockaddr *dst;
 1072 
 1073         if (rt == NULL)
 1074                 return;
 1075 
 1076         bzero(&rtinfo, sizeof(struct rt_addrinfo));
 1077         rtinfo.rti_dst = dst = rt_key(rt);
 1078         rtinfo.rti_gateway = rt->rt_gateway;
 1079         rtinfo.rti_netmask = rt_mask(rt);
 1080         if (ifp != NULL) {
 1081                 rtinfo.rti_ifpaddr =
 1082                 TAILQ_FIRST(&ifp->if_addrheads[mycpuid])->ifa->ifa_addr;
 1083         }
 1084         rtinfo.rti_ifaaddr = rt->rt_ifa->ifa_addr;
 1085 
 1086         m = rt_msg_mbuf(cmd, &rtinfo);
 1087         if (m == NULL)
 1088                 return;
 1089 
 1090         rtm = mtod(m, struct rt_msghdr *);
 1091         if (ifp != NULL)
 1092                 rtm->rtm_index = ifp->if_index;
 1093         rtm->rtm_flags |= rt->rt_flags;
 1094         rtm->rtm_errno = error;
 1095         rtm->rtm_addrs = rtinfo.rti_addrs;
 1096 
 1097         rts_input(m, familyof(dst));
 1098 }
 1099 
 1100 /*
 1101  * This is called to generate messages from the routing socket
 1102  * indicating a network interface has had addresses associated with it.
 1103  * if we ever reverse the logic and replace messages TO the routing
 1104  * socket indicate a request to configure interfaces, then it will
 1105  * be unnecessary as the routing socket will automatically generate
 1106  * copies of it.
 1107  */
 1108 void
 1109 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
 1110 {
 1111 #ifdef SCTP
 1112         /*
 1113          * notify the SCTP stack
 1114          * this will only get called when an address is added/deleted
 1115          * XXX pass the ifaddr struct instead if ifa->ifa_addr...
 1116          */
 1117         if (cmd == RTM_ADD)
 1118                 sctp_add_ip_address(ifa);
 1119         else if (cmd == RTM_DELETE)
 1120                 sctp_delete_ip_address(ifa);
 1121 #endif /* SCTP */
 1122 
 1123         if (route_cb.any_count == 0)
 1124                 return;
 1125 
 1126         if (cmd == RTM_ADD) {
 1127                 rt_ifamsg(RTM_NEWADDR, ifa);
 1128                 rt_rtmsg(RTM_ADD, rt, ifa->ifa_ifp, error);
 1129         } else {
 1130                 KASSERT((cmd == RTM_DELETE), ("unknown cmd %d", cmd));
 1131                 rt_rtmsg(RTM_DELETE, rt, ifa->ifa_ifp, error);
 1132                 rt_ifamsg(RTM_DELADDR, ifa);
 1133         }
 1134 }
 1135 
 1136 /*
 1137  * This is the analogue to the rt_newaddrmsg which performs the same
 1138  * function but for multicast group memberhips.  This is easier since
 1139  * there is no route state to worry about.
 1140  */
 1141 void
 1142 rt_newmaddrmsg(int cmd, struct ifmultiaddr *ifma)
 1143 {
 1144         struct rt_addrinfo rtinfo;
 1145         struct mbuf *m = NULL;
 1146         struct ifnet *ifp = ifma->ifma_ifp;
 1147         struct ifma_msghdr *ifmam;
 1148 
 1149         if (route_cb.any_count == 0)
 1150                 return;
 1151 
 1152         bzero(&rtinfo, sizeof(struct rt_addrinfo));
 1153         rtinfo.rti_ifaaddr = ifma->ifma_addr;
 1154         if (ifp != NULL && !TAILQ_EMPTY(&ifp->if_addrheads[mycpuid])) {
 1155                 rtinfo.rti_ifpaddr =
 1156                 TAILQ_FIRST(&ifp->if_addrheads[mycpuid])->ifa->ifa_addr;
 1157         }
 1158         /*
 1159          * If a link-layer address is present, present it as a ``gateway''
 1160          * (similarly to how ARP entries, e.g., are presented).
 1161          */
 1162         rtinfo.rti_gateway = ifma->ifma_lladdr;
 1163 
 1164         m = rt_msg_mbuf(cmd, &rtinfo);
 1165         if (m == NULL)
 1166                 return;
 1167 
 1168         ifmam = mtod(m, struct ifma_msghdr *);
 1169         ifmam->ifmam_index = ifp->if_index;
 1170         ifmam->ifmam_addrs = rtinfo.rti_addrs;
 1171 
 1172         rts_input(m, familyof(ifma->ifma_addr));
 1173 }
 1174 
 1175 static struct mbuf *
 1176 rt_makeifannouncemsg(struct ifnet *ifp, int type, int what,
 1177                      struct rt_addrinfo *info)
 1178 {
 1179         struct if_announcemsghdr *ifan;
 1180         struct mbuf *m;
 1181 
 1182         if (route_cb.any_count == 0)
 1183                 return NULL;
 1184 
 1185         bzero(info, sizeof(*info));
 1186         m = rt_msg_mbuf(type, info);
 1187         if (m == NULL)
 1188                 return NULL;
 1189 
 1190         ifan = mtod(m, struct if_announcemsghdr *);
 1191         ifan->ifan_index = ifp->if_index;
 1192         strlcpy(ifan->ifan_name, ifp->if_xname, sizeof ifan->ifan_name);
 1193         ifan->ifan_what = what;
 1194         return m;
 1195 }
 1196 
 1197 /*
 1198  * This is called to generate routing socket messages indicating
 1199  * IEEE80211 wireless events.
 1200  * XXX we piggyback on the RTM_IFANNOUNCE msg format in a clumsy way.
 1201  */
 1202 void
 1203 rt_ieee80211msg(struct ifnet *ifp, int what, void *data, size_t data_len)
 1204 {
 1205         struct rt_addrinfo info;
 1206         struct mbuf *m;
 1207 
 1208         m = rt_makeifannouncemsg(ifp, RTM_IEEE80211, what, &info);
 1209         if (m == NULL)
 1210                 return;
 1211 
 1212         /*
 1213          * Append the ieee80211 data.  Try to stick it in the
 1214          * mbuf containing the ifannounce msg; otherwise allocate
 1215          * a new mbuf and append.
 1216          *
 1217          * NB: we assume m is a single mbuf.
 1218          */
 1219         if (data_len > M_TRAILINGSPACE(m)) {
 1220                 /* XXX use m_getb(data_len, MB_DONTWAIT, MT_DATA, 0); */
 1221                 struct mbuf *n = m_get(MB_DONTWAIT, MT_DATA);
 1222                 if (n == NULL) {
 1223                         m_freem(m);
 1224                         return;
 1225                 }
 1226                 KKASSERT(data_len <= M_TRAILINGSPACE(n));
 1227                 bcopy(data, mtod(n, void *), data_len);
 1228                 n->m_len = data_len;
 1229                 m->m_next = n;
 1230         } else if (data_len > 0) {
 1231                 bcopy(data, mtod(m, u_int8_t *) + m->m_len, data_len);
 1232                 m->m_len += data_len;
 1233         }
 1234         mbuftrackid(m, 33);
 1235         if (m->m_flags & M_PKTHDR)
 1236                 m->m_pkthdr.len += data_len;
 1237         mtod(m, struct if_announcemsghdr *)->ifan_msglen += data_len;
 1238         rts_input(m, 0);
 1239 }
 1240 
 1241 /*
 1242  * This is called to generate routing socket messages indicating
 1243  * network interface arrival and departure.
 1244  */
 1245 void
 1246 rt_ifannouncemsg(struct ifnet *ifp, int what)
 1247 {
 1248         struct rt_addrinfo addrinfo;
 1249         struct mbuf *m;
 1250 
 1251         m = rt_makeifannouncemsg(ifp, RTM_IFANNOUNCE, what, &addrinfo);
 1252         if (m != NULL)
 1253                 rts_input(m, 0);
 1254 }
 1255 
 1256 static int
 1257 resizewalkarg(struct walkarg *w, int len)
 1258 {
 1259         void *newptr;
 1260 
 1261         newptr = kmalloc(len, M_RTABLE, M_INTWAIT | M_NULLOK);
 1262         if (newptr == NULL)
 1263                 return (ENOMEM);
 1264         if (w->w_tmem != NULL)
 1265                 kfree(w->w_tmem, M_RTABLE);
 1266         w->w_tmem = newptr;
 1267         w->w_tmemsize = len;
 1268         return (0);
 1269 }
 1270 
 1271 /*
 1272  * This is used in dumping the kernel table via sysctl().
 1273  */
 1274 int
 1275 sysctl_dumpentry(struct radix_node *rn, void *vw)
 1276 {
 1277         struct walkarg *w = vw;
 1278         struct rtentry *rt = (struct rtentry *)rn;
 1279         struct rt_addrinfo rtinfo;
 1280         int error, msglen;
 1281 
 1282         if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
 1283                 return 0;
 1284 
 1285         bzero(&rtinfo, sizeof(struct rt_addrinfo));
 1286         rtinfo.rti_dst = rt_key(rt);
 1287         rtinfo.rti_gateway = rt->rt_gateway;
 1288         rtinfo.rti_netmask = rt_mask(rt);
 1289         rtinfo.rti_genmask = rt->rt_genmask;
 1290         if (rt->rt_ifp != NULL) {
 1291                 rtinfo.rti_ifpaddr =
 1292                 TAILQ_FIRST(&rt->rt_ifp->if_addrheads[mycpuid])->ifa->ifa_addr;
 1293                 rtinfo.rti_ifaaddr = rt->rt_ifa->ifa_addr;
 1294                 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
 1295                         rtinfo.rti_bcastaddr = rt->rt_ifa->ifa_dstaddr;
 1296         }
 1297         msglen = rt_msgsize(RTM_GET, &rtinfo);
 1298         if (w->w_tmemsize < msglen && resizewalkarg(w, msglen) != 0)
 1299                 return (ENOMEM);
 1300         rt_msg_buffer(RTM_GET, &rtinfo, w->w_tmem, msglen);
 1301         if (w->w_req != NULL) {
 1302                 struct rt_msghdr *rtm = w->w_tmem;
 1303 
 1304                 rtm->rtm_flags = rt->rt_flags;
 1305                 rtm->rtm_use = rt->rt_use;
 1306                 rtm->rtm_rmx = rt->rt_rmx;
 1307                 rtm->rtm_index = rt->rt_ifp->if_index;
 1308                 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
 1309                 rtm->rtm_addrs = rtinfo.rti_addrs;
 1310                 error = SYSCTL_OUT(w->w_req, rtm, msglen);
 1311                 return (error);
 1312         }
 1313         return (0);
 1314 }
 1315 
 1316 static void
 1317 ifnet_compute_stats(struct ifnet *ifp)
 1318 {
 1319         IFNET_STAT_GET(ifp, ipackets, ifp->if_ipackets);
 1320         IFNET_STAT_GET(ifp, ierrors, ifp->if_ierrors);
 1321         IFNET_STAT_GET(ifp, opackets, ifp->if_opackets);
 1322         IFNET_STAT_GET(ifp, collisions, ifp->if_collisions);
 1323         IFNET_STAT_GET(ifp, ibytes, ifp->if_ibytes);
 1324         IFNET_STAT_GET(ifp, obytes, ifp->if_obytes);
 1325         IFNET_STAT_GET(ifp, imcasts, ifp->if_imcasts);
 1326         IFNET_STAT_GET(ifp, omcasts, ifp->if_omcasts);
 1327         IFNET_STAT_GET(ifp, iqdrops, ifp->if_iqdrops);
 1328         IFNET_STAT_GET(ifp, noproto, ifp->if_noproto);
 1329 }
 1330 
 1331 static int
 1332 sysctl_iflist(int af, struct walkarg *w)
 1333 {
 1334         struct ifnet *ifp;
 1335         struct rt_addrinfo rtinfo;
 1336         int msglen, error;
 1337 
 1338         bzero(&rtinfo, sizeof(struct rt_addrinfo));
 1339         TAILQ_FOREACH(ifp, &ifnet, if_link) {
 1340                 struct ifaddr_container *ifac;
 1341                 struct ifaddr *ifa;
 1342 
 1343                 if (w->w_arg && w->w_arg != ifp->if_index)
 1344                         continue;
 1345                 ifac = TAILQ_FIRST(&ifp->if_addrheads[mycpuid]);
 1346                 ifa = ifac->ifa;
 1347                 rtinfo.rti_ifpaddr = ifa->ifa_addr;
 1348                 msglen = rt_msgsize(RTM_IFINFO, &rtinfo);
 1349                 if (w->w_tmemsize < msglen && resizewalkarg(w, msglen) != 0)
 1350                         return (ENOMEM);
 1351                 rt_msg_buffer(RTM_IFINFO, &rtinfo, w->w_tmem, msglen);
 1352                 rtinfo.rti_ifpaddr = NULL;
 1353                 if (w->w_req != NULL && w->w_tmem != NULL) {
 1354                         struct if_msghdr *ifm = w->w_tmem;
 1355 
 1356                         ifm->ifm_index = ifp->if_index;
 1357                         ifm->ifm_flags = ifp->if_flags;
 1358                         ifnet_compute_stats(ifp);
 1359                         ifm->ifm_data = ifp->if_data;
 1360                         ifm->ifm_addrs = rtinfo.rti_addrs;
 1361                         error = SYSCTL_OUT(w->w_req, ifm, msglen);
 1362                         if (error)
 1363                                 return (error);
 1364                 }
 1365                 while ((ifac = TAILQ_NEXT(ifac, ifa_link)) != NULL) {
 1366                         ifa = ifac->ifa;
 1367 
 1368                         if (af && af != ifa->ifa_addr->sa_family)
 1369                                 continue;
 1370                         if (curproc->p_ucred->cr_prison &&
 1371                             prison_if(curproc->p_ucred, ifa->ifa_addr))
 1372                                 continue;
 1373                         rtinfo.rti_ifaaddr = ifa->ifa_addr;
 1374                         rtinfo.rti_netmask = ifa->ifa_netmask;
 1375                         rtinfo.rti_bcastaddr = ifa->ifa_dstaddr;
 1376                         msglen = rt_msgsize(RTM_NEWADDR, &rtinfo);
 1377                         if (w->w_tmemsize < msglen &&
 1378                             resizewalkarg(w, msglen) != 0)
 1379                                 return (ENOMEM);
 1380                         rt_msg_buffer(RTM_NEWADDR, &rtinfo, w->w_tmem, msglen);
 1381                         if (w->w_req != NULL) {
 1382                                 struct ifa_msghdr *ifam = w->w_tmem;
 1383 
 1384                                 ifam->ifam_index = ifa->ifa_ifp->if_index;
 1385                                 ifam->ifam_flags = ifa->ifa_flags;
 1386                                 ifam->ifam_metric = ifa->ifa_metric;
 1387                                 ifam->ifam_addrs = rtinfo.rti_addrs;
 1388                                 error = SYSCTL_OUT(w->w_req, w->w_tmem, msglen);
 1389                                 if (error)
 1390                                         return (error);
 1391                         }
 1392                 }
 1393                 rtinfo.rti_netmask = NULL;
 1394                 rtinfo.rti_ifaaddr = NULL;
 1395                 rtinfo.rti_bcastaddr = NULL;
 1396         }
 1397         return (0);
 1398 }
 1399 
 1400 static int
 1401 sysctl_rtsock(SYSCTL_HANDLER_ARGS)
 1402 {
 1403         int     *name = (int *)arg1;
 1404         u_int   namelen = arg2;
 1405         struct radix_node_head *rnh;
 1406         int     i, error = EINVAL;
 1407         int     origcpu;
 1408         u_char  af;
 1409         struct  walkarg w;
 1410 
 1411         name ++;
 1412         namelen--;
 1413         if (req->newptr)
 1414                 return (EPERM);
 1415         if (namelen != 3 && namelen != 4)
 1416                 return (EINVAL);
 1417         af = name[0];
 1418         bzero(&w, sizeof w);
 1419         w.w_op = name[1];
 1420         w.w_arg = name[2];
 1421         w.w_req = req;
 1422 
 1423         /*
 1424          * Optional third argument specifies cpu, used primarily for
 1425          * debugging the route table.
 1426          */
 1427         if (namelen == 4) {
 1428                 if (name[3] < 0 || name[3] >= ncpus)
 1429                         return (EINVAL);
 1430                 origcpu = mycpuid;
 1431                 lwkt_migratecpu(name[3]);
 1432         } else {
 1433                 origcpu = -1;
 1434         }
 1435         crit_enter();
 1436         switch (w.w_op) {
 1437         case NET_RT_DUMP:
 1438         case NET_RT_FLAGS:
 1439                 for (i = 1; i <= AF_MAX; i++)
 1440                         if ((rnh = rt_tables[mycpuid][i]) &&
 1441                             (af == 0 || af == i) &&
 1442                             (error = rnh->rnh_walktree(rnh,
 1443                                                        sysctl_dumpentry, &w)))
 1444                                 break;
 1445                 break;
 1446 
 1447         case NET_RT_IFLIST:
 1448                 error = sysctl_iflist(af, &w);
 1449         }
 1450         crit_exit();
 1451         if (w.w_tmem != NULL)
 1452                 kfree(w.w_tmem, M_RTABLE);
 1453         if (origcpu >= 0)
 1454                 lwkt_migratecpu(origcpu);
 1455         return (error);
 1456 }
 1457 
 1458 SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, "");
 1459 
 1460 /*
 1461  * Definitions of protocols supported in the ROUTE domain.
 1462  */
 1463 
 1464 static struct domain routedomain;               /* or at least forward */
 1465 
 1466 static struct protosw routesw[] = {
 1467     {
 1468         .pr_type = SOCK_RAW,
 1469         .pr_domain = &routedomain,
 1470         .pr_protocol = 0,
 1471         .pr_flags = PR_ATOMIC|PR_ADDR,
 1472         .pr_input = NULL,
 1473         .pr_output = route_output,
 1474         .pr_ctlinput = raw_ctlinput,
 1475         .pr_ctloutput = NULL,
 1476         .pr_ctlport = cpu0_ctlport,
 1477 
 1478         .pr_init = raw_init,
 1479         .pr_usrreqs = &route_usrreqs
 1480     }
 1481 };
 1482 
 1483 static struct domain routedomain = {
 1484         PF_ROUTE, "route", NULL, NULL, NULL,
 1485         routesw, &routesw[(sizeof routesw)/(sizeof routesw[0])],
 1486 };
 1487 
 1488 DOMAIN_SET(route);
 1489 

Cache object: caf78eb668ef473f37767c0e41f69613


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.