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.256 2022/08/27 08:36:41 skrll 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.256 2022/08/27 08:36:41 skrll Exp $");
   65 
   66 #ifdef _KERNEL_OPT
   67 #include "opt_inet.h"
   68 #include "opt_compat_netbsd.h"
   69 #endif
   70 
   71 #include <sys/param.h>
   72 #include <sys/systm.h>
   73 #include <sys/proc.h>
   74 #include <sys/socket.h>
   75 #include <sys/socketvar.h>
   76 #include <sys/domain.h>
   77 #include <sys/protosw.h>
   78 #include <sys/sysctl.h>
   79 #include <sys/kauth.h>
   80 #include <sys/kmem.h>
   81 #include <sys/intr.h>
   82 #include <sys/condvar.h>
   83 #include <sys/compat_stub.h>
   84 
   85 #include <net/if.h>
   86 #include <net/if_llatbl.h>
   87 #include <net/if_types.h>
   88 #include <net/route.h>
   89 #include <net/raw_cb.h>
   90 
   91 #include <netinet/in_var.h>
   92 #include <netinet/if_inarp.h>
   93 
   94 #include <netmpls/mpls.h>
   95 
   96 #include <compat/net/if.h>
   97 #include <compat/net/route.h>
   98 
   99 #ifdef COMPAT_RTSOCK
  100 #undef COMPAT_RTSOCK
  101 #endif
  102 
  103 static int if_addrflags(struct ifaddr *);
  104 
  105 #include <net/rtsock_shared.c>
  106 
  107 /*
  108  * XXX avoid using void * once msghdr compat disappears.
  109  */
  110 void
  111 rt_setmetrics(void *in, struct rtentry *out)
  112 {
  113         const struct rt_xmsghdr *rtm = in;
  114 
  115         _rt_setmetrics(rtm->rtm_inits, rtm, out);
  116 }
  117 
  118 int
  119 rt_msg3(int type, struct rt_addrinfo *rtinfo, void *cpv, struct rt_walkarg *w,
  120         int *lenp)
  121 {
  122         return rt_msg2(type, rtinfo, cpv, w, lenp);
  123 }
  124 
  125 static int
  126 if_addrflags(struct ifaddr *ifa)
  127 {
  128 
  129         switch (ifa->ifa_addr->sa_family) {
  130 #ifdef INET
  131         case AF_INET:
  132                 return ifatoia(ifa)->ia4_flags;
  133 #endif
  134 #ifdef INET6
  135         case AF_INET6:
  136                 return ifatoia6(ifa)->ia6_flags;
  137 #endif
  138         default:
  139                 return 0;
  140         }
  141 }
  142 
  143 
  144 /*
  145  * Send a routing message as mimicing that a cloned route is added.
  146  */
  147 void
  148 rt_clonedmsg(int type, const struct sockaddr *src, const struct sockaddr *dst,
  149     const uint8_t *lladdr, const struct ifnet *ifp)
  150 {
  151         struct rt_addrinfo info;
  152         /* Mimic flags exactly */
  153 #define RTF_LLINFO      0x400
  154 #define RTF_CLONED      0x2000
  155         int flags = RTF_DONE;
  156         union {
  157                 struct sockaddr sa;
  158                 struct sockaddr_storage ss;
  159                 struct sockaddr_dl sdl;
  160         } u;
  161 
  162         if (type != RTM_MISS)
  163                 flags |= RTF_HOST | RTF_CLONED | RTF_LLINFO;
  164         if (type == RTM_ADD || type == RTM_CHANGE)
  165                 flags |= RTF_UP;
  166         memset(&info, 0, sizeof(info));
  167         info.rti_info[RTAX_AUTHOR] = src;
  168         info.rti_info[RTAX_DST] = dst;
  169         sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type,
  170             NULL, 0, lladdr, ifp->if_addrlen);
  171         info.rti_info[RTAX_GATEWAY] = &u.sa;
  172 
  173         rt_missmsg(type, &info, flags, 0);
  174 #undef RTF_LLINFO
  175 #undef RTF_CLONED
  176 }
  177 
  178 
  179 /*
  180  * The remaining code implements the routing-table sysctl node.  It is
  181  * compiled only for the non-COMPAT case.
  182  */
  183 
  184 /*
  185  * This is used in dumping the kernel table via sysctl().
  186  */
  187 static int
  188 sysctl_dumpentry(struct rtentry *rt, void *v)
  189 {
  190         struct rt_walkarg *w = v;
  191         int error = 0, size;
  192         struct rt_addrinfo info;
  193 
  194         if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
  195                 return 0;
  196         memset(&info, 0, sizeof(info));
  197         info.rti_info[RTAX_DST] = rt_getkey(rt);
  198         info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
  199         info.rti_info[RTAX_NETMASK] = rt_mask(rt);
  200         info.rti_info[RTAX_TAG] = rt_gettag(rt);
  201         if (rt->rt_ifp) {
  202                 const struct ifaddr *rtifa;
  203                 info.rti_info[RTAX_IFP] = rt->rt_ifp->if_dl->ifa_addr;
  204                 /* rtifa used to be simply rt->rt_ifa.  If rt->rt_ifa != NULL,
  205                  * then rt_get_ifa() != NULL.  So this ought to still be safe.
  206                  * --dyoung
  207                  */
  208                 rtifa = rt_get_ifa(rt);
  209                 info.rti_info[RTAX_IFA] = rtifa->ifa_addr;
  210                 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
  211                         info.rti_info[RTAX_BRD] = rtifa->ifa_dstaddr;
  212         }
  213         if ((error = rt_msg2(RTM_GET, &info, 0, w, &size)))
  214                 return error;
  215         if (w->w_where && w->w_tmem && w->w_needed <= 0) {
  216                 struct rt_xmsghdr *rtm = (struct rt_xmsghdr *)w->w_tmem;
  217 
  218                 rtm->rtm_flags = rt->rt_flags;
  219                 rtm->rtm_use = rt->rt_use;
  220                 rtm_setmetrics(rt, rtm);
  221                 KASSERT(rt->rt_ifp != NULL);
  222                 rtm->rtm_index = rt->rt_ifp->if_index;
  223                 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
  224                 rtm->rtm_addrs = info.rti_addrs;
  225                 if ((error = copyout(rtm, w->w_where, size)) != 0)
  226                         w->w_where = NULL;
  227                 else
  228                         w->w_where = (char *)w->w_where + size;
  229         }
  230         return error;
  231 }
  232 
  233 static int
  234 sysctl_iflist_if(struct ifnet *ifp, struct rt_walkarg *w,
  235     struct rt_addrinfo *info, size_t len)
  236 {
  237         struct if_xmsghdr *ifm;
  238         int error;
  239 
  240         ifm = (struct if_xmsghdr *)w->w_tmem;
  241         ifm->ifm_index = ifp->if_index;
  242         ifm->ifm_flags = ifp->if_flags;
  243         if_export_if_data(ifp, &ifm->ifm_data, false);
  244         ifm->ifm_addrs = info->rti_addrs;
  245         if ((error = copyout(ifm, w->w_where, len)) == 0)
  246                 w->w_where = (char *)w->w_where + len;
  247         return error;
  248 }
  249 
  250 static int
  251 sysctl_iflist_addr(struct rt_walkarg *w, struct ifaddr *ifa,
  252      struct rt_addrinfo *info)
  253 {
  254         int len, error;
  255 
  256         if ((error = rt_msg2(RTM_XNEWADDR, info, 0, w, &len)))
  257                 return error;
  258         if (w->w_where && w->w_tmem && w->w_needed <= 0) {
  259                 struct ifa_xmsghdr *ifam;
  260 
  261                 ifam = (struct ifa_xmsghdr *)w->w_tmem;
  262                 ifam->ifam_index = ifa->ifa_ifp->if_index;
  263                 ifam->ifam_flags = ifa->ifa_flags;
  264                 ifam->ifam_metric = ifa->ifa_metric;
  265                 ifam->ifam_addrs = info->rti_addrs;
  266                 ifam->ifam_pid = 0;
  267                 ifam->ifam_addrflags = if_addrflags(ifa);
  268                 if ((error = copyout(w->w_tmem, w->w_where, len)) == 0)
  269                         w->w_where = (char *)w->w_where + len;
  270         }
  271         return error;
  272 }
  273 
  274 static int
  275 sysctl_iflist(int af, struct rt_walkarg *w, int type)
  276 {
  277         struct ifnet *ifp;
  278         struct ifaddr *ifa;
  279         struct  rt_addrinfo info;
  280         int     cmd, len, error = 0;
  281         int s;
  282         struct psref psref;
  283         int bound;
  284 
  285         switch (type) {
  286         case NET_RT_IFLIST:
  287                 cmd = RTM_IFINFO;
  288                 break;
  289         case NET_RT_OOOIFLIST:
  290                 cmd = RTM_OOIFINFO;
  291                 break;
  292         case NET_RT_OOIFLIST:
  293                 cmd = RTM_OIFINFO;
  294                 break;
  295         case NET_RT_OIFLIST:
  296                 cmd = RTM_IFINFO;
  297                 break;
  298         default:
  299 #ifdef RTSOCK_DEBUG
  300                 printf("%s: unsupported IFLIST type %d\n", __func__, type);
  301 #endif
  302                 return EINVAL;
  303         }
  304 
  305         memset(&info, 0, sizeof(info));
  306 
  307         bound = curlwp_bind();
  308         s = pserialize_read_enter();
  309         IFNET_READER_FOREACH(ifp) {
  310                 int _s;
  311                 if (w->w_arg && w->w_arg != ifp->if_index)
  312                         continue;
  313                 if (IFADDR_READER_EMPTY(ifp))
  314                         continue;
  315 
  316                 if_acquire(ifp, &psref);
  317                 pserialize_read_exit(s);
  318 
  319                 info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr;
  320                 if ((error = rt_msg2(cmd, &info, NULL, w, &len)) != 0)
  321                         goto release_exit;
  322                 info.rti_info[RTAX_IFP] = NULL;
  323                 if (w->w_where && w->w_tmem && w->w_needed <= 0) {
  324                         switch (type) {
  325                         case NET_RT_OIFLIST: /* old _70 */
  326                                 if (!rtsock_iflist_70_hook.hooked) {
  327                                         error = EINVAL;
  328                                         break;
  329                                 }
  330                                 /* FALLTHROUGH */
  331                         case NET_RT_IFLIST: /* current */
  332                                 error = sysctl_iflist_if(ifp, w, &info, len);
  333                                 break;
  334                         case NET_RT_OOIFLIST: /* old _50 */
  335                                 MODULE_HOOK_CALL(rtsock_iflist_50_hook,
  336                                     (ifp, w, &info, len), enosys(), error);
  337                                 break;
  338                         case NET_RT_OOOIFLIST: /* old _14 */
  339                                 MODULE_HOOK_CALL(rtsock_iflist_14_hook,
  340                                    (ifp, w, &info, len), enosys(), error);
  341                                 break;
  342                         default:
  343                                 error = EINVAL;
  344                         }
  345                         if (error != 0) {
  346                                 if (error == ENOSYS)
  347                                         error = EINVAL;
  348                                 goto release_exit;
  349                         }
  350                 }
  351                 _s = pserialize_read_enter();
  352                 IFADDR_READER_FOREACH(ifa, ifp) {
  353                         struct psref _psref;
  354                         if (af && af != ifa->ifa_addr->sa_family)
  355                                 continue;
  356                         ifa_acquire(ifa, &_psref);
  357                         pserialize_read_exit(_s);
  358 
  359                         info.rti_info[RTAX_IFA] = ifa->ifa_addr;
  360                         info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
  361                         info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr;
  362                         switch (type) {
  363                         case NET_RT_IFLIST:
  364                                 error = sysctl_iflist_addr(w, ifa, &info);
  365                                 break;
  366                         case NET_RT_OIFLIST:
  367                         case NET_RT_OOIFLIST:
  368                         case NET_RT_OOOIFLIST:
  369                                 MODULE_HOOK_CALL(rtsock_iflist_70_hook,
  370                                     (w, ifa, &info), enosys(), error);
  371                                 break;
  372                         default:
  373                                 error = EINVAL;
  374                         }
  375 
  376                         _s = pserialize_read_enter();
  377                         ifa_release(ifa, &_psref);
  378                         if (error != 0) {
  379                                 pserialize_read_exit(_s);
  380                                 goto release_exit;
  381                         }
  382                 }
  383                 pserialize_read_exit(_s);
  384                 info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] =
  385                     info.rti_info[RTAX_BRD] = NULL;
  386 
  387                 s = pserialize_read_enter();
  388                 if_release(ifp, &psref);
  389         }
  390         pserialize_read_exit(s);
  391         curlwp_bindx(bound);
  392 
  393         return 0;
  394 
  395 release_exit:
  396         if_release(ifp, &psref);
  397         curlwp_bindx(bound);
  398         return error;
  399 }
  400 
  401 static int
  402 sysctl_rtable(SYSCTLFN_ARGS)
  403 {
  404         void    *where = oldp;
  405         size_t  *given = oldlenp;
  406         int     i, error = EINVAL;
  407         u_char  af;
  408         struct  rt_walkarg w;
  409 
  410         if (namelen == 1 && name[0] == CTL_QUERY)
  411                 return sysctl_query(SYSCTLFN_CALL(rnode));
  412 
  413         if (newp)
  414                 return EPERM;
  415         if (namelen != 3)
  416                 return EINVAL;
  417         af = name[0];
  418         w.w_tmemneeded = 0;
  419         w.w_tmemsize = 0;
  420         w.w_tmem = NULL;
  421 again:
  422         /* we may return here if a later [re]alloc of the t_mem buffer fails */
  423         if (w.w_tmemneeded) {
  424                 w.w_tmem = kmem_zalloc(w.w_tmemneeded, KM_SLEEP);
  425                 w.w_tmemsize = w.w_tmemneeded;
  426                 w.w_tmemneeded = 0;
  427         }
  428         w.w_op = name[1];
  429         w.w_arg = name[2];
  430         w.w_given = *given;
  431         w.w_needed = 0 - w.w_given;
  432         w.w_where = where;
  433 
  434         KERNEL_LOCK_UNLESS_NET_MPSAFE();
  435         const int s = splsoftnet();
  436         switch (w.w_op) {
  437 
  438         case NET_RT_DUMP:
  439         case NET_RT_FLAGS:
  440 #if defined(INET) || defined(INET6)
  441                 /*
  442                  * take care of llinfo entries, the caller must
  443                  * specify an AF
  444                  */
  445                 if (w.w_op == NET_RT_FLAGS &&
  446                     (w.w_arg == 0 || w.w_arg & RTF_LLDATA)) {
  447                         if (af != 0)
  448                                 error = lltable_sysctl_dump(af, &w);
  449                         else
  450                                 error = EINVAL;
  451                         break;
  452                 }
  453 #endif
  454 
  455                 for (i = 1; i <= AF_MAX; i++) {
  456                         if (af == 0 || af == i) {
  457                                 error = rt_walktree(i, sysctl_dumpentry, &w);
  458                                 if (error != 0)
  459                                         break;
  460 #if defined(INET) || defined(INET6)
  461                                 /*
  462                                  * Return ARP/NDP entries too for
  463                                  * backward compatibility.
  464                                  */
  465                                 error = lltable_sysctl_dump(i, &w);
  466                                 if (error != 0)
  467                                         break;
  468 #endif
  469                         }
  470                 }
  471                 break;
  472 
  473         case NET_RT_OOOIFLIST:          /* compat_14 */
  474         case NET_RT_OOIFLIST:           /* compat_50 */
  475         case NET_RT_OIFLIST:            /* compat_70 */
  476         case NET_RT_IFLIST:             /* current */
  477                 error = sysctl_iflist(af, &w, w.w_op);
  478                 break;
  479         }
  480         splx(s);
  481         KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
  482 
  483         /* check to see if we couldn't allocate memory with NOWAIT */
  484         if (error == ENOBUFS && w.w_tmem == 0 && w.w_tmemneeded)
  485                 goto again;
  486 
  487         if (w.w_tmem)
  488                 kmem_free(w.w_tmem, w.w_tmemsize);
  489         w.w_needed += w.w_given;
  490         if (where) {
  491                 *given = (char *)w.w_where - (char *)where;
  492                 if (*given < w.w_needed)
  493                         return ENOMEM;
  494         } else {
  495                 *given = (11 * w.w_needed) / 10;
  496         }
  497         return error;
  498 }
  499 
  500 void
  501 sysctl_net_route_setup(struct sysctllog **clog, int pf, const char *name)
  502 {
  503         const struct sysctlnode *rnode = NULL;
  504 
  505         sysctl_createv(clog, 0, NULL, &rnode,
  506                        CTLFLAG_PERMANENT,
  507                        CTLTYPE_NODE, name,
  508                        SYSCTL_DESCR("PF_ROUTE information"),
  509                        NULL, 0, NULL, 0,
  510                        CTL_NET, pf, CTL_EOL);
  511 
  512         sysctl_createv(clog, 0, NULL, NULL,
  513                        CTLFLAG_PERMANENT,
  514                        CTLTYPE_NODE, "rtable",
  515                        SYSCTL_DESCR("Routing table information"),
  516                        sysctl_rtable, 0, NULL, 0,
  517                        CTL_NET, pf, 0 /* any protocol */, CTL_EOL);
  518 
  519         sysctl_createv(clog, 0, &rnode, NULL,
  520                        CTLFLAG_PERMANENT,
  521                        CTLTYPE_STRUCT, "stats",
  522                        SYSCTL_DESCR("Routing statistics"),
  523                        NULL, 0, &rtstat, sizeof(rtstat),
  524                        CTL_CREATE, CTL_EOL);
  525 }

Cache object: da571eaca3c19ffbd58b05f0483aa734


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