changes for var. length sockaddrs, routing lookup changes,
[unix-history] / usr / src / sys / netns / ns.c
index cf0c2e5..e5ce2c9 100644 (file)
@@ -1,9 +1,20 @@
 /*
 /*
- * Copyright (c) 1982 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     @(#)ns.c        6.4 (Berkeley) %G%
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)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;
-
-       hp->afh_nethash = ns_netof(sns->sns_addr);
-       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_netof(sns1->sns_addr) == ns_netof(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).
@@ -59,14 +52,17 @@ 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.
         */
-       if (ifp==0)
+       if (ifp == 0)
                return (EADDRNOTAVAIL);
        for (ia = ns_ifaddr; ia; ia = ia->ia_next)
                if (ia->ia_ifp == ifp)
                return (EADDRNOTAVAIL);
        for (ia = ns_ifaddr; ia; ia = ia->ia_next)
                if (ia->ia_ifp == ifp)
@@ -77,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);
 
 
@@ -86,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:
@@ -94,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);
        }
 
@@ -102,11 +98,21 @@ ns_control(so, cmd, data, ifp)
                return (u.u_error);
 
        switch (cmd) {
                return (u.u_error);
 
        switch (cmd) {
-
-       case SIOCSIFDSTADDR:
-               return (EOPNOTSUPP);
+       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 SIOCSIFADDR:
+       case SIOCSIFDSTADDR:
                if (ia == (struct ns_ifaddr *)0) {
                        m = m_getclr(M_WAIT, MT_IFADDR);
                        if (m == (struct mbuf *)NULL)
                if (ia == (struct ns_ifaddr *)0) {
                        m = m_getclr(M_WAIT, MT_IFADDR);
                        if (m == (struct mbuf *)NULL)
@@ -125,10 +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++;
                }
                }
-               return
-                   (ns_ifinit(ifp, ia, (struct sockaddr_ns *)&ifr->ifr_addr));
+       }
+
+       switch (cmd) {
+               int error;
+
+       case SIOCSIFDSTADDR:
+               if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
+                       return (EINVAL);
+               if (ia->ia_flags & IFA_ROUTE) {
+                       rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
+                       ia->ia_flags &= ~IFA_ROUTE;
+               }
+               if (ifp->if_ioctl) {
+                       error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia);
+                       if (error)
+                               return (error);
+               }
+               *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
+               return (0);
+
+       case SIOCSIFADDR:
+               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)
@@ -137,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".
@@ -158,61 +273,14 @@ 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(EINVAL);
-       }
-
-       /*
-        * 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, -1);
-               } else
-                   rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr, -1);
-       }
-
-       /*
-        * 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;
-       }
-       /*
-        * Point to point links are a little touchier --
-        * We have to have an address of our own first,
-        * and will use the supplied address as that of the other end.
-        */
-       if (ifp->if_flags & IFF_POINTOPOINT) {
-               struct sockaddr_ns *sns2 = IA_SNS(ia);
-               if (ns_hosteqnh(ns_zerohost,ns_thishost))
-                       return(EINVAL);
-               ia->ia_dstaddr = ia->ia_addr;
-               sns2->sns_addr.x_host = ns_thishost;
-               sns->sns_addr.x_host = ns_thishost;
-       }
-       /*
         * 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.
         */
-
        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);
                }
@@ -222,42 +290,65 @@ 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);
                }
                        splx(s);
                        return (error);
                }
-               if(!ns_hosteqnh(ns_thishost,*h)) {
+               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);
                splx(s);
-               return(EINVAL);
+               return (EINVAL);
        }
        /*
         * Add route for the network.
         */
        }
        /*
         * Add route for the network.
         */
-       if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
-               rtinit((struct sockaddr *)&netaddr, &ia->ia_addr, RTF_UP);
-       } else
-               rtinit((struct sockaddr *)&ia->ia_dstaddr, &ia->ia_addr,
-                       RTF_HOST|RTF_UP);
+       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)
+               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;
        ia->ia_flags |= IFA_ROUTE;
-       return(0);
+       return (0);
 }
 
 /*
  * Return address info for specified internet network.
  */
 struct ns_ifaddr *
 }
 
 /*
  * Return address info for specified internet network.
  */
 struct ns_ifaddr *
-ns_iaonnetof(net)
-       union ns_net net;
+ns_iaonnetof(dst)
+       register struct ns_addr *dst;
 {
        register struct ns_ifaddr *ia;
 {
        register struct ns_ifaddr *ia;
+       register struct ns_addr *compare;
+       register struct ifnet *ifp;
+       struct ns_ifaddr *ia_maybe = 0;
+       union ns_net net = dst->x_net;
 
 
-#define        NtoL(x) (*(long *)(&(x)))
-       for (ia = ns_ifaddr; ia; ia = ia->ia_next)
-               if (NtoL(ia->ia_net) == NtoL(net))
-                       return (ia);
-       return ((struct ns_ifaddr *)0);
+       for (ia = ns_ifaddr; ia; ia = ia->ia_next) {
+               if (ifp = ia->ia_ifp) {
+                       if (ifp->if_flags & IFF_POINTOPOINT) {
+                               compare = &satons_addr(ia->ia_dstaddr);
+                               if (ns_hosteq(*dst, *compare))
+                                       return (ia);
+                               if (ns_neteqnn(net, ia->ia_net))
+                                       ia_maybe = ia;
+                       } else {
+                               if (ns_neteqnn(net, ia->ia_net))
+                                       return (ia);
+                       }
+               }
+       }
+       return (ia_maybe);
 }
 #endif
 }
 #endif