changes designed so that ESIS and ARP may use routing table
authorKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Thu, 21 Jun 1990 10:05:27 +0000 (02:05 -0800)
committerKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Thu, 21 Jun 1990 10:05:27 +0000 (02:05 -0800)
instead of private cache; allow RTM_CHANGE to specify new ifp.

SCCS-vsn: sys/net/route.c 7.16
SCCS-vsn: sys/net/if.c 7.12
SCCS-vsn: sys/net/if_ethersubr.c 7.9
SCCS-vsn: sys/net/radix.c 7.6
SCCS-vsn: sys/net/rtsock.c 7.10

usr/src/sys/net/if.c
usr/src/sys/net/if_ethersubr.c
usr/src/sys/net/radix.c
usr/src/sys/net/route.c
usr/src/sys/net/rtsock.c

index 60c1ae4..bca4875 100644 (file)
@@ -14,7 +14,7 @@
  * 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.
  *
- *     @(#)if.c        7.11 (Berkeley) %G%
+ *     @(#)if.c        7.12 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -31,6 +31,7 @@
 #include "if.h"
 #include "af.h"
 #include "if_dl.h"
 #include "if.h"
 #include "af.h"
 #include "if_dl.h"
+#include "if_types.h"
 
 #include "ether.h"
 
 
 #include "ether.h"
 
@@ -69,6 +70,7 @@ ifubareset(uban)
 #endif
 
 int if_index = 0;
 #endif
 
 int if_index = 0;
+struct ifaddr **ifnet_addrs;
 /*
  * Attach an interface to the
  * list of "active" interfaces.
 /*
  * Attach an interface to the
  * list of "active" interfaces.
@@ -76,18 +78,35 @@ int if_index = 0;
 if_attach(ifp)
        struct ifnet *ifp;
 {
 if_attach(ifp)
        struct ifnet *ifp;
 {
-       register struct ifnet **p = &ifnet;
        unsigned socksize, ifasize;
        int namelen, unitlen;
        char workbuf[16];
        unsigned socksize, ifasize;
        int namelen, unitlen;
        char workbuf[16];
+       register struct ifnet **p = &ifnet;
        register struct sockaddr_dl *sdl;
        register struct ifaddr *ifa;
        register struct sockaddr_dl *sdl;
        register struct ifaddr *ifa;
-       extern link_rtrequest();
+       static int if_indexlim = 8;
+       extern link_rtrequest(), ether_output();
 
        while (*p)
                p = &((*p)->if_next);
        *p = ifp;
        ifp->if_index = ++if_index;
 
        while (*p)
                p = &((*p)->if_next);
        *p = ifp;
        ifp->if_index = ++if_index;
+       if (ifnet_addrs == 0 || if_index >= if_indexlim) {
+               unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
+               struct ifaddr **q = (struct ifaddr **)
+                                       malloc(n, M_IFADDR, M_WAITOK);
+               if (ifnet_addrs) {
+                       bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
+                       free((caddr_t)ifnet_addrs, M_IFADDR);
+               }
+               ifnet_addrs = q;
+       }
+       /* XXX -- Temporary fix before changing 10 ethernet drivers */
+       if (ifp->if_output == ether_output) {
+               ifp->if_type = IFT_ETHER;
+               ifp->if_addrlen = 6;
+               ifp->if_hdrlen = 14;
+       }
        /*
         * create a Link Level name for this device
         */
        /*
         * create a Link Level name for this device
         */
@@ -99,10 +118,13 @@ if_attach(ifp)
                               unitlen + namelen + ifp->if_addrlen;
 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
        socksize = ROUNDUP(socksize);
                               unitlen + namelen + ifp->if_addrlen;
 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
        socksize = ROUNDUP(socksize);
+       if (socksize < sizeof(*sdl))
+               socksize = sizeof(*sdl);
        ifasize = sizeof(*ifa) + 2 * socksize;
        ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
        if (ifa == 0)
                return;
        ifasize = sizeof(*ifa) + 2 * socksize;
        ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK);
        if (ifa == 0)
                return;
+       ifnet_addrs[if_index - 1] = ifa;
        bzero((caddr_t)ifa, ifasize);
        sdl = (struct sockaddr_dl *)(ifa + 1);
        ifa->ifa_addr = (struct sockaddr *)sdl;
        bzero((caddr_t)ifa, ifasize);
        sdl = (struct sockaddr_dl *)(ifa + 1);
        ifa->ifa_addr = (struct sockaddr *)sdl;
@@ -141,8 +163,8 @@ ifa_ifwithaddr(addr)
                        continue;
                if (equal(addr, ifa->ifa_addr))
                        return (ifa);
                        continue;
                if (equal(addr, ifa->ifa_addr))
                        return (ifa);
-               if ((ifp->if_flags & IFF_BROADCAST) &&
-                   equal(&ifa->ifa_broadaddr, addr))
+               if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
+                   equal(ifa->ifa_broadaddr, addr))
                        return (ifa);
        }
        return ((struct ifaddr *)0);
                        return (ifa);
        }
        return ((struct ifaddr *)0);
@@ -179,14 +201,19 @@ ifa_ifwithnet(addr)
 {
        register struct ifnet *ifp;
        register struct ifaddr *ifa;
 {
        register struct ifnet *ifp;
        register struct ifaddr *ifa;
-       register char *cp, *cp2, *cp3;
-       register char *cplim;
        u_int af = addr->sa_family;
 
        if (af >= AF_MAX)
                return (0);
        u_int af = addr->sa_family;
 
        if (af >= AF_MAX)
                return (0);
+       if (af == AF_LINK) {
+           register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
+           if (sdl->sdl_index && sdl->sdl_index <= if_index)
+               return (ifnet_addrs[sdl->sdl_index - 1]);
+       }
        for (ifp = ifnet; ifp; ifp = ifp->if_next)
            for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
        for (ifp = ifnet; ifp; ifp = ifp->if_next)
            for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
+               register char *cp, *cp2, *cp3;
+               register char *cplim;
                if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
                        continue;
                cp = addr->sa_data;
                if (ifa->ifa_addr->sa_family != af || ifa->ifa_netmask == 0)
                        continue;
                cp = addr->sa_data;
@@ -219,6 +246,45 @@ ifa_ifwithaf(af)
        return ((struct ifaddr *)0);
 }
 
        return ((struct ifaddr *)0);
 }
 
+/*
+ * Find an interface address specific to an interface best matching
+ * a given address.
+ */
+struct ifaddr *
+ifaof_ifpforaddr(addr, ifp)
+       struct sockaddr *addr;
+       register struct ifnet *ifp;
+{
+       register struct ifaddr *ifa;
+       register char *cp, *cp2, *cp3;
+       register char *cplim;
+       struct ifaddr *ifa_maybe = 0;
+       u_int af = addr->sa_family;
+
+       if (af >= AF_MAX)
+               return (0);
+       for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
+               if (ifa->ifa_addr->sa_family != af)
+                       continue;
+               ifa_maybe = ifa;
+               if (ifa->ifa_netmask == 0) {
+                       if (equal(addr, ifa->ifa_addr) ||
+                           (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
+                               return (ifa);
+                       continue;
+               }
+               cp = addr->sa_data;
+               cp2 = ifa->ifa_addr->sa_data;
+               cp3 = ifa->ifa_netmask->sa_data;
+               cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
+               for (; cp3 < cplim; cp3++)
+                       if ((*cp++ ^ *cp2++) & *cp3)
+                               break;
+               if (cp3 == cplim)
+                       return (ifa);
+       }
+       return (ifa_maybe);
+}
 #include "route.h"
 /*
  * Default action when installing a route with a Link Level gateway.
 #include "route.h"
 /*
  * Default action when installing a route with a Link Level gateway.
@@ -236,15 +302,11 @@ struct sockaddr *sa;
        if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
            ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
                return;
        if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
            ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
                return;
-       ifnet = ifp;
-       if (((ifa = ifa_ifwithnet(dst)) && ifa->ifa_ifp == ifp) ||
-           ((ifa = ifa_ifwithaf(dst->sa_family)) && ifa->ifa_ifp == ifp)) {
-               ifnet = oldifnet;
+       if (ifa = ifaof_ifpforaddr(dst, ifp)) {
                rt->rt_ifa = ifa;
                if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
                        ifa->ifa_rtrequest(cmd, rt, sa);
                rt->rt_ifa = ifa;
                if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
                        ifa->ifa_rtrequest(cmd, rt, sa);
-       } else
-               ifnet = oldifnet;
+       }
 }
 
 /*
 }
 
 /*
index 449a2dd..c0b6b98 100644 (file)
@@ -14,7 +14,7 @@
  * 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.
  *
- *     @(#)if_ethersubr.c      7.8 (Berkeley) %G%
+ *     @(#)if_ethersubr.c      7.9 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -126,12 +126,11 @@ ether_output(ifp, m0, dst, rt)
                struct  llc *l;
 
        iso_again:
                struct  llc *l;
 
        iso_again:
+               iso_etherout();
                if (rt && rt->rt_gateway && (rt->rt_flags & RTF_UP)) {
                        if (rt->rt_flags & RTF_GATEWAY) {
                if (rt && rt->rt_gateway && (rt->rt_flags & RTF_UP)) {
                        if (rt->rt_flags & RTF_GATEWAY) {
-                               register struct llinfo_llc *lc =
-                                       (struct llinfo_llc *)rt->rt_llinfo;
-                               if (lc && lc->lc_rtgate) {
-                                       rt = lc->lc_rtgate;
+                               if (rt->rt_llinfo) {
+                                       rt = (struct rtentry *)rt->rt_llinfo;
                                        goto iso_again;
                                }
                        } else {
                                        goto iso_again;
                                }
                        } else {
@@ -390,3 +389,4 @@ ether_sprintf(ap)
        *--cp = 0;
        return (etherbuf);
 }
        *--cp = 0;
        return (etherbuf);
 }
+iso_etherout() {}
index 12c09fc..e3fc629 100644 (file)
@@ -14,7 +14,7 @@
  * 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.
  *
- *     @(#)radix.c     7.5 (Berkeley) %G%
+ *     @(#)radix.c     7.6 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -273,9 +273,53 @@ on1:
        return (tt);
 }
 
        return (tt);
 }
 
+struct radix_node *
+rn_addmask(netmask, search, skip)
+caddr_t netmask;
+{
+       register struct radix_node *x;
+       register caddr_t cp, cplim;
+       register int b, mlen, j;
+       int maskduplicated;
+
+       mlen = *(u_char *)netmask;
+       if (search) {
+               x = rn_search(netmask, rn_maskhead);
+               mlen = *(u_char *)netmask;
+               if (Bcmp(netmask, x->rn_key, mlen) == 0)
+                       return (x);
+       }
+       R_Malloc(x, struct radix_node *, MAXKEYLEN + 2 * sizeof (*x));
+       if (x == 0)
+               return (0);
+       Bzero(x, MAXKEYLEN + 2 * sizeof (*x));
+       cp = (caddr_t)(x + 2);
+       Bcopy(netmask, cp, mlen);
+       netmask = cp;
+       x = rn_insert(netmask, rn_maskhead, &maskduplicated, x);
+       /*
+        * Calculate index of mask.
+        */
+       cplim = netmask + mlen;
+       for (cp = netmask + skip; cp < cplim; cp++)
+               if (*(u_char *)cp != 0xff)
+                       break;
+       b = (cp - netmask) << 3;
+       if (cp != cplim) {
+               if (*cp != 0) {
+                       gotOddMasks = 1;
+                       for (j = 0x80; j; b++, j >>= 1)  
+                               if ((j & *cp) == 0)
+                                       break;
+               }
+       }
+       x->rn_b = -1 - b;
+       return (x);
+}
+
 struct radix_node *
 rn_addroute(v, netmask, head, treenodes)
 struct radix_node *
 rn_addroute(v, netmask, head, treenodes)
-       struct radix_node *head;
+struct radix_node *head;
        caddr_t netmask, v;
        struct radix_node treenodes[2];
 {
        caddr_t netmask, v;
        struct radix_node treenodes[2];
 {
@@ -283,7 +327,7 @@ rn_addroute(v, netmask, head, treenodes)
        register caddr_t cp;
        register struct radix_node *t, *x, *tt;
        short b = 0, b_leaf;
        register caddr_t cp;
        register struct radix_node *t, *x, *tt;
        short b = 0, b_leaf;
-       int vlen = *(u_char *)v, maskduplicated = 0, mlen, keyduplicated;
+       int vlen = *(u_char *)v, mlen, keyduplicated;
        caddr_t cplim; unsigned char *maskp;
        struct radix_mask *m, **mp;
        struct radix_node *saved_tt;
        caddr_t cplim; unsigned char *maskp;
        struct radix_mask *m, **mp;
        struct radix_node *saved_tt;
@@ -298,38 +342,13 @@ rn_addroute(v, netmask, head, treenodes)
        if (netmask)  {
                x = rn_search(netmask, rn_maskhead);
                mlen = *(u_char *)netmask;
        if (netmask)  {
                x = rn_search(netmask, rn_maskhead);
                mlen = *(u_char *)netmask;
-               if (Bcmp(netmask, x->rn_key, mlen) == 0) {
-                       maskduplicated = 1;
-                       netmask = x->rn_key;
-                       b = -1 - x->rn_b;
-               } else {
-                       maskduplicated = 0;
-                       R_Malloc(x, struct radix_node *, MAXKEYLEN + 2 * sizeof (*x));
+               if (Bcmp(netmask, x->rn_key, mlen) != 0) {
+                       x = rn_addmask(netmask, 0, head->rn_off);
                        if (x == 0)
                                return (0);
                        if (x == 0)
                                return (0);
-                       Bzero(x, MAXKEYLEN + 2 * sizeof (*x));
-                       cp = (caddr_t)(x + 2);
-                       Bcopy(netmask, cp, mlen);
-                       netmask = cp;
-                       x = rn_insert(netmask, rn_maskhead, &maskduplicated, x);
-                       /*
-                        * Calculate index of mask.
-                        */
-                       cplim = netmask + vlen;
-                       for (cp = netmask + head->rn_off; cp < cplim; cp++)
-                               if (*(u_char *)cp != 0xff)
-                                       break;
-                       b = (cp - netmask) << 3;
-                       if (cp != cplim) {
-                               if (*cp != 0) {
-                                       gotOddMasks = 1;
-                                       for (j = 0x80; j; b++, j >>= 1)  
-                                               if ((j & *cp) == 0)
-                                                       break;
-                               }
-                       }
-                       x->rn_b = -1 - b;
                }
                }
+               netmask = x->rn_key;
+               b = -1 - x->rn_b;
        }
        /*
         * Deal with duplicated keys: attach node to previous instance
        }
        /*
         * Deal with duplicated keys: attach node to previous instance
index 730dbbc..f9f3232 100644 (file)
@@ -14,7 +14,7 @@
  * 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.15 (Berkeley) %G%
+ *     @(#)route.c     7.16 (Berkeley) %G%
  */
 #include "machine/reg.h"
  
  */
 #include "machine/reg.h"
  
@@ -273,6 +273,39 @@ rtioctl(req, data)
        return (error);
 #endif
 }
        return (error);
 #endif
 }
+
+struct ifaddr *
+ifa_ifwithroute(flags, dst, gateway)
+int    flags;
+struct sockaddr        *dst, *gateway;
+{
+       struct ifaddr *ifa;
+       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);
+       return (ifa);
+}
+
 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
 
 rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
 #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1)))
 
 rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
@@ -318,7 +351,7 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
                break;
 
        case RTM_RESOLVE:
                break;
 
        case RTM_RESOLVE:
-               if (ret_nrt== 0 || (rt = *ret_nrt) == 0)
+               if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
                        senderr(EINVAL);
                ifa = rt->rt_ifa;
                flags = rt->rt_flags & ~RTF_CLONING;
                        senderr(EINVAL);
                ifa = rt->rt_ifa;
                flags = rt->rt_flags & ~RTF_CLONING;
@@ -328,34 +361,11 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
                goto makeroute;
 
        case RTM_ADD:
                goto makeroute;
 
        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)
-                               senderr(ENETUNREACH);
-               }
-    makeroute: len = sizeof (*rt) + ROUNDUP(gateway->sa_len)
-                   + ROUNDUP(dst->sa_len) + ROUNDUP(ifa->ifa_llinfolen);
+               if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
+                       senderr(ENETUNREACH);
+       makeroute:
+               len = sizeof (*rt) + ROUNDUP(gateway->sa_len)
+                   + ROUNDUP(dst->sa_len);
                R_Malloc(rt, struct rtentry *, len);
                if (rt == 0)
                        senderr(ENOBUFS);
                R_Malloc(rt, struct rtentry *, len);
                if (rt == 0)
                        senderr(ENOBUFS);
@@ -378,8 +388,6 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
                rt->rt_gateway = (struct sockaddr *)
                                        (rn->rn_key + ROUNDUP(dst->sa_len));
                Bcopy(gateway, rt->rt_gateway, gateway->sa_len);
                rt->rt_gateway = (struct sockaddr *)
                                        (rn->rn_key + ROUNDUP(dst->sa_len));
                Bcopy(gateway, rt->rt_gateway, gateway->sa_len);
-               rt->rt_llinfo = ROUNDUP(gateway->sa_len)
-                                       + (caddr_t)rt->rt_gateway;
                if (req == RTM_RESOLVE)
                        rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
                if (ifa->ifa_rtrequest)
                if (req == RTM_RESOLVE)
                        rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
                if (ifa->ifa_rtrequest)
index fd90eb8..6ba4ddf 100644 (file)
@@ -14,7 +14,7 @@
  * 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.
  *
- *     @(#)rtsock.c    7.9 (Berkeley) %G%
+ *     @(#)rtsock.c    7.10 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -90,12 +90,16 @@ route_output(m, so)
        register struct mbuf *m;
        struct socket *so;
 {
        register struct mbuf *m;
        struct socket *so;
 {
-       register struct rt_msghdr *rtm = 0;
+       register struct rt_msghdr *rtm;
        register struct rtentry *rt = 0;
        struct rtentry *saved_nrt = 0;
        struct sockaddr *dst = 0, *gate = 0, *netmask = 0, *genmask = 0;
        register struct rtentry *rt = 0;
        struct rtentry *saved_nrt = 0;
        struct sockaddr *dst = 0, *gate = 0, *netmask = 0, *genmask = 0;
+       struct sockaddr *ifpaddr = 0;
        caddr_t cp, lim;
        int len, error = 0;
        caddr_t cp, lim;
        int len, error = 0;
+       struct ifnet *ifp = 0;
+       struct  ifaddr *ifa;
+       extern struct ifaddr *ifaof_ifpforaddr(), *ifa_ifwithroute();
 
 #define senderr(e) { error = e; goto flush;}
        if (m == 0 || m->m_len < sizeof(long))
 
 #define senderr(e) { error = e; goto flush;}
        if (m == 0 || m->m_len < sizeof(long))
@@ -135,7 +139,20 @@ route_output(m, so)
 
        }
        if ((rtm->rtm_addrs & RTA_GENMASK) && cp < lim)  {
 
        }
        if ((rtm->rtm_addrs & RTA_GENMASK) && cp < lim)  {
+               struct radix_node *t, *rn_addmask();
                genmask = (struct sockaddr *)cp;
                genmask = (struct sockaddr *)cp;
+               if (*cp)
+                       cp += ROUNDUP(netmask->sa_len);
+               else
+                       cp += sizeof(long);
+               t = rn_addmask(genmask, 1, 2);
+               if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0)
+                       genmask = (struct sockaddr *)(t->rn_key);
+               else
+                       senderr(ENOBUFS);
+       }
+       if ((rtm->rtm_addrs & RTA_IFP) && cp < lim)  {
+               ifpaddr = (struct sockaddr *)cp;
        }
        switch (rtm->rtm_type) {
        case RTM_ADD:
        }
        switch (rtm->rtm_type) {
        case RTM_ADD:
@@ -147,6 +164,7 @@ route_output(m, so)
                        rt_setmetrics(rtm->rtm_inits,
                                &rtm->rtm_rmx, &saved_nrt->rt_rmx);
                        saved_nrt->rt_refcnt--;
                        rt_setmetrics(rtm->rtm_inits,
                                &rtm->rtm_rmx, &saved_nrt->rt_rmx);
                        saved_nrt->rt_refcnt--;
+                       saved_nrt->rt_genmask = genmask;
                }
                break;
 
                }
                break;
 
@@ -198,17 +216,40 @@ route_output(m, so)
                        break;
 
                case RTM_CHANGE:
                        break;
 
                case RTM_CHANGE:
-                       if (gate == 0)
+                       if (gate == 0 || netmask != 0)
                                senderr(EINVAL);
                        if (gate->sa_len > (len = rt->rt_gateway->sa_len))
                                senderr(EDQUOT);
                        if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
                                senderr(EINVAL);
                        if (gate->sa_len > (len = rt->rt_gateway->sa_len))
                                senderr(EDQUOT);
                        if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
-                               rt->rt_ifa->ifa_rtrequest(RTM_CHANGE, rt, gate);
+                               rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, gate);
+                       /* new gateway could require new ifaddr, ifp;
+                          flags may also be different; ifp may be specified
+                          by ll sockaddr when protocol address is ambiguous */
+                       if (ifpaddr &&
+                           (ifa = ifa_ifwithnet(ifpaddr)) &&
+                           (ifp = ifa->ifa_ifp) &&
+                           (ifa = ifaof_ifpforaddr(gate, ifp))) {
+                                    /* We got it */
+                       } else {
+                           ifa = 0; ifp = 0;
+                       }
                        Bcopy(gate, rt->rt_gateway, len);
                        rt->rt_gateway->sa_len = len;
                        Bcopy(gate, rt->rt_gateway, len);
                        rt->rt_gateway->sa_len = len;
-               
                        rt_setmetrics(rtm->rtm_inits,
                                &rtm->rtm_rmx, &rt->rt_rmx);
                        rt_setmetrics(rtm->rtm_inits,
                                &rtm->rtm_rmx, &rt->rt_rmx);
+                       if (ifa == 0)
+                           ifa = ifa_ifwithroute(rt->rt_flags, rt_key(rt),
+                                               gate);
+                       if (ifa) {
+                               if (rt->rt_ifa != ifa) {
+                                   rt->rt_ifa = ifa;
+                                   rt->rt_ifp = ifa->ifa_ifp;
+                               }
+                       }
+                       if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
+                              rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate);
+                       if (genmask)
+                               rt->rt_genmask = genmask;
                        /*
                         * Fall into
                         */
                        /*
                         * Fall into
                         */
@@ -263,7 +304,7 @@ cleanup:
        return (error);
 }
 
        return (error);
 }
 
-static rt_setmetrics(which, in, out)
+rt_setmetrics(which, in, out)
        u_long which;
        register struct rt_metrics *in, *out;
 {
        u_long which;
        register struct rt_metrics *in, *out;
 {