checkpoint semi-working version with routing socket (by sklower)
authorMike Karels <karels@ucbvax.Berkeley.EDU>
Wed, 14 Dec 1988 05:31:26 +0000 (21:31 -0800)
committerMike Karels <karels@ucbvax.Berkeley.EDU>
Wed, 14 Dec 1988 05:31:26 +0000 (21:31 -0800)
SCCS-vsn: sys/net/route.c 7.8

usr/src/sys/net/route.c

index 4d898a4..5896b05 100644 (file)
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- *     @(#)route.c     7.7 (Berkeley) %G%
+ *     @(#)route.c     7.8 (Berkeley) %G%
  */
  */
-
+#include "../machine/reg.h"
 #include "param.h"
 #include "systm.h"
 #include "param.h"
 #include "systm.h"
-#include "mbuf.h"
-#include "protosw.h"
-#include "socket.h"
 #include "dir.h"
 #include "user.h"
 #include "dir.h"
 #include "user.h"
-#include "ioctl.h"
+#include "inode.h"
+#include "proc.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "domain.h"
+#include "protosw.h"
 #include "errno.h"
 #include "errno.h"
+#include "ioctl.h"
 
 #include "if.h"
 #include "af.h"
 #include "route.h"
 
 #include "if.h"
 #include "af.h"
 #include "route.h"
-#include "radix.h"
-
-#include "radix.c"
-#ifdef INET
+#include "raw_cb.h"
 #include "../netinet/in.h"
 #include "../netinet/in_var.h"
 #include "../netinet/in.h"
 #include "../netinet/in_var.h"
-#endif
+
+#include "../machine/mtpr.h"
+#include "netisr.h"
+
+#include "rtsock.c"
 
 int    rttrash;                /* routes not in table but not freed */
 struct sockaddr wildcard;      /* zero valued cookie for wildcard searches */
 
 int    rttrash;                /* routes not in table but not freed */
 struct sockaddr wildcard;      /* zero valued cookie for wildcard searches */
@@ -44,6 +50,7 @@ int   rthashsize = RTHASHSIZ; /* for netstat, etc. */
 
 static int rtinits_done = 0;
 struct radix_node_head *ns_rnhead, *in_rnhead;
 
 static int rtinits_done = 0;
 struct radix_node_head *ns_rnhead, *in_rnhead;
+struct radix_node *rn_match(), *rn_delete(), *rn_addroute();
 rtinitheads()
 {
        if (rtinits_done == 0 &&
 rtinitheads()
 {
        if (rtinits_done == 0 &&
@@ -57,43 +64,52 @@ rtinitheads()
  */
 rtalloc(ro)
        register struct route *ro;
  */
 rtalloc(ro)
        register struct route *ro;
+{
+       if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
+               return;                          /* XXX */
+       ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
+}
+
+struct rtentry *
+rtalloc1(dst, report)
+       struct sockaddr *dst;
+       int  report;
 {
        register struct radix_node_head *rnh;
        register struct radix_node *rn;
        register struct rtentry *rt = 0;
 {
        register struct radix_node_head *rnh;
        register struct radix_node *rn;
        register struct rtentry *rt = 0;
-       u_char af = ro->ro_dst.sa_family;
-       int  s;
+       u_char af = dst->sa_family;
+       int  s = splnet();
 
 
-       if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
-               return;                          /* XXX */
-       s = splnet();
        for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); )
                rnh = rnh->rnh_next;
        if (rnh && rnh->rnh_treetop &&
        for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); )
                rnh = rnh->rnh_next;
        if (rnh && rnh->rnh_treetop &&
-           (rn = rn_match((char *)&(ro->ro_dst), rnh->rnh_treetop)) &&
+           (rn = rn_match((caddr_t)dst, rnh->rnh_treetop)) &&
            ((rn->rn_flags & RNF_ROOT) == 0)) {
            ((rn->rn_flags & RNF_ROOT) == 0)) {
-               rt = &(((struct nrtentry *)rn)->nrt_rt);
+               rt = (struct rtentry *)rn;
                rt->rt_refcnt++;
                rt->rt_refcnt++;
-       } else
+       } else {
                rtstat.rts_unreach++;
                rtstat.rts_unreach++;
-       ro->ro_rt = rt;
+               if (report && route_cb.any_count)
+                       rt_missmsg(RTM_MISS, dst, (struct sockaddr *)0,
+                              (struct sockaddr *)0, (struct sockaddr *)0, 0);
+       }
        splx(s);
        splx(s);
+       return (rt);
 }
 
 rtfree(rt)
        register struct rtentry *rt;
 {
 }
 
 rtfree(rt)
        register struct rtentry *rt;
 {
-       register struct nrtentry *nrt;
        u_char *af;
        if (rt == 0)
                panic("rtfree");
        rt->rt_refcnt--;
        if (rt->rt_refcnt <= 0 && (rt->rt_flags&RTF_UP) == 0) {
                rttrash--;
        u_char *af;
        if (rt == 0)
                panic("rtfree");
        rt->rt_refcnt--;
        if (rt->rt_refcnt <= 0 && (rt->rt_flags&RTF_UP) == 0) {
                rttrash--;
-               nrt = (struct nrtentry *) (((struct radix_node *)rt) - 2);
-               if (nrt->nrt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
+               if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
                        panic ("rtfree 2");
                        panic ("rtfree 2");
-               free((caddr_t)nrt, M_RTABLE);
+               free((caddr_t)rt, M_RTABLE);
        }
 }
 
        }
 }
 
@@ -106,11 +122,10 @@ rtfree(rt)
  * N.B.: must be called at splnet
  *
  */
  * N.B.: must be called at splnet
  *
  */
-rtredirect(dst, gateway, flags, src)
+rtredirect(dst, gateway, netmask, flags, src)
        struct sockaddr *dst, *gateway, *src;
        int flags;
 {
        struct sockaddr *dst, *gateway, *src;
        int flags;
 {
-       struct route ro;
        register struct rtentry *rt;
 
        /* verify the gateway is directly reachable */
        register struct rtentry *rt;
 
        /* verify the gateway is directly reachable */
@@ -118,10 +133,7 @@ rtredirect(dst, gateway, flags, src)
                rtstat.rts_badredirect++;
                return;
        }
                rtstat.rts_badredirect++;
                return;
        }
-       ro.ro_dst = *dst;
-       ro.ro_rt = 0;
-       rtalloc(&ro);
-       rt = ro.ro_rt;
+       rt = rtalloc1(dst, 1);
 #define        equal(a1, a2) \
   (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
        /*
 #define        equal(a1, a2) \
   (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
        /*
@@ -155,10 +167,13 @@ rtredirect(dst, gateway, flags, src)
                rtfree(rt);
                rt = 0;
        }
                rtfree(rt);
                rt = 0;
        }
+       if (route_cb.any_count)
+               rt_missmsg(RTM_REDIRECT, dst, gateway, netmask, src,
+                               (flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC);
         */
        if (rt == 0) {
         */
        if (rt == 0) {
-               rtinit(dst, gateway, (int)SIOCADDRT,
-                   (flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC);
+               rtrequest((int)RTM_ADD, dst, gateway, 0,
+                   (flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC, 0);
                rtstat.rts_dynamic++;
                return;
        }
                rtstat.rts_dynamic++;
                return;
        }
@@ -172,17 +187,20 @@ rtredirect(dst, gateway, flags, src)
                         * Changing from route to net => route to host.
                         * Create new route, rather than smashing route to net.
                         */
                         * Changing from route to net => route to host.
                         * Create new route, rather than smashing route to net.
                         */
-                       rtinit(dst, gateway, (int)SIOCADDRT,
-                           flags | RTF_DYNAMIC);
+                       rtrequest((int)RTM_ADD, dst, gateway, 0,
+                           (flags & RTF_HOST) | RTF_GATEWAY | RTF_DYNAMIC, 0);
                        rtstat.rts_dynamic++;
                } else {
                        /*
                         * Smash the current notion of the gateway to
                         * this destination.
                         */
                        rtstat.rts_dynamic++;
                } else {
                        /*
                         * Smash the current notion of the gateway to
                         * this destination.
                         */
-                       rt->rt_gateway = *gateway; /*XXX -- size? */
-                       rt->rt_flags |= RTF_MODIFIED;
-                       rtstat.rts_newgateway++;
+                       if (gateway->sa_len <= rt->rt_gateway->sa_len) {
+                               Bcopy(gateway, rt->rt_gateway, gateway->sa_len);
+                               rt->rt_flags |= RTF_MODIFIED;
+                               rtstat.rts_newgateway++;
+                       } else
+                               rtstat.rts_badredirect++;
                }
        } else
                rtstat.rts_badredirect++;
                }
        } else
                rtstat.rts_badredirect++;
@@ -192,95 +210,27 @@ rtredirect(dst, gateway, flags, src)
 /*
  * Routing table ioctl interface.
  */
 /*
  * Routing table ioctl interface.
  */
-rtioctl(cmd, data)
-       int cmd;
+rtioctl(req, data)
+       int req;
        caddr_t data;
 {
        caddr_t data;
 {
+#ifndef COMPAT_43
+       return (EOPNOTSUPP);
+#else
+       register struct ortentry *entry = (struct ortentry *)data;
+       int error;
+       struct sockaddr *netmask = 0;
 
 
-       if (cmd != SIOCADDRT && cmd != SIOCDELRT)
+       if (req == SIOCADDRT)
+               req = RTM_ADD;
+       else if (req == SIOCDELRT)
+               req = RTM_DELETE;
+       else
                return (EINVAL);
                return (EINVAL);
+
        if (!suser())
                return (u.u_error);
        if (!suser())
                return (u.u_error);
-       return (rtrequest(cmd, (struct rtentry *)data));
-}
-/*
- * This routine will go away soon.
- * Tries to guess which netmask is appropriate for a given net.
- */
-static struct sockaddr_in rtgmask = { 8, 0 };
-
-char *
-rtgetmask(sa, ifa)
-register struct sockaddr *sa;
-register struct ifaddr *ifa;
-{
-       u_long i, net, mask, subnet;
-
-       switch (sa->sa_family) {
-#ifdef INET
-       register struct in_ifaddr *ia;
-
-       case AF_INET:
-
-               i = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
-               if (i == 0) {
-                       rtgmask.sin_addr.s_addr = 0;
-                       return ((char *)&rtgmask);
-               } else if (IN_CLASSA(i)) {
-                       net = i & IN_CLASSA_NET;
-                       mask = IN_CLASSA_NET;
-               } else if (IN_CLASSB(i)) {
-                       net = i & IN_CLASSB_NET;
-                       mask = IN_CLASSB_NET;
-               } else if (IN_CLASSC(i)) {
-                       net = i & IN_CLASSC_NET;
-                       mask = IN_CLASSC_NET;
-               } else {
-                       net = i;
-                       mask = 0xffffffff;
-               }
-
-               /*
-                * Check whether network is a subnet;
-                * if so, return subnet number.
-                */
-               for (ia = in_ifaddr; ia; ia = ia->ia_next)
-                       if (net == ia->ia_net) {
-                               ifa = &ia->ia_ifa;
-                               break;
-                       }
-               if (ia == 0) {
-                       rtgmask.sin_addr.s_addr = ntohl(mask);
-                       return ((char *)&rtgmask);
-               }
-#endif
-       }
-       return ((char *)ifa->ifa_netmask);
-}
-
-/*
- * Carry out a request to change the routing table.  Called by
- * interfaces at boot time to make their ``local routes'' known,
- * for ioctl's, and as the result of routing redirects.
- */
-rtrequest(req, entry)
-       int req;
-       register struct rtentry *entry;
-{
-       register struct rtentry *rt;
-       int s, error = 0, found;
-       u_char af;
-       struct ifaddr *ifa;
-       struct ifaddr *ifa_ifwithdstaddr();
-       register struct nrtentry *nrt;
-       register struct radix_node *rn;
-       register struct radix_node_head *rnh;
-       struct radix_node *head;
-       char *netmask;
-
-#ifdef COMPAT_43
 #if BYTE_ORDER != BIG_ENDIAN
 #if BYTE_ORDER != BIG_ENDIAN
-       s = splnet();
        if (entry->rt_dst.sa_family == 0 && entry->rt_dst.sa_len < 16) {
                entry->rt_dst.sa_family = entry->rt_dst.sa_len;
                entry->rt_dst.sa_len = 16;
        if (entry->rt_dst.sa_family == 0 && entry->rt_dst.sa_len < 16) {
                entry->rt_dst.sa_family = entry->rt_dst.sa_len;
                entry->rt_dst.sa_len = 16;
@@ -295,110 +245,173 @@ rtrequest(req, entry)
        if (entry->rt_gateway.sa_len == 0)
                entry->rt_gateway.sa_len = 16;
 #endif
        if (entry->rt_gateway.sa_len == 0)
                entry->rt_gateway.sa_len = 16;
 #endif
+       if ((entry->rt_flags & RTF_HOST) == 0)
+               switch (entry->rt_dst.sa_family) {
+#ifdef INET
+               case AF_INET:
+                       {
+                               extern struct sockaddr_in icmpmask;
+                               u_long in_maskof();
+                               struct sockaddr_in *dst_in = 
+                                       (struct sockaddr_in *)&entry->rt_dst;
+                               u_long i = ntohl(dst_in->sin_addr.s_addr);
+
+                               icmpmask.sin_addr.s_addr = ntohl(in_maskof(i));
+                               netmask = (struct sockaddr *)&icmpmask;
+                       }
+                       break;
+#endif
+#ifdef NS
+               case AF_NS:
+                       {
+                               extern struct sockaddr_ns ns_netmask;
+                               netmask = (struct sockaddr *)&ns_netmask;
+                       }
+#endif
+               }
+       error =  rtrequest(req, &(entry->rt_dst), &(entry->rt_gateway), netmask,
+                                       entry->rt_flags, 0);
+       rt_missmsg((req == RTM_ADD ? RTM_OLDADD : RTM_OLDDEL),
+                  &(entry->rt_dst), &(entry->rt_gateway),
+                  netmask, (struct sockaddr *)error, entry->rt_flags);
+       return (error);
 #endif
 #endif
+}
+
+rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
+       int req, flags;
+       struct sockaddr *dst, *gateway, *netmask;
+       struct rtentry **ret_nrt;
+{
+       int s = splnet(), len, error = 0;
+       register struct rtentry *rt;
+       register struct radix_node *rn;
+       register struct radix_node_head *rnh;
+       struct ifaddr *ifa, *ifa_ifwithdstaddr();
+       u_char af = dst->sa_family;
+
        if (rtinits_done == 0)
                rtinitheads();
        if (rtinits_done == 0)
                rtinitheads();
-       af = entry->rt_dst.sa_family;
        for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); )
                rnh = rnh->rnh_next;
        if (rnh == 0) {
                error = ESRCH;
                goto bad;
        }
        for (rnh = radix_node_head; rnh && (af != rnh->rnh_af); )
                rnh = rnh->rnh_next;
        if (rnh == 0) {
                error = ESRCH;
                goto bad;
        }
-       head = rnh->rnh_treetop;
-       if ((entry->rt_flags & RTF_GATEWAY) == 0) {
-               /*
-                * If we are adding a route to an interface,
-                * and the interface is a pt to pt link
-                * we should search for the destination
-                * as our clue to the interface.  Otherwise
-                * we can use the local address.
-                */
-               ifa = 0;
-               if (entry->rt_flags & RTF_HOST) 
-                       ifa = ifa_ifwithdstaddr(&entry->rt_dst);
-               if (ifa == 0)
-                       ifa = ifa_ifwithaddr(&entry->rt_gateway);
-       } else {
-               /*
-                * If we are adding a route to a remote net
-                * or host, the gateway may still be on the
-                * other end of a pt to pt link.
-                */
-               ifa = ifa_ifwithdstaddr(&entry->rt_gateway);
-       }
-       if (ifa == 0) {
-               ifa = ifa_ifwithnet(&entry->rt_gateway);
-               if (ifa == 0 && req == SIOCADDRT) {
-                       error = ENETUNREACH;
-                       goto bad;
-               }
-       }
-       if (entry->rt_flags & RTF_HOST)
-               netmask = 0;
-       else
-               netmask = rtgetmask(&entry->rt_dst, ifa);
        switch (req) {
        switch (req) {
-
-       case SIOCDELRT:
-               if ((rn = rn_delete((char *)&entry->rt_dst,
-                                       netmask, head)) == 0) {
+       case RTM_DELETE:
+               if ((rn = rn_delete((caddr_t)dst, (caddr_t)netmask, 
+                                       rnh->rnh_treetop)) == 0) {
                        error = ESRCH;
                        goto bad;
                }
                if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
                        panic ("rtrequest delete");
                        error = ESRCH;
                        goto bad;
                }
                if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
                        panic ("rtrequest delete");
-               nrt = (struct nrtentry *)rn;
-               nrt->nrt_rt.rt_flags &= ~RTF_UP;
-               if (nrt->nrt_rt.rt_refcnt > 0)
+               rt = (struct rtentry *)rn;
+               rt->rt_flags &= ~RTF_UP;
+               if (rt->rt_refcnt > 0)
                        rttrash++;
                else 
                        rttrash++;
                else 
-                       free((caddr_t)nrt, M_RTABLE);
+                       free((caddr_t)rt, M_RTABLE);
                break;
 
                break;
 
-       case SIOCADDRT:
-               Malloc(nrt, struct nrtentry *, sizeof *nrt);
-               if (nrt == 0) {
+       case RTM_ADD:
+               if ((flags & RTF_GATEWAY) == 0) {
+                       /*
+                        * If we are adding a route to an interface,
+                        * and the interface is a pt to pt link
+                        * we should search for the destination
+                        * as our clue to the interface.  Otherwise
+                        * we can use the local address.
+                        */
+                       ifa = 0;
+                       if (flags & RTF_HOST) 
+                               ifa = ifa_ifwithdstaddr(dst);
+                       if (ifa == 0)
+                               ifa = ifa_ifwithaddr(gateway);
+               } else {
+                       /*
+                        * If we are adding a route to a remote net
+                        * or host, the gateway may still be on the
+                        * other end of a pt to pt link.
+                        */
+                       ifa = ifa_ifwithdstaddr(gateway);
+               }
+               if (ifa == 0) {
+                       ifa = ifa_ifwithnet(gateway);
+                       if (ifa == 0 && req == RTM_ADD) {
+                               error = ENETUNREACH;
+                               goto bad;
+                       }
+               }
+               len = sizeof (*rt) + ROUNDUP(gateway->sa_len)
+                                               + ROUNDUP(dst->sa_len);
+               R_Malloc(rt, struct rtentry *, len);
+               if (rt == 0) {
                        error = ENOBUFS;
                        goto bad;
                }
                        error = ENOBUFS;
                        goto bad;
                }
-               Bzero(nrt, sizeof *nrt);
-               rn = rn_addroute((char *)&entry->rt_dst, netmask,
-                                                   head, nrt->nrt_nodes);
+               Bzero(rt, len);
+               rn = rn_addroute((caddr_t)dst, (caddr_t)netmask,
+                                       rnh->rnh_treetop, rt->rt_nodes);
                if (rn == 0) {
                if (rn == 0) {
-                       free((caddr_t)nrt, M_RTABLE);
+                       free((caddr_t)rt, M_RTABLE);
                        error = EEXIST;
                        goto bad;
                }
                        error = EEXIST;
                        goto bad;
                }
-               rt = &nrt->nrt_rt;
-               rn->rn_key = (char *)&(nrt->nrt_rt.rt_dst);
-               rt->rt_dst = entry->rt_dst;
-               rt->rt_gateway = entry->rt_gateway;
-               rt->rt_flags = RTF_UP |
-                   (entry->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_DYNAMIC));
+               if (ret_nrt)
+                       *ret_nrt = rt; /* == (struct rtentry *)rn */
+               rt->rt_ifp = ifa->ifa_ifp;
                rt->rt_use = 0;
                rt->rt_refcnt = 0;
                rt->rt_use = 0;
                rt->rt_refcnt = 0;
-               rt->rt_ifp = ifa->ifa_ifp;
+               rt->rt_flags = RTF_UP |
+                   (flags & (RTF_HOST|RTF_GATEWAY|RTF_DYNAMIC));
+               rn->rn_key = (caddr_t) (rt + 1); /* == rt_dst */
+               Bcopy(dst, rn->rn_key, dst->sa_len);
+               rt->rt_gateway = (struct sockaddr *)
+                                       (rn->rn_key + ROUNDUP(dst->sa_len));
+               Bcopy(gateway, rt->rt_gateway, gateway->sa_len);
                break;
        }
 bad:
        splx(s);
        return (error);
 }
                break;
        }
 bad:
        splx(s);
        return (error);
 }
-
 /*
  * Set up a routing table entry, normally
  * for an interface.
  */
 /*
  * Set up a routing table entry, normally
  * for an interface.
  */
-rtinit(dst, gateway, cmd, flags)
-       struct sockaddr *dst, *gateway;
+rtinit(ifa, cmd, flags)
+       register struct ifaddr *ifa;
        int cmd, flags;
 {
        int cmd, flags;
 {
-       struct rtentry route;
+       struct sockaddr net, *netp;
+       register caddr_t cp, cp2, cp3;
+       caddr_t cplim, freeit = 0;
+       int len;
 
 
-       bzero((caddr_t)&route, sizeof (route));
-       route.rt_dst = *dst;
-       route.rt_gateway = *gateway;
-       route.rt_flags = flags;
-       (void) rtrequest(cmd, &route);
+       if (flags & RTF_HOST || ifa->ifa_netmask == 0) {
+               (void) rtrequest(cmd, ifa->ifa_dstaddr, ifa->ifa_addr,
+                                                               0, flags, 0);
+       } else {
+               if ((len = ifa->ifa_addr->sa_len) >= sizeof (net)) {
+                       R_Malloc(freeit, caddr_t, len);
+                       if (freeit == 0)
+                               return;
+                       netp = (struct sockaddr *)freeit;
+               }
+               netp->sa_len = len;
+               cp2 = 1 + (caddr_t)ifa->ifa_addr;
+               netp->sa_family = *cp2++;
+               cp3 = (caddr_t) ifa->ifa_netmask->sa_data;
+               cp = (caddr_t) netp->sa_data;
+               cplim = cp + len - 2;
+               while (cp < cplim)
+                       *cp++ = *cp2++ & *cp3++;
+               (void) rtrequest(cmd, netp, ifa->ifa_addr, ifa->ifa_netmask,
+                                       flags, 0);
+               if (freeit)
+                       Free(freeit);
+       }
 }
 }
+#include "radix.c"