root/net/rtsock.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. route_usrreq
  2. route_output
  3. rt_setmetrics
  4. rt_getmetrics
  5. rt_xaddrs
  6. rt_msg1
  7. rt_msg2
  8. rt_missmsg
  9. rt_ifmsg
  10. rt_newaddrmsg
  11. rt_ifannouncemsg
  12. sysctl_dumpentry
  13. sysctl_iflist
  14. sysctl_rtable

    1 /*      $OpenBSD: rtsock.c,v 1.63 2007/02/14 00:53:48 jsg Exp $ */
    2 /*      $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $  */
    3 
    4 /*
    5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    6  * All rights reserved.
    7  * 
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the project nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  * 
   20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * Copyright (c) 1988, 1991, 1993
   35  *      The Regents of the University of California.  All rights reserved.
   36  *
   37  * Redistribution and use in source and binary forms, with or without
   38  * modification, are permitted provided that the following conditions
   39  * are met:
   40  * 1. Redistributions of source code must retain the above copyright
   41  *    notice, this list of conditions and the following disclaimer.
   42  * 2. Redistributions in binary form must reproduce the above copyright
   43  *    notice, this list of conditions and the following disclaimer in the
   44  *    documentation and/or other materials provided with the distribution.
   45  * 3. Neither the name of the University nor the names of its contributors
   46  *    may be used to endorse or promote products derived from this software
   47  *    without specific prior written permission.
   48  *
   49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   59  * SUCH DAMAGE.
   60  *
   61  *      @(#)rtsock.c    8.6 (Berkeley) 2/11/95
   62  */
   63 
   64 #include <sys/param.h>
   65 #include <sys/systm.h>
   66 #include <sys/proc.h>
   67 #include <sys/mbuf.h>
   68 #include <sys/socket.h>
   69 #include <sys/socketvar.h>
   70 #include <sys/domain.h>
   71 #include <sys/protosw.h>
   72 
   73 #include <uvm/uvm_extern.h>
   74 #include <sys/sysctl.h>
   75 
   76 #include <net/if.h>
   77 #include <net/route.h>
   78 #include <net/raw_cb.h>
   79 
   80 #include <sys/stdarg.h>
   81 
   82 struct sockaddr         route_dst = { 2, PF_ROUTE, };
   83 struct sockaddr         route_src = { 2, PF_ROUTE, };
   84 struct sockproto        route_proto = { PF_ROUTE, };
   85 
   86 struct walkarg {
   87         int     w_op, w_arg, w_given, w_needed, w_tmemsize;
   88         caddr_t w_where, w_tmem;
   89 };
   90 
   91 static struct mbuf
   92                 *rt_msg1(int, struct rt_addrinfo *);
   93 static int       rt_msg2(int, struct rt_addrinfo *, caddr_t, struct walkarg *);
   94 static void      rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
   95 
   96 /* Sleazy use of local variables throughout file, warning!!!! */
   97 #define dst     info.rti_info[RTAX_DST]
   98 #define gate    info.rti_info[RTAX_GATEWAY]
   99 #define netmask info.rti_info[RTAX_NETMASK]
  100 #define genmask info.rti_info[RTAX_GENMASK]
  101 #define ifpaddr info.rti_info[RTAX_IFP]
  102 #define ifaaddr info.rti_info[RTAX_IFA]
  103 #define brdaddr info.rti_info[RTAX_BRD]
  104 
  105 int
  106 route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
  107     struct mbuf *control)
  108 {
  109         int              error = 0;
  110         struct rawcb    *rp = sotorawcb(so);
  111         int              s;
  112 
  113         if (req == PRU_ATTACH) {
  114                 MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
  115                 so->so_pcb = rp;
  116                 bzero(so->so_pcb, sizeof(*rp));
  117         }
  118         if (req == PRU_DETACH && rp) {
  119                 int af = rp->rcb_proto.sp_protocol;
  120                 if (af == AF_INET)
  121                         route_cb.ip_count--;
  122                 else if (af == AF_INET6)
  123                         route_cb.ip6_count--;
  124                 route_cb.any_count--;
  125         }
  126         s = splsoftnet();
  127         /*
  128          * Don't call raw_usrreq() in the attach case, because
  129          * we want to allow non-privileged processes to listen on
  130          * and send "safe" commands to the routing socket.
  131          */
  132         if (req == PRU_ATTACH) {
  133                 if (curproc == 0)
  134                         error = EACCES;
  135                 else
  136                         error = raw_attach(so, (int)(long)nam);
  137         } else
  138                 error = raw_usrreq(so, req, m, nam, control);
  139 
  140         rp = sotorawcb(so);
  141         if (req == PRU_ATTACH && rp) {
  142                 int af = rp->rcb_proto.sp_protocol;
  143                 if (error) {
  144                         free(rp, M_PCB);
  145                         splx(s);
  146                         return (error);
  147                 }
  148                 if (af == AF_INET)
  149                         route_cb.ip_count++;
  150                 else if (af == AF_INET6)
  151                         route_cb.ip6_count++;
  152                 rp->rcb_faddr = &route_src;
  153                 route_cb.any_count++;
  154                 soisconnected(so);
  155                 so->so_options |= SO_USELOOPBACK;
  156         }
  157         splx(s);
  158         return (error);
  159 }
  160 
  161 int
  162 route_output(struct mbuf *m, ...)
  163 {
  164         struct rt_msghdr        *rtm = NULL;
  165         struct radix_node       *rn = NULL;
  166         struct rtentry          *rt = NULL;
  167         struct rtentry          *saved_nrt = NULL;
  168         struct radix_node_head  *rnh;
  169         struct rt_addrinfo       info;
  170         int                      len, error = 0;
  171         struct ifnet            *ifp = NULL;
  172         struct ifaddr           *ifa = NULL;
  173         struct socket           *so;
  174         struct rawcb            *rp = NULL;
  175         struct sockaddr_rtlabel  sa_rt;
  176         const char              *label;
  177         va_list                  ap;
  178         u_int                    tableid;
  179 
  180         va_start(ap, m);
  181         so = va_arg(ap, struct socket *);
  182         va_end(ap);
  183 
  184         if (m == 0 || ((m->m_len < sizeof(int32_t)) &&
  185             (m = m_pullup(m, sizeof(int32_t))) == 0))
  186                 return (ENOBUFS);
  187         if ((m->m_flags & M_PKTHDR) == 0)
  188                 panic("route_output");
  189         len = m->m_pkthdr.len;
  190         if (len < sizeof(*rtm) ||
  191             len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
  192                 dst = 0;
  193                 error = EINVAL;
  194                 goto flush;
  195         }
  196         R_Malloc(rtm, struct rt_msghdr *, len);
  197         if (rtm == 0) {
  198                 dst = 0;
  199                 error = ENOBUFS;
  200                 goto flush;
  201         }
  202         m_copydata(m, 0, len, (caddr_t)rtm);
  203         if (rtm->rtm_version != RTM_VERSION) {
  204                 dst = 0;
  205                 error = EPROTONOSUPPORT;
  206                 goto flush;
  207         }
  208         rtm->rtm_pid = curproc->p_pid;
  209 
  210         tableid = rtm->rtm_tableid;
  211         if (!rtable_exists(tableid)) {
  212                 if (rtm->rtm_type == RTM_ADD) {
  213                         if (rtable_add(tableid)) {
  214                                 error = EINVAL;
  215                                 goto flush;
  216                         }
  217                 } else {
  218                         error = EINVAL;
  219                         goto flush;
  220                 }
  221         }
  222 
  223         bzero(&info, sizeof(info));
  224         info.rti_addrs = rtm->rtm_addrs;
  225         rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info);
  226         info.rti_flags = rtm->rtm_flags;
  227         if (dst == 0 || dst->sa_family >= AF_MAX ||
  228             (gate != 0 && gate->sa_family >= AF_MAX)) {
  229                 error = EINVAL;
  230                 goto flush;
  231         }
  232         if (genmask) {
  233                 struct radix_node       *t;
  234                 t = rn_addmask(genmask, 0, 1);
  235                 if (t && genmask->sa_len >=
  236                     ((struct sockaddr *)t->rn_key)->sa_len &&
  237                     Bcmp((caddr_t *)genmask + 1, (caddr_t *)t->rn_key + 1,
  238                     ((struct sockaddr *)t->rn_key)->sa_len) - 1)
  239                         genmask = (struct sockaddr *)(t->rn_key);
  240                 else {
  241                         error = ENOBUFS;
  242                         goto flush;
  243                 }
  244         }
  245 
  246         /*
  247          * Verify that the caller has the appropriate privilege; RTM_GET
  248          * is the only operation the non-superuser is allowed.
  249          */
  250         if (rtm->rtm_type != RTM_GET && suser(curproc, 0) != 0) {
  251                 error = EACCES;
  252                 goto flush;
  253         }
  254 
  255         switch (rtm->rtm_type) {
  256         case RTM_ADD:
  257                 if (gate == 0) {
  258                         error = EINVAL;
  259                         goto flush;
  260                 }
  261                 error = rtrequest1(rtm->rtm_type, &info, &saved_nrt, tableid);
  262                 if (error == 0 && saved_nrt) {
  263                         rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
  264                             &saved_nrt->rt_rmx);
  265                         saved_nrt->rt_refcnt--;
  266                         saved_nrt->rt_genmask = genmask;
  267                         rtm->rtm_index = saved_nrt->rt_ifp->if_index;
  268                 }
  269                 break;
  270         case RTM_DELETE:
  271                 error = rtrequest1(rtm->rtm_type, &info, &saved_nrt, tableid);
  272                 if (error == 0) {
  273                         (rt = saved_nrt)->rt_refcnt++;
  274                         goto report;
  275                 }
  276                 break;
  277         case RTM_GET:
  278         case RTM_CHANGE:
  279         case RTM_LOCK:
  280                 if ((rnh = rt_gettable(dst->sa_family, tableid)) == NULL) {
  281                         error = EAFNOSUPPORT;
  282                         goto flush;
  283                 }
  284                 rn = rt_lookup(dst, netmask, tableid);
  285                 if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) {
  286                         error = ESRCH;
  287                         goto flush;
  288                 }
  289                 rt = (struct rtentry *)rn;
  290 #ifndef SMALL_KERNEL
  291                 /*
  292                  * for RTM_CHANGE/LOCK, if we got multipath routes,
  293                  * we require users to specify a matching RTAX_GATEWAY.
  294                  *
  295                  * for RTM_GET, gate is optional even with multipath.
  296                  * if gate == NULL the first match is returned.
  297                  * (no need to call rt_mpath_matchgate if gate == NULL)
  298                  */
  299                 if (rn_mpath_capable(rnh) &&
  300                     (rtm->rtm_type != RTM_GET || gate)) {
  301                         rt = rt_mpath_matchgate(rt, gate);
  302                         rn = (struct radix_node *)rt;
  303                         if (!rt) {
  304                                 error = ESRCH;
  305                                 goto flush;
  306                         }
  307                 }
  308 #endif
  309                 rt->rt_refcnt++;
  310 
  311                 /*
  312                  * RTM_CHANGE/LOCK need a perfect match, rn_lookup()
  313                  * returns a perfect match in case a netmask is specified.
  314                  * For host routes only a longest prefix match is returned
  315                  * so it is necessary to compare the existence of the netmaks.
  316                  * If both have a netmask rn_lookup() did a perfect match and
  317                  * if none of them have a netmask both are host routes which is
  318                  * also a perfect match.
  319                  */
  320                 if (rtm->rtm_type != RTM_GET && !rt_mask(rt) != !netmask) {
  321                                 error = ESRCH;
  322                                 goto flush;
  323                 }
  324 
  325                 switch (rtm->rtm_type) {
  326                 case RTM_GET:
  327 report:
  328                         dst = rt_key(rt);
  329                         gate = rt->rt_gateway;
  330                         netmask = rt_mask(rt);
  331                         genmask = rt->rt_genmask;
  332 
  333                         if (rt->rt_labelid) {
  334                                 bzero(&sa_rt, sizeof(sa_rt));
  335                                 sa_rt.sr_len = sizeof(sa_rt);
  336                                 label = rtlabel_id2name(rt->rt_labelid);
  337                                 if (label != NULL)
  338                                         strlcpy(sa_rt.sr_label, label,
  339                                             sizeof(sa_rt.sr_label));
  340                                 info.rti_info[RTAX_LABEL] =
  341                                     (struct sockaddr *)&sa_rt;
  342                         }
  343 
  344                         ifpaddr = 0;
  345                         ifaaddr = 0;
  346                         if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA) &&
  347                             (ifp = rt->rt_ifp) != NULL) {
  348                                 ifpaddr =
  349                                     TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
  350                                 ifaaddr = rt->rt_ifa->ifa_addr;
  351                                 if (ifp->if_flags & IFF_POINTOPOINT)
  352                                         brdaddr = rt->rt_ifa->ifa_dstaddr;
  353                                 else
  354                                         brdaddr = 0;
  355                                 rtm->rtm_index = ifp->if_index;
  356                         }
  357                         len = rt_msg2(rtm->rtm_type, &info, NULL, NULL);
  358                         if (len > rtm->rtm_msglen) {
  359                                 struct rt_msghdr        *new_rtm;
  360                                 R_Malloc(new_rtm, struct rt_msghdr *, len);
  361                                 if (new_rtm == 0) {
  362                                         error = ENOBUFS;
  363                                         goto flush;
  364                                 }
  365                                 Bcopy(rtm, new_rtm, rtm->rtm_msglen);
  366                                 Free(rtm); rtm = new_rtm;
  367                         }
  368                         rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm, NULL);
  369                         rtm->rtm_flags = rt->rt_flags;
  370                         rtm->rtm_use = 0;
  371                         rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
  372                         rtm->rtm_addrs = info.rti_addrs;
  373                         break;
  374 
  375                 case RTM_CHANGE:
  376                         /*
  377                          * new gateway could require new ifaddr, ifp;
  378                          * flags may also be different; ifp may be specified
  379                          * by ll sockaddr when protocol address is ambiguous
  380                          */
  381                         if ((error = rt_getifa(&info)) != 0)
  382                                 goto flush;
  383                         if (gate && rt_setgate(rt, rt_key(rt), gate, tableid)) {
  384                                 error = EDQUOT;
  385                                 goto flush;
  386                         }
  387                         if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&
  388                             (ifp = ifa->ifa_ifp) && (ifaaddr || gate))
  389                                 ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
  390                                                         ifp);
  391                         else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||
  392                             (gate && (ifa = ifa_ifwithroute(rt->rt_flags,
  393                             rt_key(rt), gate))))
  394                                 ifp = ifa->ifa_ifp;
  395                         if (ifa) {
  396                                 struct ifaddr *oifa = rt->rt_ifa;
  397                                 if (oifa != ifa) {
  398                                     if (oifa && oifa->ifa_rtrequest)
  399                                         oifa->ifa_rtrequest(RTM_DELETE, rt,
  400                                             &info);
  401                                     IFAFREE(rt->rt_ifa);
  402                                     rt->rt_ifa = ifa;
  403                                     ifa->ifa_refcnt++;
  404                                     rt->rt_ifp = ifp;
  405                                 }
  406                         }
  407 
  408                         /* XXX Hack to allow some flags to be toggled */
  409                         if (rtm->rtm_fmask & RTF_FMASK)
  410                                 rt->rt_flags = (rt->rt_flags &
  411                                     ~rtm->rtm_fmask) |
  412                                     (rtm->rtm_flags & rtm->rtm_fmask);
  413 
  414                         rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
  415                             &rt->rt_rmx);
  416                         rtm->rtm_index = rt->rt_ifp->if_index;
  417                         if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
  418                                 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info);
  419                         if (genmask)
  420                                 rt->rt_genmask = genmask;
  421                         if (info.rti_info[RTAX_LABEL] != NULL) {
  422                                 char *rtlabel = ((struct sockaddr_rtlabel *)
  423                                     info.rti_info[RTAX_LABEL])->sr_label;
  424                                 rtlabel_unref(rt->rt_labelid);
  425                                 rt->rt_labelid =
  426                                     rtlabel_name2id(rtlabel);
  427                         }
  428                         if_group_routechange(dst, netmask);
  429                         /* FALLTHROUGH */
  430                 case RTM_LOCK:
  431                         rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
  432                         rt->rt_rmx.rmx_locks |=
  433                             (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
  434                         break;
  435                 }
  436                 break;
  437 
  438         default:
  439                 error = EOPNOTSUPP;
  440                 break;
  441         }
  442 
  443 flush:
  444         if (rtm) {
  445                 if (error)
  446                         rtm->rtm_errno = error;
  447                 else 
  448                         rtm->rtm_flags |= RTF_DONE;
  449         }
  450         if (rt)
  451                 rtfree(rt);
  452 
  453         /*
  454          * Check to see if we don't want our own messages.
  455          */
  456         if (!(so->so_options & SO_USELOOPBACK)) {
  457                 if (route_cb.any_count <= 1) {
  458                         if (rtm)
  459                                 Free(rtm);
  460                         m_freem(m);
  461                         return (error);
  462                 }
  463                 /* There is another listener, so construct message */
  464                 rp = sotorawcb(so);
  465         }
  466         if (rp)
  467                 rp->rcb_proto.sp_family = 0; /* Avoid us */
  468         if (dst)
  469                 route_proto.sp_protocol = dst->sa_family;
  470         if (rtm) {
  471                 m_copyback(m, 0, rtm->rtm_msglen, rtm);
  472                 if (m->m_pkthdr.len < rtm->rtm_msglen) {
  473                         m_freem(m);
  474                         m = NULL;
  475                 } else if (m->m_pkthdr.len > rtm->rtm_msglen)
  476                         m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
  477                 Free(rtm);
  478         }
  479         if (m)
  480                 raw_input(m, &route_proto, &route_src, &route_dst);
  481         if (rp)
  482                 rp->rcb_proto.sp_family = PF_ROUTE;
  483 
  484         return (error);
  485 }
  486 
  487 void
  488 rt_setmetrics(u_long which, struct rt_metrics *in, struct rt_kmetrics *out)
  489 {
  490         if (which & RTV_MTU)
  491                 out->rmx_mtu = in->rmx_mtu;
  492         if (which & RTV_EXPIRE)
  493                 out->rmx_expire = in->rmx_expire;
  494 }
  495 
  496 void
  497 rt_getmetrics(struct rt_kmetrics *in, struct rt_metrics *out)
  498 {
  499         bzero(out, sizeof(*out));
  500         out->rmx_locks = in->rmx_locks;
  501         out->rmx_mtu = in->rmx_mtu;
  502         out->rmx_expire = in->rmx_expire;
  503         out->rmx_pksent = in->rmx_pksent;
  504 }
  505 
  506 #define ROUNDUP(a) \
  507         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
  508 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
  509 
  510 static void
  511 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
  512 {
  513         struct sockaddr *sa;
  514         int              i;
  515 
  516         bzero(rtinfo->rti_info, sizeof(rtinfo->rti_info));
  517         for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
  518                 if ((rtinfo->rti_addrs & (1 << i)) == 0)
  519                         continue;
  520                 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
  521                 ADVANCE(cp, sa);
  522         }
  523 }
  524 
  525 static struct mbuf *
  526 rt_msg1(int type, struct rt_addrinfo *rtinfo)
  527 {
  528         struct rt_msghdr        *rtm;
  529         struct mbuf             *m;
  530         int                      i;
  531         struct sockaddr         *sa;
  532         int                      len, dlen;
  533 
  534         switch (type) {
  535         case RTM_DELADDR:
  536         case RTM_NEWADDR:
  537                 len = sizeof(struct ifa_msghdr);
  538                 break;
  539         case RTM_IFINFO:
  540                 len = sizeof(struct if_msghdr);
  541                 break;
  542         case RTM_IFANNOUNCE:
  543                 len = sizeof(struct if_announcemsghdr);
  544                 break;
  545         default:
  546                 len = sizeof(struct rt_msghdr);
  547                 break;
  548         }
  549         if (len > MCLBYTES)
  550                 panic("rt_msg1");
  551         m = m_gethdr(M_DONTWAIT, MT_DATA);
  552         if (m && len > MHLEN) {
  553                 MCLGET(m, M_DONTWAIT);
  554                 if ((m->m_flags & M_EXT) == 0) {
  555                         m_free(m);
  556                         m = NULL;
  557                 }
  558         }
  559         if (m == 0)
  560                 return (m);
  561         m->m_pkthdr.len = m->m_len = len;
  562         m->m_pkthdr.rcvif = NULL;
  563         rtm = mtod(m, struct rt_msghdr *);
  564         bzero(rtm, len);
  565         for (i = 0; i < RTAX_MAX; i++) {
  566                 if ((sa = rtinfo->rti_info[i]) == NULL)
  567                         continue;
  568                 rtinfo->rti_addrs |= (1 << i);
  569                 dlen = ROUNDUP(sa->sa_len);
  570                 m_copyback(m, len, dlen, sa);
  571                 len += dlen;
  572         }
  573         if (m->m_pkthdr.len != len) {
  574                 m_freem(m);
  575                 return (NULL);
  576         }
  577         rtm->rtm_msglen = len;
  578         rtm->rtm_version = RTM_VERSION;
  579         rtm->rtm_type = type;
  580         return (m);
  581 }
  582 
  583 static int
  584 rt_msg2(int type, struct rt_addrinfo *rtinfo, caddr_t cp, struct walkarg *w)
  585 {
  586         int             i;
  587         int             len, dlen, second_time = 0;
  588         caddr_t         cp0;
  589 
  590         rtinfo->rti_addrs = 0;
  591 again:
  592         switch (type) {
  593         case RTM_DELADDR:
  594         case RTM_NEWADDR:
  595                 len = sizeof(struct ifa_msghdr);
  596                 break;
  597         case RTM_IFINFO:
  598                 len = sizeof(struct if_msghdr);
  599                 break;
  600         default:
  601                 len = sizeof(struct rt_msghdr);
  602                 break;
  603         }
  604         if ((cp0 = cp) != NULL)
  605                 cp += len;
  606         for (i = 0; i < RTAX_MAX; i++) {
  607                 struct sockaddr *sa;
  608 
  609                 if ((sa = rtinfo->rti_info[i]) == 0)
  610                         continue;
  611                 rtinfo->rti_addrs |= (1 << i);
  612                 dlen = ROUNDUP(sa->sa_len);
  613                 if (cp) {
  614                         bcopy(sa, cp, (size_t)dlen);
  615                         cp += dlen;
  616                 }
  617                 len += dlen;
  618         }
  619         if (cp == 0 && w != NULL && !second_time) {
  620                 struct walkarg *rw = w;
  621 
  622                 rw->w_needed += len;
  623                 if (rw->w_needed <= 0 && rw->w_where) {
  624                         if (rw->w_tmemsize < len) {
  625                                 if (rw->w_tmem)
  626                                         free(rw->w_tmem, M_RTABLE);
  627                                 rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT);
  628                                 if (rw->w_tmem)
  629                                         rw->w_tmemsize = len;
  630                         }
  631                         if (rw->w_tmem) {
  632                                 cp = rw->w_tmem;
  633                                 second_time = 1;
  634                                 goto again;
  635                         } else
  636                                 rw->w_where = 0;
  637                 }
  638         }
  639         if (cp) {
  640                 struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
  641 
  642                 rtm->rtm_version = RTM_VERSION;
  643                 rtm->rtm_type = type;
  644                 rtm->rtm_msglen = len;
  645         }
  646         return (len);
  647 }
  648 
  649 /*
  650  * This routine is called to generate a message from the routing
  651  * socket indicating that a redirect has occurred, a routing lookup
  652  * has failed, or that a protocol has detected timeouts to a particular
  653  * destination.
  654  */
  655 void
  656 rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags,
  657     struct ifnet *ifp, int error, u_int tableid)
  658 {
  659         struct rt_msghdr        *rtm;
  660         struct mbuf             *m;
  661         struct sockaddr         *sa = rtinfo->rti_info[RTAX_DST];
  662 
  663         if (route_cb.any_count == 0)
  664                 return;
  665         m = rt_msg1(type, rtinfo);
  666         if (m == 0)
  667                 return;
  668         rtm = mtod(m, struct rt_msghdr *);
  669         rtm->rtm_flags = RTF_DONE | flags;
  670         rtm->rtm_errno = error;
  671         rtm->rtm_tableid = tableid;
  672         rtm->rtm_addrs = rtinfo->rti_addrs;
  673         if (ifp != NULL)
  674                 rtm->rtm_index = ifp->if_index;
  675         if (sa == NULL)
  676                 route_proto.sp_protocol = 0;
  677         else
  678                 route_proto.sp_protocol = sa->sa_family;
  679         raw_input(m, &route_proto, &route_src, &route_dst);
  680 }
  681 
  682 /*
  683  * This routine is called to generate a message from the routing
  684  * socket indicating that the status of a network interface has changed.
  685  */
  686 void
  687 rt_ifmsg(struct ifnet *ifp)
  688 {
  689         struct if_msghdr        *ifm;
  690         struct mbuf             *m;
  691         struct rt_addrinfo       info;
  692 
  693         if (route_cb.any_count == 0)
  694                 return;
  695         bzero(&info, sizeof(info));
  696         m = rt_msg1(RTM_IFINFO, &info);
  697         if (m == 0)
  698                 return;
  699         ifm = mtod(m, struct if_msghdr *);
  700         ifm->ifm_index = ifp->if_index;
  701         ifm->ifm_flags = ifp->if_flags;
  702         ifm->ifm_data = ifp->if_data;
  703         ifm->ifm_addrs = 0;
  704         route_proto.sp_protocol = 0;
  705         raw_input(m, &route_proto, &route_src, &route_dst);
  706 }
  707 
  708 /*
  709  * This is called to generate messages from the routing socket
  710  * indicating a network interface has had addresses associated with it.
  711  * if we ever reverse the logic and replace messages TO the routing
  712  * socket indicate a request to configure interfaces, then it will
  713  * be unnecessary as the routing socket will automatically generate
  714  * copies of it.
  715  */
  716 void
  717 rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
  718 {
  719         struct rt_addrinfo       info;
  720         struct sockaddr         *sa = NULL;
  721         int                      pass;
  722         struct mbuf             *m = NULL;
  723         struct ifnet            *ifp = ifa->ifa_ifp;
  724 
  725         if (route_cb.any_count == 0)
  726                 return;
  727         for (pass = 1; pass < 3; pass++) {
  728                 bzero(&info, sizeof(info));
  729                 if ((cmd == RTM_ADD && pass == 1) ||
  730                     (cmd == RTM_DELETE && pass == 2)) {
  731                         struct ifa_msghdr       *ifam;
  732                         int                      ncmd;
  733 
  734                         if (cmd == RTM_ADD)
  735                                 ncmd = RTM_NEWADDR;
  736                         else
  737                                 ncmd = RTM_DELADDR;
  738 
  739                         ifaaddr = sa = ifa->ifa_addr;
  740                         ifpaddr = TAILQ_FIRST(&ifp->if_addrlist)->ifa_addr;
  741                         netmask = ifa->ifa_netmask;
  742                         brdaddr = ifa->ifa_dstaddr;
  743                         if ((m = rt_msg1(ncmd, &info)) == NULL)
  744                                 continue;
  745                         ifam = mtod(m, struct ifa_msghdr *);
  746                         ifam->ifam_index = ifp->if_index;
  747                         ifam->ifam_metric = ifa->ifa_metric;
  748                         ifam->ifam_flags = ifa->ifa_flags;
  749                         ifam->ifam_addrs = info.rti_addrs;
  750                 }
  751                 if ((cmd == RTM_ADD && pass == 2) ||
  752                     (cmd == RTM_DELETE && pass == 1)) {
  753                         struct rt_msghdr *rtm;
  754                         
  755                         if (rt == 0)
  756                                 continue;
  757                         netmask = rt_mask(rt);
  758                         dst = sa = rt_key(rt);
  759                         gate = rt->rt_gateway;
  760                         if ((m = rt_msg1(cmd, &info)) == NULL)
  761                                 continue;
  762                         rtm = mtod(m, struct rt_msghdr *);
  763                         rtm->rtm_index = ifp->if_index;
  764                         rtm->rtm_flags |= rt->rt_flags;
  765                         rtm->rtm_errno = error;
  766                         rtm->rtm_addrs = info.rti_addrs;
  767                 }
  768                 if (sa == NULL)
  769                         route_proto.sp_protocol = 0;
  770                 else
  771                         route_proto.sp_protocol = sa->sa_family;
  772                 raw_input(m, &route_proto, &route_src, &route_dst);
  773         }
  774 }
  775 
  776 /*
  777  * This is called to generate routing socket messages indicating
  778  * network interface arrival and departure.
  779  */
  780 void
  781 rt_ifannouncemsg(struct ifnet *ifp, int what)
  782 {
  783         struct if_announcemsghdr        *ifan;
  784         struct mbuf                     *m;
  785         struct rt_addrinfo               info;
  786 
  787         if (route_cb.any_count == 0)
  788                 return;
  789         bzero(&info, sizeof(info));
  790         m = rt_msg1(RTM_IFANNOUNCE, &info);
  791         if (m == 0)
  792                 return;
  793         ifan = mtod(m, struct if_announcemsghdr *);
  794         ifan->ifan_index = ifp->if_index;
  795         strlcpy(ifan->ifan_name, ifp->if_xname, sizeof(ifan->ifan_name));
  796         ifan->ifan_what = what;
  797         route_proto.sp_protocol = 0;
  798         raw_input(m, &route_proto, &route_src, &route_dst);
  799 }
  800 
  801 /*
  802  * This is used in dumping the kernel table via sysctl().
  803  */
  804 int
  805 sysctl_dumpentry(struct radix_node *rn, void *v)
  806 {
  807         struct walkarg          *w = v;
  808         struct rtentry          *rt = (struct rtentry *)rn;
  809         int                      error = 0, size;
  810         struct rt_addrinfo       info;
  811         struct sockaddr_rtlabel  sa_rt;
  812         const char              *label;
  813 
  814         if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
  815                 return 0;
  816         bzero(&info, sizeof(info));
  817         dst = rt_key(rt);
  818         gate = rt->rt_gateway;
  819         netmask = rt_mask(rt);
  820         genmask = rt->rt_genmask;
  821         if (rt->rt_ifp) {
  822                 ifpaddr = TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
  823                 ifaaddr = rt->rt_ifa->ifa_addr;
  824                 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
  825                         brdaddr = rt->rt_ifa->ifa_dstaddr;
  826         }
  827         if (rt->rt_labelid) {
  828                 bzero(&sa_rt, sizeof(sa_rt));
  829                 sa_rt.sr_len = sizeof(sa_rt);
  830                 label = rtlabel_id2name(rt->rt_labelid);
  831                 if (label != NULL) {
  832                         strlcpy(sa_rt.sr_label, label,
  833                             sizeof(sa_rt.sr_label));
  834                         info.rti_info[RTAX_LABEL] =
  835                             (struct sockaddr *)&sa_rt;
  836                 }
  837         }
  838 
  839         size = rt_msg2(RTM_GET, &info, NULL, w);
  840         if (w->w_where && w->w_tmem && w->w_needed <= 0) {
  841                 struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
  842 
  843                 rtm->rtm_flags = rt->rt_flags;
  844                 rtm->rtm_use = 0;
  845                 rt_getmetrics(&rt->rt_rmx, &rtm->rtm_rmx);
  846                 rtm->rtm_rmx.rmx_refcnt = (u_long)rt->rt_refcnt;
  847                 rtm->rtm_index = rt->rt_ifp->if_index;
  848                 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
  849                 rtm->rtm_addrs = info.rti_addrs;
  850                 if ((error = copyout(rtm, w->w_where, size)) != 0)
  851                         w->w_where = NULL;
  852                 else
  853                         w->w_where += size;
  854         }
  855         return (error);
  856 }
  857 
  858 int
  859 sysctl_iflist(int af, struct walkarg *w)
  860 {
  861         struct ifnet            *ifp;
  862         struct ifaddr           *ifa;
  863         struct rt_addrinfo       info;
  864         int                      len, error = 0;
  865 
  866         bzero(&info, sizeof(info));
  867         TAILQ_FOREACH(ifp, &ifnet, if_list) {
  868                 if (w->w_arg && w->w_arg != ifp->if_index)
  869                         continue;
  870                 ifa = TAILQ_FIRST(&ifp->if_addrlist);
  871                 if (!ifa)
  872                         continue;
  873                 ifpaddr = ifa->ifa_addr;
  874                 len = rt_msg2(RTM_IFINFO, &info, 0, w);
  875                 ifpaddr = 0;
  876                 if (w->w_where && w->w_tmem && w->w_needed <= 0) {
  877                         struct if_msghdr *ifm;
  878 
  879                         ifm = (struct if_msghdr *)w->w_tmem;
  880                         ifm->ifm_index = ifp->if_index;
  881                         ifm->ifm_flags = ifp->if_flags;
  882                         ifm->ifm_data = ifp->if_data;
  883                         ifm->ifm_addrs = info.rti_addrs;
  884                         error = copyout(ifm, w->w_where, len);
  885                         if (error)
  886                                 return (error);
  887                         w->w_where += len;
  888                 }
  889                 while ((ifa = TAILQ_NEXT(ifa, ifa_list)) !=
  890                     TAILQ_END(&ifp->if_addrlist)) {
  891                         if (af && af != ifa->ifa_addr->sa_family)
  892                                 continue;
  893                         ifaaddr = ifa->ifa_addr;
  894                         netmask = ifa->ifa_netmask;
  895                         brdaddr = ifa->ifa_dstaddr;
  896                         len = rt_msg2(RTM_NEWADDR, &info, 0, w);
  897                         if (w->w_where && w->w_tmem && w->w_needed <= 0) {
  898                                 struct ifa_msghdr *ifam;
  899 
  900                                 ifam = (struct ifa_msghdr *)w->w_tmem;
  901                                 ifam->ifam_index = ifa->ifa_ifp->if_index;
  902                                 ifam->ifam_flags = ifa->ifa_flags;
  903                                 ifam->ifam_metric = ifa->ifa_metric;
  904                                 ifam->ifam_addrs = info.rti_addrs;
  905                                 error = copyout(w->w_tmem, w->w_where, len);
  906                                 if (error)
  907                                         return (error);
  908                                 w->w_where += len;
  909                         }
  910                 }
  911                 ifaaddr = netmask = brdaddr = 0;
  912         }
  913         return (0);
  914 }
  915 
  916 int
  917 sysctl_rtable(int *name, u_int namelen, void *where, size_t *given, void *new,
  918     size_t newlen)
  919 {
  920         struct radix_node_head  *rnh;
  921         int                      i, s, error = EINVAL;
  922         u_char                   af;
  923         struct walkarg           w;
  924         u_int                    tableid = 0;
  925 
  926         if (new)
  927                 return (EPERM);
  928         if (namelen < 3 || namelen > 4)
  929                 return (EINVAL);
  930         af = name[0];
  931         bzero(&w, sizeof(w));
  932         w.w_where = where;
  933         w.w_given = *given;
  934         w.w_needed = 0 - w.w_given;
  935         w.w_op = name[1];
  936         w.w_arg = name[2];
  937 
  938         if (namelen == 4) {
  939                 tableid = name[3];
  940                 if (!rtable_exists(tableid))
  941                         return (EINVAL);
  942         }
  943 
  944         s = splsoftnet();
  945         switch (w.w_op) {
  946 
  947         case NET_RT_DUMP:
  948         case NET_RT_FLAGS:
  949                 for (i = 1; i <= AF_MAX; i++)
  950                         if ((rnh = rt_gettable(i, tableid)) != NULL &&
  951                             (af == 0 || af == i) &&
  952                             (error = (*rnh->rnh_walktree)(rnh,
  953                             sysctl_dumpentry, &w)))
  954                                 break;
  955                 break;
  956 
  957         case NET_RT_IFLIST:
  958                 error = sysctl_iflist(af, &w);
  959                 break;
  960 
  961         case NET_RT_STATS:
  962                 error = sysctl_rdstruct(where, given, new,
  963                     &rtstat, sizeof(rtstat));
  964                 splx(s);
  965                 return (error);
  966         }
  967         splx(s);
  968         if (w.w_tmem)
  969                 free(w.w_tmem, M_RTABLE);
  970         w.w_needed += w.w_given;
  971         if (where) {
  972                 *given = w.w_where - (caddr_t)where;
  973                 if (*given < w.w_needed)
  974                         return (ENOMEM);
  975         } else
  976                 *given = (11 * w.w_needed) / 10;
  977 
  978         return (error);
  979 }
  980 
  981 /*
  982  * Definitions of protocols supported in the ROUTE domain.
  983  */
  984 
  985 extern  struct domain routedomain;              /* or at least forward */
  986 
  987 struct protosw routesw[] = {
  988 { SOCK_RAW,     &routedomain,   0,              PR_ATOMIC|PR_ADDR,
  989   raw_input,    route_output,   raw_ctlinput,   0,
  990   route_usrreq,
  991   raw_init,     0,              0,              0,
  992   sysctl_rtable,
  993 }
  994 };
  995 
  996 struct domain routedomain =
  997     { PF_ROUTE, "route", route_init, 0, 0,
  998       routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };

/* [<][>][^][v][top][bottom][index][help] */