changes for var. length sockaddrs, routing lookup changes,
[unix-history] / usr / src / sys / netns / ns.c
index 1028316..e5ce2c9 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.
  *
- *     @(#)ns.c        7.3 (Berkeley) %G%
+ *     @(#)ns.c        7.4 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
 #ifdef NS
 
 struct ns_ifaddr *ns_ifaddr;
 #ifdef NS
 
 struct ns_ifaddr *ns_ifaddr;
-
-ns_hash(sns, hp)
-       register struct sockaddr_ns *sns;
-       struct afhash *hp;
-{
-       register long hash = 0;
-       register u_short *s =  sns->sns_addr.x_host.s_host;
-       union {
-               union ns_net    net_e;
-               long            long_e;
-       } net;
-
-       net.net_e = sns->sns_addr.x_net;
-       hp->afh_nethash = net.long_e;
-       hash = *s++; hash <<= 8; hash += *s++; hash <<= 8; hash += *s;
-       hp->afh_hosthash =  hash;
-}
-
-
-ns_netmatch(sns1, sns2)
-       struct sockaddr_ns *sns1, *sns2;
-{
-
-       return (ns_neteq(sns1->sns_addr, sns2->sns_addr));
-}
+int ns_interfaces;
+extern struct sockaddr_ns ns_netmask, ns_hostmask;
 
 /*
  * Generic internet control operations (ioctl's).
 
 /*
  * Generic internet control operations (ioctl's).
@@ -75,9 +52,12 @@ ns_control(so, cmd, data, ifp)
        register struct ifnet *ifp;
 {
        register struct ifreq *ifr = (struct ifreq *)data;
        register struct ifnet *ifp;
 {
        register struct ifreq *ifr = (struct ifreq *)data;
+       register struct ns_aliasreq *ifra = (struct ns_aliasreq *)data;
        register struct ns_ifaddr *ia;
        struct ifaddr *ifa;
        register struct ns_ifaddr *ia;
        struct ifaddr *ifa;
+       struct ns_ifaddr *oia;
        struct mbuf *m;
        struct mbuf *m;
+       int dstIsNew, hostIsNew;
 
        /*
         * Find address for this interface, if it exists.
 
        /*
         * Find address for this interface, if it exists.
@@ -93,7 +73,7 @@ ns_control(so, cmd, data, ifp)
        case SIOCGIFADDR:
                if (ia == (struct ns_ifaddr *)0)
                        return (EADDRNOTAVAIL);
        case SIOCGIFADDR:
                if (ia == (struct ns_ifaddr *)0)
                        return (EADDRNOTAVAIL);
-               ifr->ifr_addr = ia->ia_addr;
+               *(struct sockaddr_ns *)&ifr->ifr_addr = ia->ia_addr;
                return (0);
 
 
                return (0);
 
 
@@ -102,7 +82,7 @@ ns_control(so, cmd, data, ifp)
                        return (EADDRNOTAVAIL);
                if ((ifp->if_flags & IFF_BROADCAST) == 0)
                        return (EINVAL);
                        return (EADDRNOTAVAIL);
                if ((ifp->if_flags & IFF_BROADCAST) == 0)
                        return (EINVAL);
-               ifr->ifr_dstaddr = ia->ia_broadaddr;
+               *(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
                return (0);
 
        case SIOCGIFDSTADDR:
                return (0);
 
        case SIOCGIFDSTADDR:
@@ -110,7 +90,7 @@ ns_control(so, cmd, data, ifp)
                        return (EADDRNOTAVAIL);
                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
                        return (EINVAL);
                        return (EADDRNOTAVAIL);
                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
                        return (EINVAL);
-               ifr->ifr_dstaddr = ia->ia_dstaddr;
+               *(struct sockaddr_ns *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
                return (0);
        }
 
                return (0);
        }
 
@@ -118,6 +98,18 @@ ns_control(so, cmd, data, ifp)
                return (u.u_error);
 
        switch (cmd) {
                return (u.u_error);
 
        switch (cmd) {
+       case SIOCAIFADDR:
+       case SIOCDIFADDR:
+               if (ifra->ifra_addr.sns_family == AF_NS)
+                   for (oia = ia; ia; ia = ia->ia_next) {
+                       if (ia->ia_ifp == ifp  &&
+                           ns_neteq(ia->ia_addr.sns_addr,
+                                 ifra->ifra_addr.sns_addr))
+                           break;
+                   }
+               if (cmd == SIOCDIFADDR && ia == 0)
+                       return (EADDRNOTAVAIL);
+               /* FALLTHROUGH */
 
        case SIOCSIFADDR:
        case SIOCSIFDSTADDR:
 
        case SIOCSIFADDR:
        case SIOCSIFDSTADDR:
@@ -139,31 +131,99 @@ ns_control(so, cmd, data, ifp)
                        } else
                                ifp->if_addrlist = (struct ifaddr *) ia;
                        ia->ia_ifp = ifp;
                        } else
                                ifp->if_addrlist = (struct ifaddr *) ia;
                        ia->ia_ifp = ifp;
-                       IA_SNS(ia)->sns_family = AF_NS;
+                       ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
+
+                       ia->ia_ifa.ifa_netmask =
+                               (struct sockaddr *)&ns_netmask;
+
+                       ia->ia_ifa.ifa_dstaddr =
+                               (struct sockaddr *)&ia->ia_dstaddr;
+                       if (ifp->if_flags & IFF_BROADCAST) {
+                               ia->ia_broadaddr.sns_family = AF_NS;
+                               ia->ia_broadaddr.sns_len = sizeof(ia->ia_addr);
+                               ia->ia_broadaddr.sns_addr.x_host = ns_broadhost;
+                       }
+                       ns_interfaces++;
                }
        }
 
        switch (cmd) {
                }
        }
 
        switch (cmd) {
+               int error;
 
        case SIOCSIFDSTADDR:
                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
                        return (EINVAL);
                if (ia->ia_flags & IFA_ROUTE) {
 
        case SIOCSIFDSTADDR:
                if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
                        return (EINVAL);
                if (ia->ia_flags & IFA_ROUTE) {
-                       rtinit(&ia->ia_dstaddr, &ia->ia_addr,
-                               (int)SIOCDELRT, RTF_HOST);
+                       rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
                        ia->ia_flags &= ~IFA_ROUTE;
                }
                if (ifp->if_ioctl) {
                        ia->ia_flags &= ~IFA_ROUTE;
                }
                if (ifp->if_ioctl) {
-                       int error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia);
+                       error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia);
                        if (error)
                                return (error);
                }
                        if (error)
                                return (error);
                }
-               ia->ia_dstaddr = ifr->ifr_dstaddr;
+               *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
                return (0);
 
        case SIOCSIFADDR:
                return (0);
 
        case SIOCSIFADDR:
-               return
-                   (ns_ifinit(ifp, ia, (struct sockaddr_ns *)&ifr->ifr_addr));
+               return (ns_ifinit(ifp, ia,
+                               (struct sockaddr_ns *)&ifr->ifr_addr, 1));
+
+       case SIOCDIFADDR:
+               ns_ifscrub(ifp, ia);
+               if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
+                       ifp->if_addrlist = ifa->ifa_next;
+               else {
+                       while (ifa->ifa_next &&
+                              (ifa->ifa_next != (struct ifaddr *)ia))
+                                   ifa = ifa->ifa_next;
+                       if (ifa->ifa_next)
+                           ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
+                       else
+                               printf("Couldn't unlink nsifaddr from ifp\n");
+               }
+               oia = ia;
+               if (oia == (ia = ns_ifaddr)) {
+                       ns_ifaddr = ia->ia_next;
+               } else {
+                       while (ia->ia_next && (ia->ia_next != oia)) {
+                               ia = ia->ia_next;
+                       }
+                       if (ia->ia_next)
+                           ia->ia_next = oia->ia_next;
+                       else
+                               printf("Didn't unlink nsifadr from list\n");
+               }
+               (void) m_free(dtom(oia));
+               if (0 == --ns_interfaces) {
+                       /*
+                        * We reset to virginity and start all over again
+                        */
+                       ns_thishost = ns_zerohost;
+               }
+               return (0);
+       
+       case SIOCAIFADDR:
+               dstIsNew = 0; hostIsNew = 1;
+               if (ia->ia_addr.sns_family == AF_NS) {
+                       if (ifra->ifra_addr.sns_len == 0) {
+                               ifra->ifra_addr = ia->ia_addr;
+                               hostIsNew = 0;
+                       } else if (ns_neteq(ifra->ifra_addr.sns_addr,
+                                        ia->ia_addr.sns_addr))
+                               hostIsNew = 0;
+               }
+               if ((ifp->if_flags & IFF_POINTOPOINT) &&
+                   (ifra->ifra_dstaddr.sns_family == AF_NS)) {
+                       if (hostIsNew == 0)
+                               ns_ifscrub(ifp, ia);
+                       ia->ia_dstaddr = ifra->ifra_dstaddr;
+                       dstIsNew  = 1;
+               }
+               if (ifra->ifra_addr.sns_family == AF_NS &&
+                                           (hostIsNew || dstIsNew))
+                       error = ns_ifinit(ifp, ia, &ifra->ifra_addr, 0);
+               return (error);
 
        default:
                if (ifp->if_ioctl == 0)
 
        default:
                if (ifp->if_ioctl == 0)
@@ -172,19 +232,39 @@ ns_control(so, cmd, data, ifp)
        }
 }
 
        }
 }
 
+/*
+* Delete any previous route for an old address.
+*/
+ns_ifscrub(ifp, ia)
+       register struct ifnet *ifp;
+       register struct ns_ifaddr *ia; 
+{
+       if (ia->ia_flags & IFA_ROUTE) {
+               if (ifp->if_flags & IFF_POINTOPOINT) {
+                       rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
+               } else
+                       rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
+               ia->ia_flags &= ~IFA_ROUTE;
+       }
+}
 /*
  * Initialize an interface's internet address
  * and routing table entry.
  */
 /*
  * Initialize an interface's internet address
  * and routing table entry.
  */
-ns_ifinit(ifp, ia, sns)
+ns_ifinit(ifp, ia, sns, scrub)
        register struct ifnet *ifp;
        register struct ns_ifaddr *ia;
        register struct ifnet *ifp;
        register struct ns_ifaddr *ia;
-       struct sockaddr_ns *sns;
+       register struct sockaddr_ns *sns;
 {
 {
-       struct sockaddr_ns netaddr;
-       register union ns_host *h = &(IA_SNS(ia)->sns_addr.x_host);
+       struct sockaddr_ns oldaddr;
+       register union ns_host *h = &ia->ia_addr.sns_addr.x_host;
        int s = splimp(), error;
 
        int s = splimp(), error;
 
+       /*
+        * Set up new addresses.
+        */
+       oldaddr = ia->ia_addr;
+       ia->ia_addr = *sns;
        /*
         * The convention we shall adopt for naming is that
         * a supplied address of zero means that "we don't care".
        /*
         * The convention we shall adopt for naming is that
         * a supplied address of zero means that "we don't care".
@@ -193,42 +273,6 @@ ns_ifinit(ifp, ia, sns)
         * if there are multiple interfaces, use any address already
         * used.
         *
         * if there are multiple interfaces, use any address already
         * used.
         *
-        * If we have gotten into trouble and want to reset back to
-        * virginity, we recognize a request of the broadcast address.
-        */
-       if (ns_hosteqnh(sns->sns_addr.x_host, ns_broadhost)) {
-               ns_thishost = ns_zerohost;
-               splx(s);
-               return (0);
-       }
-
-       /*
-        * Delete any previous route for an old address.
-        */
-       bzero((caddr_t)&netaddr, sizeof (netaddr));
-       netaddr.sns_family = AF_NS;
-       netaddr.sns_addr.x_host = ns_broadhost;
-       netaddr.sns_addr.x_net = ia->ia_net;
-       if (ia->ia_flags & IFA_ROUTE) {
-               if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
-                   rtinit((struct sockaddr *)&netaddr, &ia->ia_addr,
-                                   (int)SIOCDELRT, 0);
-               } else
-                   rtinit(&ia->ia_dstaddr, &ia->ia_addr,
-                                   (int)SIOCDELRT, RTF_HOST);
-       }
-
-       /*
-        * Set up new addresses.
-        */
-       ia->ia_addr = *(struct sockaddr *)sns;
-       ia->ia_net = sns->sns_addr.x_net;
-       netaddr.sns_addr.x_net = ia->ia_net;
-       if (ifp->if_flags & IFF_BROADCAST) {
-               ia->ia_broadaddr = * (struct sockaddr *) &netaddr;
-       }
-
-       /*
         * Give the interface a chance to initialize
         * if this is its first address,
         * and to validate the address if necessary.
         * Give the interface a chance to initialize
         * if this is its first address,
         * and to validate the address if necessary.
@@ -236,6 +280,7 @@ ns_ifinit(ifp, ia, sns)
        if (ns_hosteqnh(ns_thishost, ns_zerohost)) {
                if (ifp->if_ioctl &&
                     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
        if (ns_hosteqnh(ns_thishost, ns_zerohost)) {
                if (ifp->if_ioctl &&
                     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
+                       ia->ia_addr = oldaddr;
                        splx(s);
                        return (error);
                }
                        splx(s);
                        return (error);
                }
@@ -245,27 +290,34 @@ ns_ifinit(ifp, ia, sns)
                *h = ns_thishost;
                if (ifp->if_ioctl &&
                     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
                *h = ns_thishost;
                if (ifp->if_ioctl &&
                     (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
+                       ia->ia_addr = oldaddr;
                        splx(s);
                        return (error);
                }
                if (!ns_hosteqnh(ns_thishost,*h)) {
                        splx(s);
                        return (error);
                }
                if (!ns_hosteqnh(ns_thishost,*h)) {
+                       ia->ia_addr = oldaddr;
                        splx(s);
                        return (EINVAL);
                }
        } else {
                        splx(s);
                        return (EINVAL);
                }
        } else {
+               ia->ia_addr = oldaddr;
                splx(s);
                return (EINVAL);
        }
                splx(s);
                return (EINVAL);
        }
-
        /*
         * Add route for the network.
         */
        /*
         * Add route for the network.
         */
+       if (scrub) {
+               ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
+               ns_ifscrub(ifp, ia);
+               ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
+       }
        if (ifp->if_flags & IFF_POINTOPOINT)
        if (ifp->if_flags & IFF_POINTOPOINT)
-               rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
-                       RTF_HOST|RTF_UP);
-       else
-               rtinit(&ia->ia_broadaddr, &ia->ia_addr, (int)SIOCADDRT,
-                       RTF_UP);
+               rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
+       else {
+               ia->ia_broadaddr.sns_addr.x_net = ia->ia_net;
+               rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
+       }
        ia->ia_flags |= IFA_ROUTE;
        return (0);
 }
        ia->ia_flags |= IFA_ROUTE;
        return (0);
 }