home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / os / bsdss4.tz / bsdss4 / bsdss / server / net / route.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-22  |  14.5 KB  |  545 lines

  1. /* 
  2.  * Mach Operating System
  3.  * Copyright (c) 1992 Carnegie Mellon University
  4.  * All Rights Reserved.
  5.  * 
  6.  * Permission to use, copy, modify and distribute this software and its
  7.  * documentation is hereby granted, provided that both the copyright
  8.  * notice and this permission notice appear in all copies of the
  9.  * software, derivative works or modified versions, and any portions
  10.  * thereof, and that both notices appear in supporting documentation.
  11.  * 
  12.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  13.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  14.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  15.  * 
  16.  * Carnegie Mellon requests users of this software to return to
  17.  * 
  18.  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
  19.  *  School of Computer Science
  20.  *  Carnegie Mellon University
  21.  *  Pittsburgh PA 15213-3890
  22.  * 
  23.  * any improvements or extensions that they make and grant Carnegie Mellon 
  24.  * the rights to redistribute these changes.
  25.  */
  26. /*
  27.  * HISTORY
  28.  * $Log:    route.c,v $
  29.  * Revision 2.1  92/04/21  17:13:54  rwd
  30.  * BSDSS
  31.  * 
  32.  *
  33.  */
  34.  
  35. /*
  36.  * Copyright (c) 1980, 1986, 1991 Regents of the University of California.
  37.  * All rights reserved.
  38.  *
  39.  * Redistribution and use in source and binary forms, with or without
  40.  * modification, are permitted provided that the following conditions
  41.  * are met:
  42.  * 1. Redistributions of source code must retain the above copyright
  43.  *    notice, this list of conditions and the following disclaimer.
  44.  * 2. Redistributions in binary form must reproduce the above copyright
  45.  *    notice, this list of conditions and the following disclaimer in the
  46.  *    documentation and/or other materials provided with the distribution.
  47.  * 3. All advertising materials mentioning features or use of this software
  48.  *    must display the following acknowledgement:
  49.  *    This product includes software developed by the University of
  50.  *    California, Berkeley and its contributors.
  51.  * 4. Neither the name of the University nor the names of its contributors
  52.  *    may be used to endorse or promote products derived from this software
  53.  *    without specific prior written permission.
  54.  *
  55.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  56.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  57.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  58.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  59.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  60.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  61.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  62.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  63.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  64.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  65.  * SUCH DAMAGE.
  66.  *
  67.  *    @(#)route.c    7.22 (Berkeley) 6/27/91
  68.  */
  69. #include <ns.h>
  70. #include <inet.h>
  71.  
  72. #include <sys/param.h>
  73. #include <sys/systm.h>
  74. #include <sys/proc.h>
  75. #include <sys/mbuf.h>
  76. #include <sys/socket.h>
  77. #include <sys/socketvar.h>
  78. #include <sys/domain.h>
  79. #include <sys/protosw.h>
  80. #include <sys/ioctl.h>
  81. #include <sys/synch.h>
  82.  
  83. #include <net/if.h>
  84. #include <net/af.h>
  85. #include <net/route.h>
  86. #include <net/raw_cb.h>
  87.  
  88. #include <netinet/in.h>
  89. #include <netinet/in_var.h>
  90.  
  91. #if NS
  92. #include <netns/ns.h>
  93. #endif
  94. #include <net/netisr.h>
  95.  
  96. #define    SA(p) ((struct sockaddr *)(p))
  97.  
  98. int    rttrash;        /* routes not in table but not freed */
  99. struct    sockaddr wildcard;    /* zero valued cookie for wildcard searches */
  100. int    rthashsize = RTHASHSIZ;    /* for netstat, etc. */
  101.  
  102. static int rtinits_done = 0;
  103. struct radix_node_head *ns_rnhead, *in_rnhead;
  104. struct radix_node *rn_match(), *rn_delete(), *rn_addroute();
  105.  
  106. rtinitheads()
  107. {
  108.     if (rtinits_done == 0 &&
  109. #if NS
  110.         rn_inithead(&ns_rnhead, 16, AF_NS) &&
  111. #endif
  112.         rn_inithead(&in_rnhead, 32, AF_INET))
  113.         rtinits_done = 1;
  114. }
  115.  
  116. /*
  117.  * Packet routing routines.
  118.  */
  119. rtalloc(ro)
  120.     register struct route *ro;
  121. {
  122.     if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
  123.         return;                 /* XXX */
  124.     ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
  125. }
  126.  
  127. struct rtentry *
  128. rtalloc1(dst, report)
  129.     register struct sockaddr *dst;
  130.     int  report;
  131. {
  132.     register struct radix_node_head *rnh;
  133.     register struct rtentry *rt;
  134.     register struct radix_node *rn;
  135.     struct rtentry *newrt = 0;
  136.     int  s = splnet(), err = 0, msgtype = RTM_MISS;
  137.  
  138.     for (rnh = radix_node_head; rnh && (dst->sa_family != rnh->rnh_af); )
  139.         rnh = rnh->rnh_next;
  140.     if (rnh && rnh->rnh_treetop &&
  141.         (rn = rn_match((caddr_t)dst, rnh->rnh_treetop)) &&
  142.         ((rn->rn_flags & RNF_ROOT) == 0)) {
  143.         newrt = rt = (struct rtentry *)rn;
  144.         if (report && (rt->rt_flags & RTF_CLONING)) {
  145.             if ((err = rtrequest(RTM_RESOLVE, dst, SA(0),
  146.                           SA(0), 0, &newrt)) ||
  147.                 ((rt->rt_flags & RTF_XRESOLVE)
  148.                   && (msgtype = RTM_RESOLVE))) /* intended! */
  149.                 goto miss;
  150.         } else
  151.             rt->rt_refcnt++;
  152.     } else {
  153.         rtstat.rts_unreach++;
  154.     miss:    if (report)
  155.             rt_missmsg(msgtype, dst, SA(0), SA(0), SA(0), 0, err);
  156.     }
  157.     splx(s);
  158.     return (newrt);
  159. }
  160.  
  161. rtfree(rt)
  162.     register struct rtentry *rt;
  163. {
  164.     register struct ifaddr *ifa;
  165.     if (rt == 0)
  166.         panic("rtfree");
  167.     rt->rt_refcnt--;
  168.     if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
  169.         rttrash--;
  170.         if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
  171.             panic ("rtfree 2");
  172.         bsd_free((caddr_t)rt, M_RTABLE);
  173.     }
  174. }
  175.  
  176. /*
  177.  * Force a routing table entry to the specified
  178.  * destination to go through the given gateway.
  179.  * Normally called as a result of a routing redirect
  180.  * message from the network layer.
  181.  *
  182.  * N.B.: must be called at splnet
  183.  *
  184.  */
  185. rtredirect(dst, gateway, netmask, flags, src, rtp)
  186.     struct sockaddr *dst, *gateway, *netmask, *src;
  187.     int flags;
  188.     struct rtentry **rtp;
  189. {
  190.     register struct rtentry *rt;
  191.     int error = 0;
  192.     short *stat = 0;
  193.  
  194.     /* verify the gateway is directly reachable */
  195.     if (ifa_ifwithnet(gateway) == 0) {
  196.         error = ENETUNREACH;
  197.         goto done;
  198.     }
  199.     rt = rtalloc1(dst, 0);
  200.     /*
  201.      * If the redirect isn't from our current router for this dst,
  202.      * it's either old or wrong.  If it redirects us to ourselves,
  203.      * we have a routing loop, perhaps as a result of an interface
  204.      * going down recently.
  205.      */
  206. #define    equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
  207.     if (!(flags & RTF_DONE) && rt && !equal(src, rt->rt_gateway))
  208.         error = EINVAL;
  209.     else if (ifa_ifwithaddr(gateway))
  210.         error = EHOSTUNREACH;
  211.     if (error)
  212.         goto done;
  213.     /*
  214.      * Create a new entry if we just got back a wildcard entry
  215.      * or the the lookup failed.  This is necessary for hosts
  216.      * which use routing redirects generated by smart gateways
  217.      * to dynamically build the routing tables.
  218.      */
  219.     if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
  220.         goto create;
  221.     /*
  222.      * Don't listen to the redirect if it's
  223.      * for a route to an interface. 
  224.      */
  225.     if (rt->rt_flags & RTF_GATEWAY) {
  226.         if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
  227.             /*
  228.              * Changing from route to net => route to host.
  229.              * Create new route, rather than smashing route to net.
  230.              */
  231.         create:
  232.             flags |=  RTF_GATEWAY | RTF_DYNAMIC;
  233.             error = rtrequest((int)RTM_ADD, dst, gateway,
  234.                     SA(0), flags,
  235.                     (struct rtentry **)0);
  236.             stat = &rtstat.rts_dynamic;
  237.         } else {
  238.             /*
  239.              * Smash the current notion of the gateway to
  240.              * this destination.  Should check about netmask!!!
  241.              */
  242.             if (gateway->sa_len <= rt->rt_gateway->sa_len) {
  243.                 Bcopy(gateway, rt->rt_gateway, gateway->sa_len);
  244.                 rt->rt_flags |= RTF_MODIFIED;
  245.                 flags |= RTF_MODIFIED;
  246.                 stat = &rtstat.rts_newgateway;
  247.             } else
  248.                 error = ENOSPC;
  249.         }
  250.     } else
  251.         error = EHOSTUNREACH;
  252. done:
  253.     if (rt) {
  254.         if (rtp && !error)
  255.             *rtp = rt;
  256.         else
  257.             rtfree(rt);
  258.     }
  259.     if (error)
  260.         rtstat.rts_badredirect++;
  261.     else
  262.         (stat && (*stat)++);
  263.     rt_missmsg(RTM_REDIRECT, dst, gateway, netmask, src, flags, error);
  264. }
  265.  
  266. /*
  267. * Routing table ioctl interface.
  268. */
  269. rtioctl(req, data, p)
  270.     int req;
  271.     caddr_t data;
  272.     struct proc *p;
  273. {
  274. #ifndef COMPAT_43
  275.     return (EOPNOTSUPP);
  276. #else
  277.     register struct ortentry *entry = (struct ortentry *)data;
  278.     int error;
  279.     struct sockaddr *netmask = 0;
  280.  
  281.     if (req == SIOCADDRT)
  282.         req = RTM_ADD;
  283.     else if (req == SIOCDELRT)
  284.         req = RTM_DELETE;
  285.     else
  286.         return (EINVAL);
  287.  
  288.     if (error = suser(p->p_ucred, &p->p_acflag))
  289.         return (error);
  290. #if BYTE_ORDER != BIG_ENDIAN
  291.     if (entry->rt_dst.sa_family == 0 && entry->rt_dst.sa_len < 16) {
  292.         entry->rt_dst.sa_family = entry->rt_dst.sa_len;
  293.         entry->rt_dst.sa_len = 16;
  294.     }
  295.     if (entry->rt_gateway.sa_family == 0 && entry->rt_gateway.sa_len < 16) {
  296.         entry->rt_gateway.sa_family = entry->rt_gateway.sa_len;
  297.         entry->rt_gateway.sa_len = 16;
  298.     }
  299. #else
  300.     if (entry->rt_dst.sa_len == 0)
  301.         entry->rt_dst.sa_len = 16;
  302.     if (entry->rt_gateway.sa_len == 0)
  303.         entry->rt_gateway.sa_len = 16;
  304. #endif
  305.     if ((entry->rt_flags & RTF_HOST) == 0)
  306.         switch (entry->rt_dst.sa_family) {
  307. #if INET
  308.         case AF_INET:
  309.             {
  310.                 extern struct sockaddr_in icmpmask;
  311.                 struct sockaddr_in *dst_in = 
  312.                     (struct sockaddr_in *)&entry->rt_dst;
  313.  
  314.                 in_sockmaskof(dst_in->sin_addr, &icmpmask);
  315.                 netmask = (struct sockaddr *)&icmpmask;
  316.             }
  317.             break;
  318. #endif
  319. #if NS
  320.         case AF_NS:
  321.             {
  322.                 extern struct sockaddr_ns ns_netmask;
  323.                 netmask = (struct sockaddr *)&ns_netmask;
  324.             }
  325. #endif
  326.         }
  327.     error =  rtrequest(req, &(entry->rt_dst), &(entry->rt_gateway), netmask,
  328.                 entry->rt_flags, (struct rtentry **)0);
  329.     rt_missmsg((req == RTM_ADD ? RTM_OLDADD : RTM_OLDDEL),
  330.            &(entry->rt_dst), &(entry->rt_gateway),
  331.            netmask, SA(0), entry->rt_flags, error);
  332.     return (error);
  333. #endif
  334. }
  335.  
  336. struct ifaddr *
  337. ifa_ifwithroute(flags, dst, gateway)
  338. int    flags;
  339. struct sockaddr    *dst, *gateway;
  340. {
  341.     register struct ifaddr *ifa;
  342.     if ((flags & RTF_GATEWAY) == 0) {
  343.         /*
  344.          * If we are adding a route to an interface,
  345.          * and the interface is a pt to pt link
  346.          * we should search for the destination
  347.          * as our clue to the interface.  Otherwise
  348.          * we can use the local address.
  349.          */
  350.         ifa = 0;
  351.         if (flags & RTF_HOST) 
  352.             ifa = ifa_ifwithdstaddr(dst);
  353.         if (ifa == 0)
  354.             ifa = ifa_ifwithaddr(gateway);
  355.     } else {
  356.         /*
  357.          * If we are adding a route to a remote net
  358.          * or host, the gateway may still be on the
  359.          * other end of a pt to pt link.
  360.          */
  361.         ifa = ifa_ifwithdstaddr(gateway);
  362.     }
  363.     if (ifa == 0)
  364.         ifa = ifa_ifwithnet(gateway);
  365.     if (ifa == 0) {
  366.         struct rtentry *rt = rtalloc1(dst, 0);
  367.         if (rt == 0)
  368.             return (0);
  369.         rt->rt_refcnt--;
  370.         if ((ifa = rt->rt_ifa) == 0)
  371.             return (0);
  372.     }
  373.     if (ifa->ifa_addr->sa_family != dst->sa_family) {
  374.         struct ifaddr *oifa = ifa, *ifaof_ifpforaddr();
  375.         ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
  376.         if (ifa == 0)
  377.             ifa = oifa;
  378.     }
  379.     return (ifa);
  380. }
  381.  
  382. #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
  383.  
  384. rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
  385.     int req, flags;
  386.     struct sockaddr *dst, *gateway, *netmask;
  387.     struct rtentry **ret_nrt;
  388. {
  389.     int s = splnet(), len, error = 0;
  390.     register struct rtentry *rt;
  391.     register struct radix_node *rn;
  392.     register struct radix_node_head *rnh;
  393.     struct ifaddr *ifa, *ifa_ifwithdstaddr();
  394.     struct sockaddr *ndst;
  395.     u_char af = dst->sa_family;
  396. #define senderr(x) { error = x ; goto bad; }
  397.  
  398.     if (rtinits_done == 0)
  399.         rtinitheads();
  400.     for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); )
  401.         rnh = rnh->rnh_next;
  402.     if (rnh == 0)
  403.         senderr(ESRCH);
  404.     if (flags & RTF_HOST)
  405.         netmask = 0;
  406.     switch (req) {
  407.     case RTM_DELETE:
  408.         if (ret_nrt && (rt = *ret_nrt)) {
  409.             RTFREE(rt);
  410.             *ret_nrt = 0;
  411.         }
  412.         if ((rn = rn_delete((caddr_t)dst, (caddr_t)netmask, 
  413.                     rnh->rnh_treetop)) == 0)
  414.             senderr(ESRCH);
  415.         if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
  416.             panic ("rtrequest delete");
  417.         rt = (struct rtentry *)rn;
  418.         rt->rt_flags &= ~RTF_UP;
  419.         if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
  420.             ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
  421.         rttrash++;
  422.         if (rt->rt_refcnt <= 0)
  423.             rtfree(rt);
  424.         break;
  425.  
  426.     case RTM_RESOLVE:
  427.         if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
  428.             senderr(EINVAL);
  429.         ifa = rt->rt_ifa;
  430.         flags = rt->rt_flags & ~RTF_CLONING;
  431.         gateway = rt->rt_gateway;
  432.         if ((netmask = rt->rt_genmask) == 0)
  433.             flags |= RTF_HOST;
  434.         goto makeroute;
  435.  
  436.     case RTM_ADD:
  437.         if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
  438.             senderr(ENETUNREACH);
  439.     makeroute:
  440.         len = sizeof (*rt) + ROUNDUP(gateway->sa_len)
  441.             + ROUNDUP(dst->sa_len);
  442.         R_Malloc(rt, struct rtentry *, len);
  443.         if (rt == 0)
  444.             senderr(ENOBUFS);
  445.         Bzero(rt, len);
  446.         ndst = (struct sockaddr *)(rt + 1);
  447.         if (netmask) {
  448.             rt_maskedcopy(dst, ndst, netmask);
  449.         } else
  450.             Bcopy(dst, ndst, dst->sa_len);
  451.         rn = rn_addroute((caddr_t)ndst, (caddr_t)netmask,
  452.                     rnh->rnh_treetop, rt->rt_nodes);
  453.         if (rn == 0) {
  454.             free((caddr_t)rt, M_RTABLE);
  455.             senderr(EEXIST);
  456.         }
  457.         rt->rt_ifa = ifa;
  458.         rt->rt_ifp = ifa->ifa_ifp;
  459.         rt->rt_flags = RTF_UP | flags;
  460.         rt->rt_gateway = (struct sockaddr *)
  461.                     (rn->rn_key + ROUNDUP(dst->sa_len));
  462.         Bcopy(gateway, rt->rt_gateway, gateway->sa_len);
  463.         if (req == RTM_RESOLVE)
  464.             rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
  465.         if (ifa->ifa_rtrequest)
  466.             ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0));
  467.         if (ret_nrt) {
  468.             *ret_nrt = rt;
  469.             rt->rt_refcnt++;
  470.         }
  471.         break;
  472.     }
  473. bad:
  474.     splx(s);
  475.     return (error);
  476. }
  477.  
  478. rt_maskedcopy(src, dst, netmask)
  479. struct sockaddr *src, *dst, *netmask;
  480. {
  481.     register u_char *cp1 = (u_char *)src;
  482.     register u_char *cp2 = (u_char *)dst;
  483.     register u_char *cp3 = (u_char *)netmask;
  484.     u_char *cplim = cp2 + *cp3;
  485.     u_char *cplim2 = cp2 + *cp1;
  486.  
  487.     *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
  488.     cp3 += 2;
  489.     if (cplim > cplim2)
  490.         cplim = cplim2;
  491.     while (cp2 < cplim)
  492.         *cp2++ = *cp1++ & *cp3++;
  493.     if (cp2 < cplim2)
  494.         bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
  495. }
  496. /*
  497.  * Set up a routing table entry, normally
  498.  * for an interface.
  499.  */
  500. rtinit(ifa, cmd, flags)
  501.     register struct ifaddr *ifa;
  502.     int cmd, flags;
  503. {
  504.     register struct rtentry *rt;
  505.     register struct sockaddr *dst;
  506.     register struct sockaddr *deldst;
  507.     struct mbuf *m = 0;
  508.     int error;
  509.  
  510.     dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
  511.     if (ifa->ifa_flags & IFA_ROUTE) {
  512.         if ((rt = ifa->ifa_rt) && (rt->rt_flags & RTF_UP) == 0) {
  513.             RTFREE(rt);
  514.             ifa->ifa_rt = 0;
  515.         }
  516.     }
  517.     if (cmd == RTM_DELETE) {
  518.         if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
  519.             m = m_get(M_WAIT, MT_SONAME);
  520.             deldst = mtod(m, struct sockaddr *);
  521.             rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
  522.             dst = deldst;
  523.         }
  524.         if (rt = rtalloc1(dst, 0)) {
  525.             rt->rt_refcnt--;
  526.             if (rt->rt_ifa != ifa) {
  527.                 if (m)
  528.                     (void) m_free(m);
  529.                 return (flags & RTF_HOST ? EHOSTUNREACH
  530.                             : ENETUNREACH);
  531.             }
  532.         }
  533.     }
  534.     error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
  535.             flags | ifa->ifa_flags, &ifa->ifa_rt);
  536.     if (m)
  537.         (void) m_free(m);
  538.     if (cmd == RTM_ADD && error == 0 && (rt = ifa->ifa_rt)
  539.                         && rt->rt_ifa != ifa) {
  540.         rt->rt_ifa = ifa;
  541.         rt->rt_ifp = ifa->ifa_ifp;
  542.     }
  543.     return (error);
  544. }
  545.