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 /*      $NetBSD: rtsock.c,v 1.91 2006/11/13 19:16:01 dyoung Exp $       */
    2 
    3 /*
    4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    5  * All rights reserved.
    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 project nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Copyright (c) 1988, 1991, 1993
   34  *      The Regents of the University of California.  All rights reserved.
   35  *
   36  * Redistribution and use in source and binary forms, with or without
   37  * modification, are permitted provided that the following conditions
   38  * are met:
   39  * 1. Redistributions of source code must retain the above copyright
   40  *    notice, this list of conditions and the following disclaimer.
   41  * 2. Redistributions in binary form must reproduce the above copyright
   42  *    notice, this list of conditions and the following disclaimer in the
   43  *    documentation and/or other materials provided with the distribution.
   44  * 3. Neither the name of the University nor the names of its contributors
   45  *    may be used to endorse or promote products derived from this software
   46  *    without specific prior written permission.
   47  *
   48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   58  * SUCH DAMAGE.
   59  *
   60  *      @(#)rtsock.c    8.7 (Berkeley) 10/12/95
   61  */
   62 
   63 #include <sys/cdefs.h>
   64 __KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.91 2006/11/13 19:16:01 dyoung Exp $");
   65 
   66 #include "opt_inet.h"
   67 
   68 #include <sys/param.h>
   69 #include <sys/systm.h>
   70 #include <sys/proc.h>
   71 #include <sys/mbuf.h>
   72 #include <sys/socket.h>
   73 #include <sys/socketvar.h>
   74 #include <sys/domain.h>
   75 #include <sys/protosw.h>
   76 #include <sys/sysctl.h>
   77 #include <sys/kauth.h>
   78 #ifdef RTSOCK_DEBUG
   79 #include <netinet/in.h>
   80 #endif /* RTSOCK_DEBUG */
   81 
   82 #include <net/if.h>
   83 #include <net/route.h>
   84 #include <net/raw_cb.h>
   85 
   86 #include <machine/stdarg.h>
   87 
   88 DOMAIN_DEFINE(routedomain);     /* forward declare and add to link set */
   89 
   90 struct  sockaddr route_dst = { .sa_len = 2, .sa_family = PF_ROUTE, };
   91 struct  sockaddr route_src = { .sa_len = 2, .sa_family = PF_ROUTE, };
   92 struct  sockproto route_proto = { .sp_family = PF_ROUTE, };
   93 
   94 struct walkarg {
   95         int     w_op;
   96         int     w_arg;
   97         int     w_given;
   98         int     w_needed;
   99         caddr_t w_where;
  100         int     w_tmemsize;
  101         int     w_tmemneeded;
  102         caddr_t w_tmem;
  103 };
  104 
  105 static struct mbuf *rt_msg1(int, struct rt_addrinfo *, caddr_t, int);
  106 static int rt_msg2(int, struct rt_addrinfo *, caddr_t, struct walkarg *, int *);
  107 static int rt_xaddrs(u_char, const char *, const char *, struct rt_addrinfo *);
  108 static struct mbuf *rt_makeifannouncemsg(struct ifnet *, int, int,
  109     struct rt_addrinfo *);
  110 static int sysctl_dumpentry(struct radix_node *, void *);
  111 static int sysctl_iflist(int, struct walkarg *, int);
  112 static int sysctl_rtable(SYSCTLFN_PROTO);
  113 static inline void rt_adjustcount(int, int);
  114 
  115 /* Sleazy use of local variables throughout file, warning!!!! */
  116 #define dst     info.rti_info[RTAX_DST]
  117 #define gate    info.rti_info[RTAX_GATEWAY]
  118 #define netmask info.rti_info[RTAX_NETMASK]
  119 #define genmask info.rti_info[RTAX_GENMASK]
  120 #define ifpaddr info.rti_info[RTAX_IFP]
  121 #define ifaaddr info.rti_info[RTAX_IFA]
  122 #define brdaddr info.rti_info[RTAX_BRD]
  123 
  124 static inline void
  125 rt_adjustcount(int af, int cnt)
  126 {
  127         route_cb.any_count += cnt;
  128         switch (af) {
  129         case AF_INET:
  130                 route_cb.ip_count += cnt;
  131                 return;
  132 #ifdef INET6
  133         case AF_INET6:
  134                 route_cb.ip6_count += cnt;
  135                 return;
  136 #endif
  137         case AF_IPX:
  138                 route_cb.ipx_count += cnt;
  139                 return;
  140         case AF_NS:
  141                 route_cb.ns_count += cnt;
  142                 return;
  143         case AF_ISO:
  144                 route_cb.iso_count += cnt;
  145                 return;
  146         }
  147 }
  148 
  149 /*ARGSUSED*/
  150 int
  151 route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
  152         struct mbuf *control, struct lwp *l)
  153 {
  154         int error = 0;
  155         struct rawcb *rp = sotorawcb(so);
  156         int s;
  157 
  158         if (req == PRU_ATTACH) {
  159                 MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
  160                 if ((so->so_pcb = rp) != NULL)
  161                         memset(so->so_pcb, 0, sizeof(*rp));
  162 
  163         }
  164         if (req == PRU_DETACH && rp)
  165                 rt_adjustcount(rp->rcb_proto.sp_protocol, -1);
  166         s = splsoftnet();
  167 
  168         /*
  169          * Don't call raw_usrreq() in the attach case, because
  170          * we want to allow non-privileged processes to listen on
  171          * and send "safe" commands to the routing socket.
  172          */
  173         if (req == PRU_ATTACH) {
  174                 if (l == 0)
  175                         error = EACCES;
  176                 else
  177                         error = raw_attach(so, (int)(long)nam);
  178         } else
  179                 error = raw_usrreq(so, req, m, nam, control, l);
  180 
  181         rp = sotorawcb(so);
  182         if (req == PRU_ATTACH && rp) {
  183                 if (error) {
  184                         free((caddr_t)rp, M_PCB);
  185                         splx(s);
  186                         return (error);
  187                 }
  188                 rt_adjustcount(rp->rcb_proto.sp_protocol, 1);
  189                 rp->rcb_laddr = &route_src;
  190                 rp->rcb_faddr = &route_dst;
  191                 soisconnected(so);
  192                 so->so_options |= SO_USELOOPBACK;
  193         }
  194         splx(s);
  195         return (error);
  196 }
  197 
  198 /*ARGSUSED*/
  199 int
  200 route_output(struct mbuf *m, ...)
  201 {
  202         struct rt_msghdr *rtm = 0;
  203         struct radix_node *rn = 0;
  204         struct rtentry *rt = 0;
  205         struct rtentry *saved_nrt = 0;
  206         struct radix_node_head *rnh;
  207         struct rt_addrinfo info;
  208         int len, error = 0;
  209         struct ifnet *ifp = 0;
  210         struct ifaddr *ifa = 0;
  211         struct socket *so;
  212         va_list ap;
  213         sa_family_t family;
  214 
  215         va_start(ap, m);
  216         so = va_arg(ap, struct socket *);
  217         va_end(ap);
  218 
  219 #define senderr(e) do { error = e; goto flush;} while (/*CONSTCOND*/ 0)
  220         if (m == 0 || ((m->m_len < sizeof(int32_t)) &&
  221            (m = m_pullup(m, sizeof(int32_t))) == 0))
  222                 return (ENOBUFS);
  223         if ((m->m_flags & M_PKTHDR) == 0)
  224                 panic("route_output");
  225         len = m->m_pkthdr.len;
  226         if (len < sizeof(*rtm) ||
  227             len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
  228                 dst = 0;
  229                 senderr(EINVAL);
  230         }
  231         R_Malloc(rtm, struct rt_msghdr *, len);
  232         if (rtm == 0) {
  233                 dst = 0;
  234                 senderr(ENOBUFS);
  235         }
  236         m_copydata(m, 0, len, (caddr_t)rtm);
  237         if (rtm->rtm_version != RTM_VERSION) {
  238                 dst = 0;
  239                 senderr(EPROTONOSUPPORT);
  240         }
  241         rtm->rtm_pid = curproc->p_pid;
  242         memset(&info, 0, sizeof(info));
  243         info.rti_addrs = rtm->rtm_addrs;
  244         if (rt_xaddrs(rtm->rtm_type, (caddr_t)(rtm + 1), len + (caddr_t)rtm, &info))
  245                 senderr(EINVAL);
  246         info.rti_flags = rtm->rtm_flags;
  247 #ifdef RTSOCK_DEBUG
  248         if (dst->sa_family == AF_INET) {
  249                 printf("%s: extracted dst %s\n", __func__,
  250                     inet_ntoa(((const struct sockaddr_in *)dst)->sin_addr));
  251         }
  252 #endif /* RTSOCK_DEBUG */
  253         if (dst == 0 || (dst->sa_family >= AF_MAX))
  254                 senderr(EINVAL);
  255         if (gate != 0 && (gate->sa_family >= AF_MAX))
  256                 senderr(EINVAL);
  257         if (genmask) {
  258                 struct radix_node *t;
  259                 t = rn_addmask(genmask, 0, 1);
  260                 if (t && genmask->sa_len >= ((const struct sockaddr *)t->rn_key)->sa_len &&
  261                     Bcmp((const char *const *)genmask + 1, (const char *const *)t->rn_key + 1,
  262                     ((const struct sockaddr *)t->rn_key)->sa_len) - 1)
  263                         genmask = (const struct sockaddr *)(t->rn_key);
  264                 else
  265                         senderr(ENOBUFS);
  266         }
  267 
  268         /*
  269          * Verify that the caller has the appropriate privilege; RTM_GET
  270          * is the only operation the non-superuser is allowed.
  271          */
  272         if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_ROUTE,
  273             0, rtm, NULL, NULL) != 0)
  274                 senderr(EACCES);
  275 
  276         switch (rtm->rtm_type) {
  277 
  278         case RTM_ADD:
  279                 if (gate == 0)
  280                         senderr(EINVAL);
  281                 error = rtrequest1(rtm->rtm_type, &info, &saved_nrt);
  282                 if (error == 0 && saved_nrt) {
  283                         rt_setmetrics(rtm->rtm_inits,
  284                             &rtm->rtm_rmx, &saved_nrt->rt_rmx);
  285                         saved_nrt->rt_refcnt--;
  286                         saved_nrt->rt_genmask = genmask;
  287                 }
  288                 break;
  289 
  290         case RTM_DELETE:
  291                 error = rtrequest1(rtm->rtm_type, &info, &saved_nrt);
  292                 if (error == 0) {
  293                         (rt = saved_nrt)->rt_refcnt++;
  294                         goto report;
  295                 }
  296                 break;
  297 
  298         case RTM_GET:
  299         case RTM_CHANGE:
  300         case RTM_LOCK:
  301                 if ((rnh = rt_tables[dst->sa_family]) == 0) {
  302                         senderr(EAFNOSUPPORT);
  303                 }
  304                 rn = rnh->rnh_lookup(dst, netmask, rnh);
  305                 if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) {
  306                         senderr(ESRCH);
  307                 }
  308                 rt = (struct rtentry *)rn;
  309                 rt->rt_refcnt++;
  310                 if (rtm->rtm_type != RTM_GET) {/* XXX: too grotty */
  311                         struct radix_node *rnn;
  312                         extern struct radix_node_head *mask_rnhead;
  313 
  314                         if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0)
  315                                 senderr(ESRCH);
  316                         if (netmask && (rnn = rn_search(netmask,
  317                                             mask_rnhead->rnh_treetop)))
  318                                 netmask = (const struct sockaddr *)rnn->rn_key;
  319                         for (rnn = rt->rt_nodes; rnn; rnn = rnn->rn_dupedkey)
  320                                 if (netmask == (const struct sockaddr *)rnn->rn_mask)
  321                                         break;
  322                         if (rnn == 0)
  323                                 senderr(ETOOMANYREFS);
  324                         rt = (struct rtentry *)rnn;
  325                 }
  326 
  327                 switch (rtm->rtm_type) {
  328                 case RTM_GET:
  329                 report:
  330                         dst = rt_key(rt);
  331                         gate = rt->rt_gateway;
  332                         netmask = rt_mask(rt);
  333                         genmask = rt->rt_genmask;
  334                         if ((rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) == 0)
  335                                 ;
  336                         else if ((ifp = rt->rt_ifp) != NULL) {
  337                                 const struct ifaddr *rtifa;
  338                                 ifpaddr = TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
  339                                 /* rtifa used to be simply rt->rt_ifa.
  340                                  * If rt->rt_ifa != NULL, then
  341                                  * rt_get_ifa() != NULL.  So this
  342                                  * ought to still be safe. --dyoung
  343                                  */
  344                                 rtifa = rt_get_ifa(rt);
  345                                 ifaaddr = rtifa->ifa_addr;
  346 #ifdef RTSOCK_DEBUG
  347                                 if (ifaaddr->sa_family == AF_INET) {
  348                                         printf("%s: copying out RTAX_IFA %s ",
  349                                             __func__,
  350                                             inet_ntoa(((const struct sockaddr_in *)ifaaddr)->sin_addr));
  351                                         printf("for dst %s ifa_getifa %p ifa_seqno %p\n",
  352                                             inet_ntoa(((const struct sockaddr_in *)dst)->sin_addr),
  353                                             (void *)rtifa->ifa_getifa, rtifa->ifa_seqno);
  354                                 }
  355 #endif /* RTSOCK_DEBUG */
  356                                 if (ifp->if_flags & IFF_POINTOPOINT)
  357                                         brdaddr = rtifa->ifa_dstaddr;
  358                                 else
  359                                         brdaddr = 0;
  360                                 rtm->rtm_index = ifp->if_index;
  361                         } else {
  362                                 ifpaddr = 0;
  363                                 ifaaddr = 0;
  364                         }
  365                         (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)0,
  366                             (struct walkarg *)0, &len);
  367                         if (len > rtm->rtm_msglen) {
  368                                 struct rt_msghdr *new_rtm;
  369                                 R_Malloc(new_rtm, struct rt_msghdr *, len);
  370                                 if (new_rtm == 0)
  371                                         senderr(ENOBUFS);
  372                                 Bcopy(rtm, new_rtm, rtm->rtm_msglen);
  373                                 Free(rtm); rtm = new_rtm;
  374                         }
  375                         (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm,
  376                             (struct walkarg *)0, 0);
  377                         rtm->rtm_flags = rt->rt_flags;
  378                         rtm->rtm_rmx = rt->rt_rmx;
  379                         rtm->rtm_addrs = info.rti_addrs;
  380                         break;
  381 
  382                 case RTM_CHANGE:
  383                         /*
  384                          * new gateway could require new ifaddr, ifp;
  385                          * flags may also be different; ifp may be specified
  386                          * by ll sockaddr when protocol address is ambiguous
  387                          */
  388                         if ((error = rt_getifa(&info)) != 0)
  389                                 senderr(error);
  390                         if (gate && rt_setgate(rt, rt_key(rt), gate))
  391                                 senderr(EDQUOT);
  392                         /* new gateway could require new ifaddr, ifp;
  393                            flags may also be different; ifp may be specified
  394                            by ll sockaddr when protocol address is ambiguous */
  395                         if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&
  396                             (ifp = ifa->ifa_ifp) && (ifaaddr || gate))
  397                                 ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
  398                                     ifp);
  399                         else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||
  400                             (gate && (ifa = ifa_ifwithroute(rt->rt_flags,
  401                             rt_key(rt), gate))))
  402                                 ifp = ifa->ifa_ifp;
  403                         if (ifa) {
  404                                 struct ifaddr *oifa = rt->rt_ifa;
  405                                 if (oifa != ifa) {
  406                                         if (oifa && oifa->ifa_rtrequest) {
  407                                                 oifa->ifa_rtrequest(RTM_DELETE,
  408                                                     rt, &info);
  409                                         }
  410                                         rt_replace_ifa(rt, ifa);
  411                                         rt->rt_ifp = ifp;
  412                                 }
  413                         }
  414                         rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
  415                             &rt->rt_rmx);
  416                         if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
  417                                 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info);
  418                         if (genmask)
  419                                 rt->rt_genmask = genmask;
  420                         /*
  421                          * Fall into
  422                          */
  423                 case RTM_LOCK:
  424                         rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
  425                         rt->rt_rmx.rmx_locks |=
  426                             (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
  427                         break;
  428                 }
  429                 break;
  430 
  431         default:
  432                 senderr(EOPNOTSUPP);
  433         }
  434 
  435 flush:
  436         if (rtm) {
  437                 if (error)
  438                         rtm->rtm_errno = error;
  439                 else
  440                         rtm->rtm_flags |= RTF_DONE;
  441         }
  442         family = dst ? dst->sa_family : 0;
  443         if (rt)
  444                 rtfree(rt);
  445     {
  446         struct rawcb *rp = 0;
  447         /*
  448          * Check to see if we don't want our own messages.
  449          */
  450         if ((so->so_options & SO_USELOOPBACK) == 0) {
  451                 if (route_cb.any_count <= 1) {
  452                         if (rtm)
  453                                 Free(rtm);
  454                         m_freem(m);
  455                         return (error);
  456                 }
  457                 /* There is another listener, so construct message */
  458                 rp = sotorawcb(so);
  459         }
  460         if (rtm) {
  461                 m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
  462                 if (m->m_pkthdr.len < rtm->rtm_msglen) {
  463                         m_freem(m);
  464                         m = NULL;
  465                 } else if (m->m_pkthdr.len > rtm->rtm_msglen)
  466                         m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
  467                 Free(rtm);
  468         }
  469         if (rp)
  470                 rp->rcb_proto.sp_family = 0; /* Avoid us */
  471         if (family)
  472                 route_proto.sp_protocol = family;
  473         if (m)
  474                 raw_input(m, &route_proto, &route_src, &route_dst);
  475         if (rp)
  476                 rp->rcb_proto.sp_family = PF_ROUTE;
  477     }
  478         return (error);
  479 }
  480 
  481 void
  482 rt_setmetrics(u_long which, const struct rt_metrics *in, struct rt_metrics *out)
  483 {
  484 #define metric(f, e) if (which & (f)) out->e = in->e;
  485         metric(RTV_RPIPE, rmx_recvpipe);
  486         metric(RTV_SPIPE, rmx_sendpipe);
  487         metric(RTV_SSTHRESH, rmx_ssthresh);
  488         metric(RTV_RTT, rmx_rtt);
  489         metric(RTV_RTTVAR, rmx_rttvar);
  490         metric(RTV_HOPCOUNT, rmx_hopcount);
  491         metric(RTV_MTU, rmx_mtu);
  492         metric(RTV_EXPIRE, rmx_expire);
  493 #undef metric
  494 }
  495 
  496 #define ROUNDUP(a) \
  497         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
  498 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
  499 
  500 static int
  501 rt_xaddrs(u_char rtmtype, const char *cp, const char *cplim, struct rt_addrinfo *rtinfo)
  502 {
  503         const struct sockaddr *sa = NULL;       /* Quell compiler warning */
  504         int i;
  505 
  506         for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
  507                 if ((rtinfo->rti_addrs & (1 << i)) == 0)
  508                         continue;
  509                 rtinfo->rti_info[i] = sa = (const struct sockaddr *)cp;
  510                 ADVANCE(cp, sa);
  511         }
  512 
  513         /* Check for extra addresses specified, except RTM_GET asking for interface info.  */
  514         if (rtmtype == RTM_GET) {
  515                 if (((rtinfo->rti_addrs & (~((1 << RTAX_IFP) | (1 << RTAX_IFA)))) & (~0 << i)) != 0)
  516                         return (1);
  517         } else {
  518                 if ((rtinfo->rti_addrs & (~0 << i)) != 0)
  519                         return (1);
  520         }
  521         /* Check for bad data length.  */
  522         if (cp != cplim) {
  523                 if (i == RTAX_NETMASK + 1 && sa &&
  524                     cp - ROUNDUP(sa->sa_len) + sa->sa_len == cplim)
  525                         /*
  526                          * The last sockaddr was netmask.
  527                          * We accept this for now for the sake of old
  528                          * binaries or third party softwares.
  529                          */
  530                         ;
  531                 else
  532                         return (1);
  533         }
  534         return (0);
  535 }
  536 
  537 static struct mbuf *
  538 rt_msg1(int type, struct rt_addrinfo *rtinfo, caddr_t data, int datalen)
  539 {
  540         struct rt_msghdr *rtm;
  541         struct mbuf *m;
  542         int i;
  543         const struct sockaddr *sa;
  544         int len, dlen;
  545 
  546         m = m_gethdr(M_DONTWAIT, MT_DATA);
  547         if (m == 0)
  548                 return (m);
  549         MCLAIM(m, &routedomain.dom_mowner);
  550         switch (type) {
  551 
  552         case RTM_DELADDR:
  553         case RTM_NEWADDR:
  554                 len = sizeof(struct ifa_msghdr);
  555                 break;
  556 
  557 #ifdef COMPAT_14
  558         case RTM_OIFINFO:
  559                 len = sizeof(struct if_msghdr14);
  560                 break;
  561 #endif
  562 
  563         case RTM_IFINFO:
  564                 len = sizeof(struct if_msghdr);
  565                 break;
  566 
  567         case RTM_IFANNOUNCE:
  568         case RTM_IEEE80211:
  569                 len = sizeof(struct if_announcemsghdr);
  570                 break;
  571 
  572         default:
  573                 len = sizeof(struct rt_msghdr);
  574         }
  575         if (len > MHLEN + MLEN)
  576                 panic("rt_msg1: message too long");
  577         else if (len > MHLEN) {
  578                 m->m_next = m_get(M_DONTWAIT, MT_DATA);
  579                 if (m->m_next == NULL) {
  580                         m_freem(m);
  581                         return (NULL);
  582                 }
  583                 MCLAIM(m->m_next, m->m_owner);
  584                 m->m_pkthdr.len = len;
  585                 m->m_len = MHLEN;
  586                 m->m_next->m_len = len - MHLEN;
  587         } else {
  588                 m->m_pkthdr.len = m->m_len = len;
  589         }
  590         m->m_pkthdr.rcvif = 0;
  591         m_copyback(m, 0, datalen, data);
  592         rtm = mtod(m, struct rt_msghdr *);
  593         for (i = 0; i < RTAX_MAX; i++) {
  594                 if ((sa = rtinfo->rti_info[i]) == NULL)
  595                         continue;
  596                 rtinfo->rti_addrs |= (1 << i);
  597                 dlen = ROUNDUP(sa->sa_len);
  598                 m_copyback(m, len, dlen, sa);
  599                 len += dlen;
  600         }
  601         if (m->m_pkthdr.len != len) {
  602                 m_freem(m);
  603                 return (NULL);
  604         }
  605         rtm->rtm_msglen = len;
  606         rtm->rtm_version = RTM_VERSION;
  607         rtm->rtm_type = type;
  608         return (m);
  609 }
  610 
  611 /*
  612  * rt_msg2
  613  *
  614  *       fills 'cp' or 'w'.w_tmem with the routing socket message and
  615  *              returns the length of the message in 'lenp'.
  616  *
  617  * if walkarg is 0, cp is expected to be 0 or a buffer large enough to hold
  618  *      the message
  619  * otherwise walkarg's w_needed is updated and if the user buffer is
  620  *      specified and w_needed indicates space exists the information is copied
  621  *      into the temp space (w_tmem). w_tmem is [re]allocated if necessary,
  622  *      if the allocation fails ENOBUFS is returned.
  623  */
  624 static int
  625 rt_msg2(int type, struct rt_addrinfo *rtinfo, caddr_t cp, struct walkarg *w,
  626         int *lenp)
  627 {
  628         int i;
  629         int len, dlen, second_time = 0;
  630         caddr_t cp0;
  631 
  632         rtinfo->rti_addrs = 0;
  633 again:
  634         switch (type) {
  635 
  636         case RTM_DELADDR:
  637         case RTM_NEWADDR:
  638                 len = sizeof(struct ifa_msghdr);
  639                 break;
  640 #ifdef COMPAT_14
  641         case RTM_OIFINFO:
  642                 len = sizeof(struct if_msghdr14);
  643                 break;
  644 #endif
  645 
  646         case RTM_IFINFO:
  647                 len = sizeof(struct if_msghdr);
  648                 break;
  649 
  650         default:
  651                 len = sizeof(struct rt_msghdr);
  652         }
  653         if ((cp0 = cp) != NULL)
  654                 cp += len;
  655         for (i = 0; i < RTAX_MAX; i++) {
  656                 const struct sockaddr *sa;
  657 
  658                 if ((sa = rtinfo->rti_info[i]) == 0)
  659                         continue;
  660                 rtinfo->rti_addrs |= (1 << i);
  661                 dlen = ROUNDUP(sa->sa_len);
  662                 if (cp) {
  663                         bcopy(sa, cp, (unsigned)dlen);
  664                         cp += dlen;
  665                 }
  666                 len += dlen;
  667         }
  668         if (cp == 0 && w != NULL && !second_time) {
  669                 struct walkarg *rw = w;
  670 
  671                 rw->w_needed += len;
  672                 if (rw->w_needed <= 0 && rw->w_where) {
  673                         if (rw->w_tmemsize < len) {
  674                                 if (rw->w_tmem)
  675                                         free(rw->w_tmem, M_RTABLE);
  676                                 rw->w_tmem = (caddr_t) malloc(len, M_RTABLE,
  677                                     M_NOWAIT);
  678                                 if (rw->w_tmem)
  679                                         rw->w_tmemsize = len;
  680                         }
  681                         if (rw->w_tmem) {
  682                                 cp = rw->w_tmem;
  683                                 second_time = 1;
  684                                 goto again;
  685                         } else {
  686                                 rw->w_tmemneeded = len;
  687                                 return (ENOBUFS);
  688                         }
  689                 }
  690         }
  691         if (cp) {
  692                 struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
  693 
  694                 rtm->rtm_version = RTM_VERSION;
  695                 rtm->rtm_type = type;
  696                 rtm->rtm_msglen = len;
  697         }
  698         if (lenp)
  699                 *lenp = len;
  700         return (0);
  701 }
  702 
  703 /*
  704  * This routine is called to generate a message from the routing
  705  * socket indicating that a redirect has occurred, a routing lookup
  706  * has failed, or that a protocol has detected timeouts to a particular
  707  * destination.
  708  */
  709 void
  710 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error)
  711 {
  712         struct rt_msghdr rtm;
  713         struct mbuf *m;
  714         const struct sockaddr *sa = rtinfo->rti_info[RTAX_DST];
  715 
  716         if (route_cb.any_count == 0)
  717                 return;
  718         memset(&rtm, 0, sizeof(rtm));
  719         rtm.rtm_flags = RTF_DONE | flags;
  720         rtm.rtm_errno = error;
  721         m = rt_msg1(type, rtinfo, (caddr_t)&rtm, sizeof(rtm));
  722         if (m == 0)
  723                 return;
  724         mtod(m, struct rt_msghdr *)->rtm_addrs = rtinfo->rti_addrs;
  725         route_proto.sp_protocol = sa ? sa->sa_family : 0;
  726         raw_input(m, &route_proto, &route_src, &route_dst);
  727 }
  728 
  729 /*
  730  * This routine is called to generate a message from the routing
  731  * socket indicating that the status of a network interface has changed.
  732  */
  733 void
  734 rt_ifmsg(struct ifnet *ifp)
  735 {
  736         struct if_msghdr ifm;
  737 #ifdef COMPAT_14
  738         struct if_msghdr14 oifm;
  739 #endif
  740         struct mbuf *m;
  741         struct rt_addrinfo info;
  742 
  743         if (route_cb.any_count == 0)
  744                 return;
  745         memset(&info, 0, sizeof(info));
  746         memset(&ifm, 0, sizeof(ifm));
  747         ifm.ifm_index = ifp->if_index;
  748         ifm.ifm_flags = ifp->if_flags;
  749         ifm.ifm_data = ifp->if_data;
  750         ifm.ifm_addrs = 0;
  751         m = rt_msg1(RTM_IFINFO, &info, (caddr_t)&ifm, sizeof(ifm));
  752         if (m == 0)
  753                 return;
  754         route_proto.sp_protocol = 0;
  755         raw_input(m, &route_proto, &route_src, &route_dst);
  756 #ifdef COMPAT_14
  757         memset(&info, 0, sizeof(info));
  758         memset(&oifm, 0, sizeof(oifm));
  759         oifm.ifm_index = ifp->if_index;
  760         oifm.ifm_flags = ifp->if_flags;
  761         oifm.ifm_data.ifi_type = ifp->if_data.ifi_type;
  762         oifm.ifm_data.ifi_addrlen = ifp->if_data.ifi_addrlen;
  763         oifm.ifm_data.ifi_hdrlen = ifp->if_data.ifi_hdrlen;
  764         oifm.ifm_data.ifi_mtu = ifp->if_data.ifi_mtu;
  765         oifm.ifm_data.ifi_metric = ifp->if_data.ifi_metric;
  766         oifm.ifm_data.ifi_baudrate = ifp->if_data.ifi_baudrate;
  767         oifm.ifm_data.ifi_ipackets = ifp->if_data.ifi_ipackets;
  768         oifm.ifm_data.ifi_ierrors = ifp->if_data.ifi_ierrors;
  769         oifm.ifm_data.ifi_opackets = ifp->if_data.ifi_opackets;
  770         oifm.ifm_data.ifi_oerrors = ifp->if_data.ifi_oerrors;
  771         oifm.ifm_data.ifi_collisions = ifp->if_data.ifi_collisions;
  772         oifm.ifm_data.ifi_ibytes = ifp->if_data.ifi_ibytes;
  773         oifm.ifm_data.ifi_obytes = ifp->if_data.ifi_obytes;
  774         oifm.ifm_data.ifi_imcasts = ifp->if_data.ifi_imcasts;
  775         oifm.ifm_data.ifi_omcasts = ifp->if_data.ifi_omcasts;
  776         oifm.ifm_data.ifi_iqdrops = ifp->if_data.ifi_iqdrops;
  777         oifm.ifm_data.ifi_noproto = ifp->if_data.ifi_noproto;
  778         oifm.ifm_data.ifi_lastchange = ifp->if_data.ifi_lastchange;
  779         oifm.ifm_addrs = 0;
  780         m = rt_msg1(RTM_OIFINFO, &info, (caddr_t)&oifm, sizeof(oifm));
  781         if (m == 0)
  782                 return;
  783         route_proto.sp_protocol = 0;
  784         raw_input(m, &route_proto, &route_src, &route_dst);
  785 #endif
  786 }
  787 
  788 /*
  789  * This is called to generate messages from the routing socket
  790  * indicating a network interface has had addresses associated with it.
  791  * if we ever reverse the logic and replace messages TO the routing
  792  * socket indicate a request to configure interfaces, then it will
  793  * be unnecessary as the routing socket will automatically generate
  794  * copies of it.
  795  */
  796 void
  797 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
  798 {
  799         struct rt_addrinfo info;
  800         struct sockaddr *sa = NULL;
  801         int pass;
  802         struct mbuf *m = NULL;
  803         struct ifnet *ifp = ifa->ifa_ifp;
  804 
  805         if (route_cb.any_count == 0)
  806                 return;
  807         for (pass = 1; pass < 3; pass++) {
  808                 memset(&info, 0, sizeof(info));
  809                 if ((cmd == RTM_ADD && pass == 1) ||
  810                     (cmd == RTM_DELETE && pass == 2)) {
  811                         struct ifa_msghdr ifam;
  812                         int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR;
  813 
  814                         ifaaddr = sa = ifa->ifa_addr;
  815                         ifpaddr = TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
  816                         netmask = ifa->ifa_netmask;
  817                         brdaddr = ifa->ifa_dstaddr;
  818                         memset(&ifam, 0, sizeof(ifam));
  819                         ifam.ifam_index = ifp->if_index;
  820                         ifam.ifam_metric = ifa->ifa_metric;
  821                         ifam.ifam_flags = ifa->ifa_flags;
  822                         m = rt_msg1(ncmd, &info, (caddr_t)&ifam, sizeof(ifam));
  823                         if (m == NULL)
  824                                 continue;
  825                         mtod(m, struct ifa_msghdr *)->ifam_addrs =
  826                             info.rti_addrs;
  827                 }
  828                 if ((cmd == RTM_ADD && pass == 2) ||
  829                     (cmd == RTM_DELETE && pass == 1)) {
  830                         struct rt_msghdr rtm;
  831 
  832                         if (rt == 0)
  833                                 continue;
  834                         netmask = rt_mask(rt);
  835                         dst = sa = rt_key(rt);
  836                         gate = rt->rt_gateway;
  837                         memset(&rtm, 0, sizeof(rtm));
  838                         rtm.rtm_index = ifp->if_index;
  839                         rtm.rtm_flags |= rt->rt_flags;
  840                         rtm.rtm_errno = error;
  841                         m = rt_msg1(cmd, &info, (caddr_t)&rtm, sizeof(rtm));
  842                         if (m == NULL)
  843                                 continue;
  844                         mtod(m, struct rt_msghdr *)->rtm_addrs = info.rti_addrs;
  845                 }
  846                 route_proto.sp_protocol = sa ? sa->sa_family : 0;
  847                 raw_input(m, &route_proto, &route_src, &route_dst);
  848         }
  849 }
  850 
  851 static struct mbuf *
  852 rt_makeifannouncemsg(struct ifnet *ifp, int type, int what,
  853     struct rt_addrinfo *info)
  854 {
  855         struct if_announcemsghdr ifan;
  856 
  857         memset(info, 0, sizeof(*info));
  858         memset(&ifan, 0, sizeof(ifan));
  859         ifan.ifan_index = ifp->if_index;
  860         strlcpy(ifan.ifan_name, ifp->if_xname, sizeof(ifan.ifan_name));
  861         ifan.ifan_what = what;
  862         return rt_msg1(type, info, (caddr_t)&ifan, sizeof(ifan));
  863 }
  864 
  865 /*
  866  * This is called to generate routing socket messages indicating
  867  * network interface arrival and departure.
  868  */
  869 void
  870 rt_ifannouncemsg(struct ifnet *ifp, int what)
  871 {
  872         struct mbuf *m;
  873         struct rt_addrinfo info;
  874 
  875         if (route_cb.any_count == 0)
  876                 return;
  877         m = rt_makeifannouncemsg(ifp, RTM_IFANNOUNCE, what, &info);
  878         if (m == NULL)
  879                 return;
  880         route_proto.sp_protocol = 0;
  881         raw_input(m, &route_proto, &route_src, &route_dst);
  882 }
  883 
  884 /*
  885  * This is called to generate routing socket messages indicating
  886  * IEEE80211 wireless events.
  887  * XXX we piggyback on the RTM_IFANNOUNCE msg format in a clumsy way.
  888  */
  889 void
  890 rt_ieee80211msg(struct ifnet *ifp, int what, void *data, size_t data_len)
  891 {
  892         struct mbuf *m;
  893         struct rt_addrinfo info;
  894 
  895         if (route_cb.any_count == 0)
  896                 return;
  897         m = rt_makeifannouncemsg(ifp, RTM_IEEE80211, what, &info);
  898         if (m == NULL)
  899                 return;
  900         /*
  901          * Append the ieee80211 data.  Try to stick it in the
  902          * mbuf containing the ifannounce msg; otherwise allocate
  903          * a new mbuf and append.
  904          *
  905          * NB: we assume m is a single mbuf.
  906          */
  907         if (data_len > M_TRAILINGSPACE(m)) {
  908                 struct mbuf *n = m_get(M_NOWAIT, MT_DATA);
  909                 if (n == NULL) {
  910                         m_freem(m);
  911                         return;
  912                 }
  913                 (void)memcpy(mtod(n, void *), data, data_len);
  914                 n->m_len = data_len;
  915                 m->m_next = n;
  916         } else if (data_len > 0) {
  917                 (void)memcpy(mtod(m, u_int8_t *) + m->m_len, data, data_len);
  918                 m->m_len += data_len;
  919         }
  920         if (m->m_flags & M_PKTHDR)
  921                 m->m_pkthdr.len += data_len;
  922         mtod(m, struct if_announcemsghdr *)->ifan_msglen += data_len;
  923         route_proto.sp_protocol = 0;
  924         raw_input(m, &route_proto, &route_src, &route_dst);
  925 }
  926 
  927 /*
  928  * This is used in dumping the kernel table via sysctl().
  929  */
  930 static int
  931 sysctl_dumpentry(struct radix_node *rn, void *v)
  932 {
  933         struct walkarg *w = v;
  934         struct rtentry *rt = (struct rtentry *)rn;
  935         int error = 0, size;
  936         struct rt_addrinfo info;
  937 
  938         if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
  939                 return 0;
  940         memset(&info, 0, sizeof(info));
  941         dst = rt_key(rt);
  942         gate = rt->rt_gateway;
  943         netmask = rt_mask(rt);
  944         genmask = rt->rt_genmask;
  945         if (rt->rt_ifp) {
  946                 const struct ifaddr *rtifa;
  947                 ifpaddr = TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
  948                 /* rtifa used to be simply rt->rt_ifa.  If rt->rt_ifa != NULL,
  949                  * then rt_get_ifa() != NULL.  So this ought to still be safe.
  950                  * --dyoung
  951                  */
  952                 rtifa = rt_get_ifa(rt);
  953                 ifaaddr = rtifa->ifa_addr;
  954                 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
  955                         brdaddr = rtifa->ifa_dstaddr;
  956         }
  957         if ((error = rt_msg2(RTM_GET, &info, 0, w, &size)))
  958                 return (error);
  959         if (w->w_where && w->w_tmem && w->w_needed <= 0) {
  960                 struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
  961 
  962                 rtm->rtm_flags = rt->rt_flags;
  963                 rtm->rtm_use = rt->rt_use;
  964                 rtm->rtm_rmx = rt->rt_rmx;
  965                 KASSERT(rt->rt_ifp != NULL);
  966                 rtm->rtm_index = rt->rt_ifp->if_index;
  967                 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
  968                 rtm->rtm_addrs = info.rti_addrs;
  969                 if ((error = copyout(rtm, w->w_where, size)) != 0)
  970                         w->w_where = NULL;
  971                 else
  972                         w->w_where += size;
  973         }
  974         return (error);
  975 }
  976 
  977 static int
  978 sysctl_iflist(int af, struct walkarg *w, int type)
  979 {
  980         struct ifnet *ifp;
  981         struct ifaddr *ifa;
  982         struct  rt_addrinfo info;
  983         int     len, error = 0;
  984 
  985         memset(&info, 0, sizeof(info));
  986         IFNET_FOREACH(ifp) {
  987                 if (w->w_arg && w->w_arg != ifp->if_index)
  988                         continue;
  989                 ifa = TAILQ_FIRST(&ifp->if_addrlist);
  990                 if (ifa == NULL)
  991                         continue;
  992                 ifpaddr = ifa->ifa_addr;
  993                 switch (type) {
  994                 case NET_RT_IFLIST:
  995                         error =
  996                             rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w, &len);
  997                         break;
  998 #ifdef COMPAT_14
  999                 case NET_RT_OIFLIST:
 1000                         error =
 1001                             rt_msg2(RTM_OIFINFO, &info, (caddr_t)0, w, &len);
 1002                         break;
 1003 #endif
 1004                 default:
 1005                         panic("sysctl_iflist(1)");
 1006                 }
 1007                 if (error)
 1008                         return (error);
 1009                 ifpaddr = 0;
 1010                 if (w->w_where && w->w_tmem && w->w_needed <= 0) {
 1011                         switch (type) {
 1012                         case NET_RT_IFLIST: {
 1013                                 struct if_msghdr *ifm;
 1014 
 1015                                 ifm = (struct if_msghdr *)w->w_tmem;
 1016                                 ifm->ifm_index = ifp->if_index;
 1017                                 ifm->ifm_flags = ifp->if_flags;
 1018                                 ifm->ifm_data = ifp->if_data;
 1019                                 ifm->ifm_addrs = info.rti_addrs;
 1020                                 error = copyout(ifm, w->w_where, len);
 1021                                 if (error)
 1022                                         return (error);
 1023                                 w->w_where += len;
 1024                                 break;
 1025                         }
 1026 
 1027 #ifdef COMPAT_14
 1028                         case NET_RT_OIFLIST: {
 1029                                 struct if_msghdr14 *ifm;
 1030 
 1031                                 ifm = (struct if_msghdr14 *)w->w_tmem;
 1032                                 ifm->ifm_index = ifp->if_index;
 1033                                 ifm->ifm_flags = ifp->if_flags;
 1034                                 ifm->ifm_data.ifi_type = ifp->if_data.ifi_type;
 1035                                 ifm->ifm_data.ifi_addrlen =
 1036                                     ifp->if_data.ifi_addrlen;
 1037                                 ifm->ifm_data.ifi_hdrlen =
 1038                                     ifp->if_data.ifi_hdrlen;
 1039                                 ifm->ifm_data.ifi_mtu = ifp->if_data.ifi_mtu;
 1040                                 ifm->ifm_data.ifi_metric =
 1041                                     ifp->if_data.ifi_metric;
 1042                                 ifm->ifm_data.ifi_baudrate =
 1043                                     ifp->if_data.ifi_baudrate;
 1044                                 ifm->ifm_data.ifi_ipackets =
 1045                                     ifp->if_data.ifi_ipackets;
 1046                                 ifm->ifm_data.ifi_ierrors =
 1047                                     ifp->if_data.ifi_ierrors;
 1048                                 ifm->ifm_data.ifi_opackets =
 1049                                     ifp->if_data.ifi_opackets;
 1050                                 ifm->ifm_data.ifi_oerrors =
 1051                                     ifp->if_data.ifi_oerrors;
 1052                                 ifm->ifm_data.ifi_collisions =
 1053                                     ifp->if_data.ifi_collisions;
 1054                                 ifm->ifm_data.ifi_ibytes =
 1055                                     ifp->if_data.ifi_ibytes;
 1056                                 ifm->ifm_data.ifi_obytes =
 1057                                     ifp->if_data.ifi_obytes;
 1058                                 ifm->ifm_data.ifi_imcasts =
 1059                                     ifp->if_data.ifi_imcasts;
 1060                                 ifm->ifm_data.ifi_omcasts =
 1061                                     ifp->if_data.ifi_omcasts;
 1062                                 ifm->ifm_data.ifi_iqdrops =
 1063                                     ifp->if_data.ifi_iqdrops;
 1064                                 ifm->ifm_data.ifi_noproto =
 1065                                     ifp->if_data.ifi_noproto;
 1066                                 ifm->ifm_data.ifi_lastchange =
 1067                                     ifp->if_data.ifi_lastchange;
 1068                                 ifm->ifm_addrs = info.rti_addrs;
 1069                                 error = copyout(ifm, w->w_where, len);
 1070                                 if (error)
 1071                                         return (error);
 1072                                 w->w_where += len;
 1073                                 break;
 1074                         }
 1075 #endif
 1076                         default:
 1077                                 panic("sysctl_iflist(2)");
 1078                         }
 1079                 }
 1080                 while ((ifa = TAILQ_NEXT(ifa, ifa_list)) != NULL) {
 1081                         if (af && af != ifa->ifa_addr->sa_family)
 1082                                 continue;
 1083                         ifaaddr = ifa->ifa_addr;
 1084                         netmask = ifa->ifa_netmask;
 1085                         brdaddr = ifa->ifa_dstaddr;
 1086                         if ((error = rt_msg2(RTM_NEWADDR, &info, 0, w, &len)))
 1087                                 return (error);
 1088                         if (w->w_where && w->w_tmem && w->w_needed <= 0) {
 1089                                 struct ifa_msghdr *ifam;
 1090 
 1091                                 ifam = (struct ifa_msghdr *)w->w_tmem;
 1092                                 ifam->ifam_index = ifa->ifa_ifp->if_index;
 1093                                 ifam->ifam_flags = ifa->ifa_flags;
 1094                                 ifam->ifam_metric = ifa->ifa_metric;
 1095                                 ifam->ifam_addrs = info.rti_addrs;
 1096                                 error = copyout(w->w_tmem, w->w_where, len);
 1097                                 if (error)
 1098                                         return (error);
 1099                                 w->w_where += len;
 1100                         }
 1101                 }
 1102                 ifaaddr = netmask = brdaddr = 0;
 1103         }
 1104         return (0);
 1105 }
 1106 
 1107 static int
 1108 sysctl_rtable(SYSCTLFN_ARGS)
 1109 {
 1110         void    *where = oldp;
 1111         size_t  *given = oldlenp;
 1112         const void *new = newp;
 1113         struct radix_node_head *rnh;
 1114         int     i, s, error = EINVAL;
 1115         u_char  af;
 1116         struct  walkarg w;
 1117 
 1118         if (namelen == 1 && name[0] == CTL_QUERY)
 1119                 return (sysctl_query(SYSCTLFN_CALL(rnode)));
 1120 
 1121         if (new)
 1122                 return (EPERM);
 1123         if (namelen != 3)
 1124                 return (EINVAL);
 1125         af = name[0];
 1126         w.w_tmemneeded = 0;
 1127         w.w_tmemsize = 0;
 1128         w.w_tmem = NULL;
 1129 again:
 1130         /* we may return here if a later [re]alloc of the t_mem buffer fails */
 1131         if (w.w_tmemneeded) {
 1132                 w.w_tmem = (caddr_t) malloc(w.w_tmemneeded, M_RTABLE, M_WAITOK);
 1133                 w.w_tmemsize = w.w_tmemneeded;
 1134                 w.w_tmemneeded = 0;
 1135         }
 1136         w.w_op = name[1];
 1137         w.w_arg = name[2];
 1138         w.w_given = *given;
 1139         w.w_needed = 0 - w.w_given;
 1140         w.w_where = where;
 1141 
 1142         s = splsoftnet();
 1143         switch (w.w_op) {
 1144 
 1145         case NET_RT_DUMP:
 1146         case NET_RT_FLAGS:
 1147                 for (i = 1; i <= AF_MAX; i++)
 1148                         if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
 1149                             (error = (*rnh->rnh_walktree)(rnh,
 1150                             sysctl_dumpentry, &w)))
 1151                                 break;
 1152                 break;
 1153 
 1154 #ifdef COMPAT_14
 1155         case NET_RT_OIFLIST:
 1156                 error = sysctl_iflist(af, &w, w.w_op);
 1157                 break;
 1158 #endif
 1159 
 1160         case NET_RT_IFLIST:
 1161                 error = sysctl_iflist(af, &w, w.w_op);
 1162         }
 1163         splx(s);
 1164 
 1165         /* check to see if we couldn't allocate memory with NOWAIT */
 1166         if (error == ENOBUFS && w.w_tmem == 0 && w.w_tmemneeded)
 1167                 goto again;
 1168 
 1169         if (w.w_tmem)
 1170                 free(w.w_tmem, M_RTABLE);
 1171         w.w_needed += w.w_given;
 1172         if (where) {
 1173                 *given = w.w_where - (caddr_t) where;
 1174                 if (*given < w.w_needed)
 1175                         return (ENOMEM);
 1176         } else {
 1177                 *given = (11 * w.w_needed) / 10;
 1178         }
 1179         return (error);
 1180 }
 1181 
 1182 /*
 1183  * Definitions of protocols supported in the ROUTE domain.
 1184  */
 1185 
 1186 const struct protosw routesw[] = {
 1187 {
 1188         SOCK_RAW,       &routedomain,   0,              PR_ATOMIC|PR_ADDR,
 1189         raw_input,      route_output,   raw_ctlinput,   0,
 1190         route_usrreq,
 1191         raw_init,       0,              0,              0,
 1192 } };
 1193 
 1194 struct domain routedomain = {
 1195         .dom_family = PF_ROUTE,
 1196         .dom_name = "route",
 1197         .dom_init = route_init,
 1198         .dom_protosw = routesw,
 1199         .dom_protoswNPROTOSW = &routesw[sizeof(routesw)/sizeof(routesw[0])],
 1200 };
 1201 
 1202 SYSCTL_SETUP(sysctl_net_route_setup, "sysctl net.route subtree setup")
 1203 {
 1204         const struct sysctlnode *rnode = NULL;
 1205 
 1206         sysctl_createv(clog, 0, NULL, NULL,
 1207                        CTLFLAG_PERMANENT,
 1208                        CTLTYPE_NODE, "net", NULL,
 1209                        NULL, 0, NULL, 0,
 1210                        CTL_NET, CTL_EOL);
 1211 
 1212         sysctl_createv(clog, 0, NULL, &rnode,
 1213                        CTLFLAG_PERMANENT,
 1214                        CTLTYPE_NODE, "route",
 1215                        SYSCTL_DESCR("PF_ROUTE information"),
 1216                        NULL, 0, NULL, 0,
 1217                        CTL_NET, PF_ROUTE, CTL_EOL);
 1218         sysctl_createv(clog, 0, NULL, NULL,
 1219                        CTLFLAG_PERMANENT,
 1220                        CTLTYPE_NODE, "rtable",
 1221                        SYSCTL_DESCR("Routing table information"),
 1222                        sysctl_rtable, 0, NULL, 0,
 1223                        CTL_NET, PF_ROUTE, 0 /* any protocol */, CTL_EOL);
 1224         sysctl_createv(clog, 0, &rnode, NULL,
 1225                        CTLFLAG_PERMANENT,
 1226                        CTLTYPE_STRUCT, "stats",
 1227                        SYSCTL_DESCR("Routing statistics"),
 1228                        NULL, 0, &rtstat, sizeof(rtstat),
 1229                        CTL_CREATE, CTL_EOL);
 1230 }

Cache object: 4eef5c7913562b4baa239ea407f79290


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