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


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

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

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

    1 /*
    2  * Copyright (c) 1988, 1991, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by the University of
   16  *      California, Berkeley and its contributors.
   17  * 4. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  *      @(#)rtsock.c    8.7 (Berkeley) 10/12/95
   34  * $FreeBSD: releng/5.0/sys/net/rtsock.c 104302 2002-10-01 15:48:31Z phk $
   35  */
   36 
   37 
   38 #include <sys/param.h>
   39 #include <sys/domain.h>
   40 #include <sys/kernel.h>
   41 #include <sys/jail.h>
   42 #include <sys/malloc.h>
   43 #include <sys/mbuf.h>
   44 #include <sys/proc.h>
   45 #include <sys/protosw.h>
   46 #include <sys/signalvar.h>
   47 #include <sys/socket.h>
   48 #include <sys/socketvar.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/systm.h>
   51 
   52 #include <net/if.h>
   53 #include <net/raw_cb.h>
   54 #include <net/route.h>
   55 
   56 MALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables");
   57 
   58 static struct   sockaddr route_dst = { 2, PF_ROUTE, };
   59 static struct   sockaddr route_src = { 2, PF_ROUTE, };
   60 static struct   sockaddr sa_zero   = { sizeof(sa_zero), AF_INET, };
   61 static struct   sockproto route_proto = { PF_ROUTE, };
   62 
   63 struct walkarg {
   64         int     w_tmemsize;
   65         int     w_op, w_arg;
   66         caddr_t w_tmem;
   67         struct sysctl_req *w_req;
   68 };
   69 
   70 static struct mbuf *
   71                 rt_msg1(int, struct rt_addrinfo *);
   72 static int      rt_msg2(int, struct rt_addrinfo *, caddr_t, struct walkarg *);
   73 static int      rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
   74 static int      sysctl_dumpentry(struct radix_node *rn, void *vw);
   75 static int      sysctl_iflist(int af, struct walkarg *w);
   76 static int       route_output(struct mbuf *, struct socket *);
   77 static void      rt_setmetrics(u_long, struct rt_metrics *, struct rt_metrics *);
   78 
   79 /* Sleazy use of local variables throughout file, warning!!!! */
   80 #define dst     info.rti_info[RTAX_DST]
   81 #define gate    info.rti_info[RTAX_GATEWAY]
   82 #define netmask info.rti_info[RTAX_NETMASK]
   83 #define genmask info.rti_info[RTAX_GENMASK]
   84 #define ifpaddr info.rti_info[RTAX_IFP]
   85 #define ifaaddr info.rti_info[RTAX_IFA]
   86 #define brdaddr info.rti_info[RTAX_BRD]
   87 
   88 /*
   89  * It really doesn't make any sense at all for this code to share much
   90  * with raw_usrreq.c, since its functionality is so restricted.  XXX
   91  */
   92 static int
   93 rts_abort(struct socket *so)
   94 {
   95         int s, error;
   96         s = splnet();
   97         error = raw_usrreqs.pru_abort(so);
   98         splx(s);
   99         return error;
  100 }
  101 
  102 /* pru_accept is EOPNOTSUPP */
  103 
  104 static int
  105 rts_attach(struct socket *so, int proto, struct thread *td)
  106 {
  107         struct rawcb *rp;
  108         int s, error;
  109 
  110         if (sotorawcb(so) != 0)
  111                 return EISCONN; /* XXX panic? */
  112         /* XXX */
  113         MALLOC(rp, struct rawcb *, sizeof *rp, M_PCB, M_WAITOK | M_ZERO);
  114         if (rp == 0)
  115                 return ENOBUFS;
  116 
  117         /*
  118          * The splnet() is necessary to block protocols from sending
  119          * error notifications (like RTM_REDIRECT or RTM_LOSING) while
  120          * this PCB is extant but incompletely initialized.
  121          * Probably we should try to do more of this work beforehand and
  122          * eliminate the spl.
  123          */
  124         s = splnet();
  125         so->so_pcb = (caddr_t)rp;
  126         error = raw_attach(so, proto);
  127         rp = sotorawcb(so);
  128         if (error) {
  129                 splx(s);
  130                 so->so_pcb = NULL;
  131                 free(rp, M_PCB);
  132                 return error;
  133         }
  134         switch(rp->rcb_proto.sp_protocol) {
  135         case AF_INET:
  136                 route_cb.ip_count++;
  137                 break;
  138         case AF_INET6:
  139                 route_cb.ip6_count++;
  140                 break;
  141         case AF_IPX:
  142                 route_cb.ipx_count++;
  143                 break;
  144         case AF_NS:
  145                 route_cb.ns_count++;
  146                 break;
  147         }
  148         rp->rcb_faddr = &route_src;
  149         route_cb.any_count++;
  150         soisconnected(so);
  151         so->so_options |= SO_USELOOPBACK;
  152         splx(s);
  153         return 0;
  154 }
  155 
  156 static int
  157 rts_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
  158 {
  159         int s, error;
  160         s = splnet();
  161         error = raw_usrreqs.pru_bind(so, nam, td); /* xxx just EINVAL */
  162         splx(s);
  163         return error;
  164 }
  165 
  166 static int
  167 rts_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
  168 {
  169         int s, error;
  170         s = splnet();
  171         error = raw_usrreqs.pru_connect(so, nam, td); /* XXX just EINVAL */
  172         splx(s);
  173         return error;
  174 }
  175 
  176 /* pru_connect2 is EOPNOTSUPP */
  177 /* pru_control is EOPNOTSUPP */
  178 
  179 static int
  180 rts_detach(struct socket *so)
  181 {
  182         struct rawcb *rp = sotorawcb(so);
  183         int s, error;
  184 
  185         s = splnet();
  186         if (rp != 0) {
  187                 switch(rp->rcb_proto.sp_protocol) {
  188                 case AF_INET:
  189                         route_cb.ip_count--;
  190                         break;
  191                 case AF_INET6:
  192                         route_cb.ip6_count--;
  193                         break;
  194                 case AF_IPX:
  195                         route_cb.ipx_count--;
  196                         break;
  197                 case AF_NS:
  198                         route_cb.ns_count--;
  199                         break;
  200                 }
  201                 route_cb.any_count--;
  202         }
  203         error = raw_usrreqs.pru_detach(so);
  204         splx(s);
  205         return error;
  206 }
  207 
  208 static int
  209 rts_disconnect(struct socket *so)
  210 {
  211         int s, error;
  212         s = splnet();
  213         error = raw_usrreqs.pru_disconnect(so);
  214         splx(s);
  215         return error;
  216 }
  217 
  218 /* pru_listen is EOPNOTSUPP */
  219 
  220 static int
  221 rts_peeraddr(struct socket *so, struct sockaddr **nam)
  222 {
  223         int s, error;
  224         s = splnet();
  225         error = raw_usrreqs.pru_peeraddr(so, nam);
  226         splx(s);
  227         return error;
  228 }
  229 
  230 /* pru_rcvd is EOPNOTSUPP */
  231 /* pru_rcvoob is EOPNOTSUPP */
  232 
  233 static int
  234 rts_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
  235          struct mbuf *control, struct thread *td)
  236 {
  237         int s, error;
  238         s = splnet();
  239         error = raw_usrreqs.pru_send(so, flags, m, nam, control, td);
  240         splx(s);
  241         return error;
  242 }
  243 
  244 /* pru_sense is null */
  245 
  246 static int
  247 rts_shutdown(struct socket *so)
  248 {
  249         int s, error;
  250         s = splnet();
  251         error = raw_usrreqs.pru_shutdown(so);
  252         splx(s);
  253         return error;
  254 }
  255 
  256 static int
  257 rts_sockaddr(struct socket *so, struct sockaddr **nam)
  258 {
  259         int s, error;
  260         s = splnet();
  261         error = raw_usrreqs.pru_sockaddr(so, nam);
  262         splx(s);
  263         return error;
  264 }
  265 
  266 static struct pr_usrreqs route_usrreqs = {
  267         rts_abort, pru_accept_notsupp, rts_attach, rts_bind, rts_connect,
  268         pru_connect2_notsupp, pru_control_notsupp, rts_detach, rts_disconnect,
  269         pru_listen_notsupp, rts_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp,
  270         rts_send, pru_sense_null, rts_shutdown, rts_sockaddr,
  271         sosend, soreceive, sopoll
  272 };
  273 
  274 /*ARGSUSED*/
  275 static int
  276 route_output(m, so)
  277         register struct mbuf *m;
  278         struct socket *so;
  279 {
  280         register struct rt_msghdr *rtm = 0;
  281         register struct rtentry *rt = 0;
  282         struct rtentry *saved_nrt = 0;
  283         struct radix_node_head *rnh;
  284         struct rt_addrinfo info;
  285         int len, error = 0;
  286         struct ifnet *ifp = 0;
  287         struct ifaddr *ifa = 0;
  288 
  289 #define senderr(e) { error = e; goto flush;}
  290         if (m == 0 || ((m->m_len < sizeof(long)) &&
  291                        (m = m_pullup(m, sizeof(long))) == 0))
  292                 return (ENOBUFS);
  293         if ((m->m_flags & M_PKTHDR) == 0)
  294                 panic("route_output");
  295         len = m->m_pkthdr.len;
  296         if (len < sizeof(*rtm) ||
  297             len != mtod(m, struct rt_msghdr *)->rtm_msglen) {
  298                 dst = 0;
  299                 senderr(EINVAL);
  300         }
  301         R_Malloc(rtm, struct rt_msghdr *, len);
  302         if (rtm == 0) {
  303                 dst = 0;
  304                 senderr(ENOBUFS);
  305         }
  306         m_copydata(m, 0, len, (caddr_t)rtm);
  307         if (rtm->rtm_version != RTM_VERSION) {
  308                 dst = 0;
  309                 senderr(EPROTONOSUPPORT);
  310         }
  311         rtm->rtm_pid = curproc->p_pid;
  312         bzero(&info, sizeof(info));
  313         info.rti_addrs = rtm->rtm_addrs;
  314         if (rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info)) {
  315                 dst = 0;
  316                 senderr(EINVAL);
  317         }
  318         info.rti_flags = rtm->rtm_flags;
  319         if (dst == 0 || (dst->sa_family >= AF_MAX)
  320             || (gate != 0 && (gate->sa_family >= AF_MAX)))
  321                 senderr(EINVAL);
  322         if (genmask) {
  323                 struct radix_node *t;
  324                 t = rn_addmask((caddr_t)genmask, 0, 1);
  325                 if (t && Bcmp((caddr_t *)genmask + 1, (caddr_t *)t->rn_key + 1,
  326                               *(u_char *)t->rn_key - 1) == 0)
  327                         genmask = (struct sockaddr *)(t->rn_key);
  328                 else
  329                         senderr(ENOBUFS);
  330         }
  331 
  332         /*
  333          * Verify that the caller has the appropriate privilege; RTM_GET
  334          * is the only operation the non-superuser is allowed.
  335          */
  336         if (rtm->rtm_type != RTM_GET && (error = suser(curthread)) != 0)
  337                 senderr(error);
  338 
  339         switch (rtm->rtm_type) {
  340 
  341         case RTM_ADD:
  342                 if (gate == 0)
  343                         senderr(EINVAL);
  344                 error = rtrequest1(RTM_ADD, &info, &saved_nrt);
  345                 if (error == 0 && saved_nrt) {
  346                         rt_setmetrics(rtm->rtm_inits,
  347                                 &rtm->rtm_rmx, &saved_nrt->rt_rmx);
  348                         saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
  349                         saved_nrt->rt_rmx.rmx_locks |=
  350                                 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
  351                         saved_nrt->rt_refcnt--;
  352                         saved_nrt->rt_genmask = genmask;
  353                 }
  354                 break;
  355 
  356         case RTM_DELETE:
  357                 error = rtrequest1(RTM_DELETE, &info, &saved_nrt);
  358                 if (error == 0) {
  359                         if ((rt = saved_nrt))
  360                                 rt->rt_refcnt++;
  361                         goto report;
  362                 }
  363                 break;
  364 
  365         case RTM_GET:
  366         case RTM_CHANGE:
  367         case RTM_LOCK:
  368                 if ((rnh = rt_tables[dst->sa_family]) == 0) {
  369                         senderr(EAFNOSUPPORT);
  370                 } else if ((rt = (struct rtentry *)
  371                                 rnh->rnh_lookup(dst, netmask, rnh)) != NULL)
  372                         rt->rt_refcnt++;
  373                 else
  374                         senderr(ESRCH);
  375                 switch(rtm->rtm_type) {
  376 
  377                 case RTM_GET:
  378                 report:
  379                         dst = rt_key(rt);
  380                         gate = rt->rt_gateway;
  381                         netmask = rt_mask(rt);
  382                         genmask = rt->rt_genmask;
  383                         if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
  384                                 ifp = rt->rt_ifp;
  385                                 if (ifp) {
  386                                         ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
  387                                         ifaaddr = rt->rt_ifa->ifa_addr;
  388                                         if (ifp->if_flags & IFF_POINTOPOINT)
  389                                                 brdaddr = rt->rt_ifa->ifa_dstaddr;
  390                                         rtm->rtm_index = ifp->if_index;
  391                                 } else {
  392                                         ifpaddr = 0;
  393                                         ifaaddr = 0;
  394                                 }
  395                         }
  396                         len = rt_msg2(rtm->rtm_type, &info, (caddr_t)0,
  397                                 (struct walkarg *)0);
  398                         if (len > rtm->rtm_msglen) {
  399                                 struct rt_msghdr *new_rtm;
  400                                 R_Malloc(new_rtm, struct rt_msghdr *, len);
  401                                 if (new_rtm == 0)
  402                                         senderr(ENOBUFS);
  403                                 Bcopy(rtm, new_rtm, rtm->rtm_msglen);
  404                                 Free(rtm); rtm = new_rtm;
  405                         }
  406                         (void)rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm,
  407                                 (struct walkarg *)0);
  408                         rtm->rtm_flags = rt->rt_flags;
  409                         rtm->rtm_rmx = rt->rt_rmx;
  410                         rtm->rtm_addrs = info.rti_addrs;
  411                         break;
  412 
  413                 case RTM_CHANGE:
  414                         /* new gateway could require new ifaddr, ifp;
  415                            flags may also be different; ifp may be specified
  416                            by ll sockaddr when protocol address is ambiguous */
  417 #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
  418                         if ((rt->rt_flags & RTF_GATEWAY && gate != NULL) ||
  419                             ifpaddr != NULL ||
  420                             (ifaaddr != NULL &&
  421                             !equal(ifaaddr, rt->rt_ifa->ifa_addr))) {
  422                                 if ((error = rt_getifa(&info)) != 0)
  423                                         senderr(error);
  424                         }
  425                         if (gate != NULL &&
  426                             (error = rt_setgate(rt, rt_key(rt), gate)) != 0)
  427                                 senderr(error);
  428                         if ((ifa = info.rti_ifa) != NULL) {
  429                                 register struct ifaddr *oifa = rt->rt_ifa;
  430                                 if (oifa != ifa) {
  431                                     if (oifa && oifa->ifa_rtrequest)
  432                                         oifa->ifa_rtrequest(RTM_DELETE, rt,
  433                                             &info);
  434                                     IFAFREE(rt->rt_ifa);
  435                                     rt->rt_ifa = ifa;
  436                                     ifa->ifa_refcnt++;
  437                                     rt->rt_ifp = info.rti_ifp;
  438                                 }
  439                         }
  440                         rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
  441                                         &rt->rt_rmx);
  442                         if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
  443                                rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info);
  444                         if (genmask)
  445                                 rt->rt_genmask = genmask;
  446                         /* FALLTHROUGH */
  447                 case RTM_LOCK:
  448                         rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
  449                         rt->rt_rmx.rmx_locks |=
  450                                 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
  451                         break;
  452                 }
  453                 break;
  454 
  455         default:
  456                 senderr(EOPNOTSUPP);
  457         }
  458 
  459 flush:
  460         if (rtm) {
  461                 if (error)
  462                         rtm->rtm_errno = error;
  463                 else
  464                         rtm->rtm_flags |= RTF_DONE;
  465         }
  466         if (rt)
  467                 rtfree(rt);
  468     {
  469         register struct rawcb *rp = 0;
  470         /*
  471          * Check to see if we don't want our own messages.
  472          */
  473         if ((so->so_options & SO_USELOOPBACK) == 0) {
  474                 if (route_cb.any_count <= 1) {
  475                         if (rtm)
  476                                 Free(rtm);
  477                         m_freem(m);
  478                         return (error);
  479                 }
  480                 /* There is another listener, so construct message */
  481                 rp = sotorawcb(so);
  482         }
  483         if (rtm) {
  484                 m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
  485                 if (m->m_pkthdr.len < rtm->rtm_msglen) {
  486                         m_freem(m);
  487                         m = NULL;
  488                 } else if (m->m_pkthdr.len > rtm->rtm_msglen)
  489                         m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len);
  490                 Free(rtm);
  491         }
  492         if (rp)
  493                 rp->rcb_proto.sp_family = 0; /* Avoid us */
  494         if (dst)
  495                 route_proto.sp_protocol = dst->sa_family;
  496         if (m)
  497                 raw_input(m, &route_proto, &route_src, &route_dst);
  498         if (rp)
  499                 rp->rcb_proto.sp_family = PF_ROUTE;
  500     }
  501         return (error);
  502 }
  503 
  504 static void
  505 rt_setmetrics(which, in, out)
  506         u_long which;
  507         register struct rt_metrics *in, *out;
  508 {
  509 #define metric(f, e) if (which & (f)) out->e = in->e;
  510         metric(RTV_RPIPE, rmx_recvpipe);
  511         metric(RTV_SPIPE, rmx_sendpipe);
  512         metric(RTV_SSTHRESH, rmx_ssthresh);
  513         metric(RTV_RTT, rmx_rtt);
  514         metric(RTV_RTTVAR, rmx_rttvar);
  515         metric(RTV_HOPCOUNT, rmx_hopcount);
  516         metric(RTV_MTU, rmx_mtu);
  517         metric(RTV_EXPIRE, rmx_expire);
  518 #undef metric
  519 }
  520 
  521 #define ROUNDUP(a) \
  522         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
  523 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
  524 
  525 
  526 /*
  527  * Extract the addresses of the passed sockaddrs.
  528  * Do a little sanity checking so as to avoid bad memory references.
  529  * This data is derived straight from userland.
  530  */
  531 static int
  532 rt_xaddrs(cp, cplim, rtinfo)
  533         register caddr_t cp, cplim;
  534         register struct rt_addrinfo *rtinfo;
  535 {
  536         register struct sockaddr *sa;
  537         register int i;
  538 
  539         for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
  540                 if ((rtinfo->rti_addrs & (1 << i)) == 0)
  541                         continue;
  542                 sa = (struct sockaddr *)cp;
  543                 /*
  544                  * It won't fit.
  545                  */
  546                 if ( (cp + sa->sa_len) > cplim ) {
  547                         return (EINVAL);
  548                 }
  549 
  550                 /*
  551                  * there are no more.. quit now
  552                  * If there are more bits, they are in error.
  553                  * I've seen this. route(1) can evidently generate these. 
  554                  * This causes kernel to core dump.
  555                  * for compatibility, If we see this, point to a safe address.
  556                  */
  557                 if (sa->sa_len == 0) {
  558                         rtinfo->rti_info[i] = &sa_zero;
  559                         return (0); /* should be EINVAL but for compat */
  560                 }
  561 
  562                 /* accept it */
  563                 rtinfo->rti_info[i] = sa;
  564                 ADVANCE(cp, sa);
  565         }
  566         return (0);
  567 }
  568 
  569 static struct mbuf *
  570 rt_msg1(type, rtinfo)
  571         int type;
  572         register struct rt_addrinfo *rtinfo;
  573 {
  574         register struct rt_msghdr *rtm;
  575         register struct mbuf *m;
  576         register int i;
  577         register struct sockaddr *sa;
  578         int len, dlen;
  579 
  580         switch (type) {
  581 
  582         case RTM_DELADDR:
  583         case RTM_NEWADDR:
  584                 len = sizeof(struct ifa_msghdr);
  585                 break;
  586 
  587         case RTM_DELMADDR:
  588         case RTM_NEWMADDR:
  589                 len = sizeof(struct ifma_msghdr);
  590                 break;
  591 
  592         case RTM_IFINFO:
  593                 len = sizeof(struct if_msghdr);
  594                 break;
  595 
  596         case RTM_IFANNOUNCE:
  597                 len = sizeof(struct if_announcemsghdr);
  598                 break;
  599 
  600         default:
  601                 len = sizeof(struct rt_msghdr);
  602         }
  603         if (len > MCLBYTES)
  604                 panic("rt_msg1");
  605         m = m_gethdr(M_DONTWAIT, MT_DATA);
  606         if (m && len > MHLEN) {
  607                 MCLGET(m, M_DONTWAIT);
  608                 if ((m->m_flags & M_EXT) == 0) {
  609                         m_free(m);
  610                         m = NULL;
  611                 }
  612         }
  613         if (m == 0)
  614                 return (m);
  615         m->m_pkthdr.len = m->m_len = len;
  616         m->m_pkthdr.rcvif = 0;
  617         rtm = mtod(m, struct rt_msghdr *);
  618         bzero((caddr_t)rtm, len);
  619         for (i = 0; i < RTAX_MAX; i++) {
  620                 if ((sa = rtinfo->rti_info[i]) == NULL)
  621                         continue;
  622                 rtinfo->rti_addrs |= (1 << i);
  623                 dlen = ROUNDUP(sa->sa_len);
  624                 m_copyback(m, len, dlen, (caddr_t)sa);
  625                 len += dlen;
  626         }
  627         if (m->m_pkthdr.len != len) {
  628                 m_freem(m);
  629                 return (NULL);
  630         }
  631         rtm->rtm_msglen = len;
  632         rtm->rtm_version = RTM_VERSION;
  633         rtm->rtm_type = type;
  634         return (m);
  635 }
  636 
  637 static int
  638 rt_msg2(type, rtinfo, cp, w)
  639         int type;
  640         register struct rt_addrinfo *rtinfo;
  641         caddr_t cp;
  642         struct walkarg *w;
  643 {
  644         register int i;
  645         int len, dlen, second_time = 0;
  646         caddr_t cp0;
  647 
  648         rtinfo->rti_addrs = 0;
  649 again:
  650         switch (type) {
  651 
  652         case RTM_DELADDR:
  653         case RTM_NEWADDR:
  654                 len = sizeof(struct ifa_msghdr);
  655                 break;
  656 
  657         case RTM_IFINFO:
  658                 len = sizeof(struct if_msghdr);
  659                 break;
  660 
  661         default:
  662                 len = sizeof(struct rt_msghdr);
  663         }
  664         cp0 = cp;
  665         if (cp0)
  666                 cp += len;
  667         for (i = 0; i < RTAX_MAX; i++) {
  668                 register struct sockaddr *sa;
  669 
  670                 if ((sa = rtinfo->rti_info[i]) == 0)
  671                         continue;
  672                 rtinfo->rti_addrs |= (1 << i);
  673                 dlen = ROUNDUP(sa->sa_len);
  674                 if (cp) {
  675                         bcopy((caddr_t)sa, cp, (unsigned)dlen);
  676                         cp += dlen;
  677                 }
  678                 len += dlen;
  679         }
  680         len = ALIGN(len);
  681         if (cp == 0 && w != NULL && !second_time) {
  682                 register struct walkarg *rw = w;
  683 
  684                 if (rw->w_req) {
  685                         if (rw->w_tmemsize < len) {
  686                                 if (rw->w_tmem)
  687                                         free(rw->w_tmem, M_RTABLE);
  688                                 rw->w_tmem = (caddr_t)
  689                                         malloc(len, M_RTABLE, M_NOWAIT);
  690                                 if (rw->w_tmem)
  691                                         rw->w_tmemsize = len;
  692                         }
  693                         if (rw->w_tmem) {
  694                                 cp = rw->w_tmem;
  695                                 second_time = 1;
  696                                 goto again;
  697                         }
  698                 }
  699         }
  700         if (cp) {
  701                 register struct rt_msghdr *rtm = (struct rt_msghdr *)cp0;
  702 
  703                 rtm->rtm_version = RTM_VERSION;
  704                 rtm->rtm_type = type;
  705                 rtm->rtm_msglen = len;
  706         }
  707         return (len);
  708 }
  709 
  710 /*
  711  * This routine is called to generate a message from the routing
  712  * socket indicating that a redirect has occured, a routing lookup
  713  * has failed, or that a protocol has detected timeouts to a particular
  714  * destination.
  715  */
  716 void
  717 rt_missmsg(type, rtinfo, flags, error)
  718         int type, flags, error;
  719         register struct rt_addrinfo *rtinfo;
  720 {
  721         register struct rt_msghdr *rtm;
  722         register struct mbuf *m;
  723         struct sockaddr *sa = rtinfo->rti_info[RTAX_DST];
  724 
  725         if (route_cb.any_count == 0)
  726                 return;
  727         m = rt_msg1(type, rtinfo);
  728         if (m == 0)
  729                 return;
  730         rtm = mtod(m, struct rt_msghdr *);
  731         rtm->rtm_flags = RTF_DONE | flags;
  732         rtm->rtm_errno = error;
  733         rtm->rtm_addrs = rtinfo->rti_addrs;
  734         route_proto.sp_protocol = sa ? sa->sa_family : 0;
  735         raw_input(m, &route_proto, &route_src, &route_dst);
  736 }
  737 
  738 /*
  739  * This routine is called to generate a message from the routing
  740  * socket indicating that the status of a network interface has changed.
  741  */
  742 void
  743 rt_ifmsg(ifp)
  744         register struct ifnet *ifp;
  745 {
  746         register struct if_msghdr *ifm;
  747         struct mbuf *m;
  748         struct rt_addrinfo info;
  749 
  750         if (route_cb.any_count == 0)
  751                 return;
  752         bzero((caddr_t)&info, sizeof(info));
  753         m = rt_msg1(RTM_IFINFO, &info);
  754         if (m == 0)
  755                 return;
  756         ifm = mtod(m, struct if_msghdr *);
  757         ifm->ifm_index = ifp->if_index;
  758         ifm->ifm_flags = ifp->if_flags;
  759         ifm->ifm_data = ifp->if_data;
  760         ifm->ifm_addrs = 0;
  761         route_proto.sp_protocol = 0;
  762         raw_input(m, &route_proto, &route_src, &route_dst);
  763 }
  764 
  765 /*
  766  * This is called to generate messages from the routing socket
  767  * indicating a network interface has had addresses associated with it.
  768  * if we ever reverse the logic and replace messages TO the routing
  769  * socket indicate a request to configure interfaces, then it will
  770  * be unnecessary as the routing socket will automatically generate
  771  * copies of it.
  772  */
  773 void
  774 rt_newaddrmsg(cmd, ifa, error, rt)
  775         int cmd, error;
  776         register struct ifaddr *ifa;
  777         register struct rtentry *rt;
  778 {
  779         struct rt_addrinfo info;
  780         struct sockaddr *sa = 0;
  781         int pass;
  782         struct mbuf *m = 0;
  783         struct ifnet *ifp = ifa->ifa_ifp;
  784 
  785         if (route_cb.any_count == 0)
  786                 return;
  787         for (pass = 1; pass < 3; pass++) {
  788                 bzero((caddr_t)&info, sizeof(info));
  789                 if ((cmd == RTM_ADD && pass == 1) ||
  790                     (cmd == RTM_DELETE && pass == 2)) {
  791                         register struct ifa_msghdr *ifam;
  792                         int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR;
  793 
  794                         ifaaddr = sa = ifa->ifa_addr;
  795                         ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
  796                         netmask = ifa->ifa_netmask;
  797                         brdaddr = ifa->ifa_dstaddr;
  798                         if ((m = rt_msg1(ncmd, &info)) == NULL)
  799                                 continue;
  800                         ifam = mtod(m, struct ifa_msghdr *);
  801                         ifam->ifam_index = ifp->if_index;
  802                         ifam->ifam_metric = ifa->ifa_metric;
  803                         ifam->ifam_flags = ifa->ifa_flags;
  804                         ifam->ifam_addrs = info.rti_addrs;
  805                 }
  806                 if ((cmd == RTM_ADD && pass == 2) ||
  807                     (cmd == RTM_DELETE && pass == 1)) {
  808                         register struct rt_msghdr *rtm;
  809 
  810                         if (rt == 0)
  811                                 continue;
  812                         netmask = rt_mask(rt);
  813                         dst = sa = rt_key(rt);
  814                         gate = rt->rt_gateway;
  815                         if ((m = rt_msg1(cmd, &info)) == NULL)
  816                                 continue;
  817                         rtm = mtod(m, struct rt_msghdr *);
  818                         rtm->rtm_index = ifp->if_index;
  819                         rtm->rtm_flags |= rt->rt_flags;
  820                         rtm->rtm_errno = error;
  821                         rtm->rtm_addrs = info.rti_addrs;
  822                 }
  823                 route_proto.sp_protocol = sa ? sa->sa_family : 0;
  824                 raw_input(m, &route_proto, &route_src, &route_dst);
  825         }
  826 }
  827 
  828 /*
  829  * This is the analogue to the rt_newaddrmsg which performs the same
  830  * function but for multicast group memberhips.  This is easier since
  831  * there is no route state to worry about.
  832  */
  833 void
  834 rt_newmaddrmsg(cmd, ifma)
  835         int cmd;
  836         struct ifmultiaddr *ifma;
  837 {
  838         struct rt_addrinfo info;
  839         struct mbuf *m = 0;
  840         struct ifnet *ifp = ifma->ifma_ifp;
  841         struct ifma_msghdr *ifmam;
  842 
  843         if (route_cb.any_count == 0)
  844                 return;
  845 
  846         bzero((caddr_t)&info, sizeof(info));
  847         ifaaddr = ifma->ifma_addr;
  848         if (ifp && TAILQ_FIRST(&ifp->if_addrhead))
  849                 ifpaddr = TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
  850         else
  851                 ifpaddr = NULL;
  852         /*
  853          * If a link-layer address is present, present it as a ``gateway''
  854          * (similarly to how ARP entries, e.g., are presented).
  855          */
  856         gate = ifma->ifma_lladdr;
  857         if ((m = rt_msg1(cmd, &info)) == NULL)
  858                 return;
  859         ifmam = mtod(m, struct ifma_msghdr *);
  860         ifmam->ifmam_index = ifp->if_index;
  861         ifmam->ifmam_addrs = info.rti_addrs;
  862         route_proto.sp_protocol = ifma->ifma_addr->sa_family;
  863         raw_input(m, &route_proto, &route_src, &route_dst);
  864 }
  865 
  866 /*
  867  * This is called to generate routing socket messages indicating
  868  * network interface arrival and departure.
  869  */
  870 void
  871 rt_ifannouncemsg(ifp, what)
  872         struct ifnet *ifp;
  873         int what;
  874 {
  875         struct if_announcemsghdr *ifan;
  876         struct mbuf *m;
  877         struct rt_addrinfo info;
  878 
  879         if (route_cb.any_count == 0)
  880                 return;
  881         bzero((caddr_t)&info, sizeof(info));
  882         m = rt_msg1(RTM_IFANNOUNCE, &info);
  883         if (m == NULL)
  884                 return;
  885         ifan = mtod(m, struct if_announcemsghdr *);
  886         ifan->ifan_index = ifp->if_index;
  887         snprintf(ifan->ifan_name, sizeof(ifan->ifan_name),
  888             "%s%d", ifp->if_name, ifp->if_unit);
  889         ifan->ifan_what = what;
  890         route_proto.sp_protocol = 0;
  891         raw_input(m, &route_proto, &route_src, &route_dst);
  892  }
  893 
  894 /*
  895  * This is used in dumping the kernel table via sysctl().
  896  */
  897 static int
  898 sysctl_dumpentry(rn, vw)
  899         struct radix_node *rn;
  900         void *vw;
  901 {
  902         register struct walkarg *w = vw;
  903         register struct rtentry *rt = (struct rtentry *)rn;
  904         int error = 0, size;
  905         struct rt_addrinfo info;
  906 
  907         if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg))
  908                 return 0;
  909         bzero((caddr_t)&info, sizeof(info));
  910         dst = rt_key(rt);
  911         gate = rt->rt_gateway;
  912         netmask = rt_mask(rt);
  913         genmask = rt->rt_genmask;
  914         if (rt->rt_ifp) {
  915                 ifpaddr = TAILQ_FIRST(&rt->rt_ifp->if_addrhead)->ifa_addr;
  916                 ifaaddr = rt->rt_ifa->ifa_addr;
  917                 if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
  918                         brdaddr = rt->rt_ifa->ifa_dstaddr;
  919         }
  920         size = rt_msg2(RTM_GET, &info, 0, w);
  921         if (w->w_req && w->w_tmem) {
  922                 register struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;
  923 
  924                 rtm->rtm_flags = rt->rt_flags;
  925                 rtm->rtm_use = rt->rt_use;
  926                 rtm->rtm_rmx = rt->rt_rmx;
  927                 rtm->rtm_index = rt->rt_ifp->if_index;
  928                 rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0;
  929                 rtm->rtm_addrs = info.rti_addrs;
  930                 error = SYSCTL_OUT(w->w_req, (caddr_t)rtm, size);
  931                 return (error);
  932         }
  933         return (error);
  934 }
  935 
  936 static int
  937 sysctl_iflist(af, w)
  938         int     af;
  939         register struct walkarg *w;
  940 {
  941         register struct ifnet *ifp;
  942         register struct ifaddr *ifa;
  943         struct  rt_addrinfo info;
  944         int     len, error = 0;
  945 
  946         bzero((caddr_t)&info, sizeof(info));
  947         TAILQ_FOREACH(ifp, &ifnet, if_link) {
  948                 if (w->w_arg && w->w_arg != ifp->if_index)
  949                         continue;
  950                 ifa = TAILQ_FIRST(&ifp->if_addrhead);
  951                 ifpaddr = ifa->ifa_addr;
  952                 len = rt_msg2(RTM_IFINFO, &info, (caddr_t)0, w);
  953                 ifpaddr = 0;
  954                 if (w->w_req && w->w_tmem) {
  955                         register struct if_msghdr *ifm;
  956 
  957                         ifm = (struct if_msghdr *)w->w_tmem;
  958                         ifm->ifm_index = ifp->if_index;
  959                         ifm->ifm_flags = ifp->if_flags;
  960                         ifm->ifm_data = ifp->if_data;
  961                         ifm->ifm_addrs = info.rti_addrs;
  962                         error = SYSCTL_OUT(w->w_req,(caddr_t)ifm, len);
  963                         if (error)
  964                                 goto done;
  965                 }
  966                 while ((ifa = TAILQ_NEXT(ifa, ifa_link)) != 0) {
  967                         if (af && af != ifa->ifa_addr->sa_family)
  968                                 continue;
  969                         if (jailed(curthread->td_ucred) &&
  970                             prison_if(curthread->td_ucred, ifa->ifa_addr))
  971                                 continue;
  972                         ifaaddr = ifa->ifa_addr;
  973                         netmask = ifa->ifa_netmask;
  974                         brdaddr = ifa->ifa_dstaddr;
  975                         len = rt_msg2(RTM_NEWADDR, &info, 0, w);
  976                         if (w->w_req && w->w_tmem) {
  977                                 register struct ifa_msghdr *ifam;
  978 
  979                                 ifam = (struct ifa_msghdr *)w->w_tmem;
  980                                 ifam->ifam_index = ifa->ifa_ifp->if_index;
  981                                 ifam->ifam_flags = ifa->ifa_flags;
  982                                 ifam->ifam_metric = ifa->ifa_metric;
  983                                 ifam->ifam_addrs = info.rti_addrs;
  984                                 error = SYSCTL_OUT(w->w_req, w->w_tmem, len);
  985                                 if (error)
  986                                         goto done;
  987                         }
  988                 }
  989                 ifaaddr = netmask = brdaddr = 0;
  990         }
  991 done:
  992         return (error);
  993 }
  994 
  995 static int
  996 sysctl_rtsock(SYSCTL_HANDLER_ARGS)
  997 {
  998         int     *name = (int *)arg1;
  999         u_int   namelen = arg2;
 1000         register struct radix_node_head *rnh;
 1001         int     i, s, error = EINVAL;
 1002         u_char  af;
 1003         struct  walkarg w;
 1004 
 1005         name ++;
 1006         namelen--;
 1007         if (req->newptr)
 1008                 return (EPERM);
 1009         if (namelen != 3)
 1010                 return ((namelen < 3) ? EISDIR : ENOTDIR);
 1011         af = name[0];
 1012         Bzero(&w, sizeof(w));
 1013         w.w_op = name[1];
 1014         w.w_arg = name[2];
 1015         w.w_req = req;
 1016 
 1017         s = splnet();
 1018         switch (w.w_op) {
 1019 
 1020         case NET_RT_DUMP:
 1021         case NET_RT_FLAGS:
 1022                 for (i = 1; i <= AF_MAX; i++)
 1023                         if ((rnh = rt_tables[i]) && (af == 0 || af == i) &&
 1024                             (error = rnh->rnh_walktree(rnh,
 1025                                                         sysctl_dumpentry, &w)))
 1026                                 break;
 1027                 break;
 1028 
 1029         case NET_RT_IFLIST:
 1030                 error = sysctl_iflist(af, &w);
 1031         }
 1032         splx(s);
 1033         if (w.w_tmem)
 1034                 free(w.w_tmem, M_RTABLE);
 1035         return (error);
 1036 }
 1037 
 1038 SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD, sysctl_rtsock, "");
 1039 
 1040 /*
 1041  * Definitions of protocols supported in the ROUTE domain.
 1042  */
 1043 
 1044 extern struct domain routedomain;               /* or at least forward */
 1045 
 1046 static struct protosw routesw[] = {
 1047 { SOCK_RAW,     &routedomain,   0,              PR_ATOMIC|PR_ADDR,
 1048   0,            route_output,   raw_ctlinput,   0,
 1049   0,
 1050   raw_init,     0,              0,              0,
 1051   &route_usrreqs
 1052 }
 1053 };
 1054 
 1055 static struct domain routedomain =
 1056     { PF_ROUTE, "route", 0, 0, 0,
 1057       routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };
 1058 
 1059 DOMAIN_SET(route);

Cache object: 505a399389996e7d8eca9c80378e249f


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