BSD 4_3 release
[unix-history] / usr / src / sys / netns / ns_ip.c
index ee6d2a2..7a20a3b 100644 (file)
@@ -1,9 +1,9 @@
 /*
 /*
- * Copyright (c) 1982 Regents of the University of California.
+ * Copyright (c) 1985, 1986 Regents of the University of California.
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
  * All rights reserved.  The Berkeley software License Agreement
  * specifies the terms and conditions for redistribution.
  *
- *     @(#)ns_ip.c     6.6 (Berkeley) %G%
+ *     @(#)ns_ip.c     7.1 (Berkeley) 6/5/86
  */
 
 /*
  */
 
 /*
@@ -18,6 +18,7 @@
 #include "socketvar.h"
 #include "errno.h"
 #include "ioctl.h"
 #include "socketvar.h"
 #include "errno.h"
 #include "ioctl.h"
+#include "protosw.h"
 
 #include "../net/if.h"
 #include "../net/netisr.h"
 
 #include "../net/if.h"
 #include "../net/netisr.h"
 #include "../netns/ns_if.h"
 #include "../netns/idp.h"
 
 #include "../netns/ns_if.h"
 #include "../netns/idp.h"
 
-#ifdef BBNNET
-#include "../bbnnet/in_pcb.h"
-#include "../bbnnet/nopcb.h"
-#endif
-
 struct ifnet_en {
        struct ifnet ifen_ifnet;
        struct route ifen_route;
 struct ifnet_en {
        struct ifnet ifen_ifnet;
        struct route ifen_route;
@@ -53,7 +49,6 @@ int   nsipoutput(), nsipioctl();
 #define LOMTU  (1024+512);
 
 struct ifnet nsipif;
 #define LOMTU  (1024+512);
 
 struct ifnet nsipif;
-union ns_net nsip_net;
 struct mbuf *nsip_list;                /* list of all hosts and gateways or
                                        broadcast addrs */
 
 struct mbuf *nsip_list;                /* list of all hosts and gateways or
                                        broadcast addrs */
 
@@ -63,7 +58,7 @@ nsipattach()
        register struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
        register struct ifnet *ifp;
 
        register struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
        register struct ifnet *ifp;
 
-       if (m==0) return (0);
+       if (m == NULL) return (NULL);
        m->m_off = MMINOFF;
        m->m_len = sizeof(struct ifnet_en);
        m->m_next = nsip_list;
        m->m_off = MMINOFF;
        m->m_len = sizeof(struct ifnet_en);
        m->m_next = nsip_list;
@@ -77,7 +72,7 @@ nsipattach()
        ifp->if_flags = IFF_POINTOPOINT;
        ifp->if_unit = nsipif.if_unit++;
        if_attach(ifp);
        ifp->if_flags = IFF_POINTOPOINT;
        ifp->if_unit = nsipif.if_unit++;
        if_attach(ifp);
-       return(dtom(ifp));
+       return (dtom(ifp));
 }
 
 
 }
 
 
@@ -91,16 +86,26 @@ nsipioctl(ifp, cmd, data)
        caddr_t data;
 {
        int error = 0;
        caddr_t data;
 {
        int error = 0;
+       struct ifreq *ifr;
 
        switch (cmd) {
 
        case SIOCSIFADDR:
                ifp->if_flags |= IFF_UP;
 
        switch (cmd) {
 
        case SIOCSIFADDR:
                ifp->if_flags |= IFF_UP;
+               /* fall into: */
+
+       case SIOCSIFDSTADDR:
                /*
                 * Everything else is done at a higher level.
                 */
                break;
 
                /*
                 * Everything else is done at a higher level.
                 */
                break;
 
+       case SIOCSIFFLAGS:
+               ifr = (struct ifreq *)data;
+               if ((ifr->ifr_flags & IFF_UP) == 0)
+                       error = nsip_free(ifp);
+
+
        default:
                error = EINVAL;
        }
        default:
                error = EINVAL;
        }
@@ -111,45 +116,42 @@ struct mbuf *nsip_badlen;
 struct mbuf *nsip_lastin;
 int nsip_hold_input;
 
 struct mbuf *nsip_lastin;
 int nsip_hold_input;
 
-idpip_input(m0)
-       struct mbuf *m0;
+idpip_input(m, ifp)
+       register struct mbuf *m;
+       struct ifnet *ifp;
 {
        register struct ip *ip;
        register struct idp *idp;
 {
        register struct ip *ip;
        register struct idp *idp;
-       register struct mbuf *m;
        register struct ifqueue *ifq = &nsintrq;
        int len, s;
 
        register struct ifqueue *ifq = &nsintrq;
        int len, s;
 
-       if(nsip_hold_input) {
-               if(nsip_lastin) {
+       if (nsip_hold_input) {
+               if (nsip_lastin) {
                        m_freem(nsip_lastin);
                }
                        m_freem(nsip_lastin);
                }
-               nsip_lastin = m_copy(m0, 0, (int)M_COPYALL);
+               nsip_lastin = m_copy(m, 0, (int)M_COPYALL);
        }
        /*
         * Get IP and IDP header together in first mbuf.
         */
        nsipif.if_ipackets++;
        }
        /*
         * Get IP and IDP header together in first mbuf.
         */
        nsipif.if_ipackets++;
-       m = m0;
        s = sizeof (struct ip) + sizeof (struct idp);
        if ((m->m_off > MMAXOFF || m->m_len < s) &&
        s = sizeof (struct ip) + sizeof (struct idp);
        if ((m->m_off > MMAXOFF || m->m_len < s) &&
-           (m = m_pullup(m, s))==0) {
+           (m = m_pullup(m, s)) == 0) {
                nsipif.if_ierrors++;
                return;
        }
        ip = mtod(m, struct ip *);
                nsipif.if_ierrors++;
                return;
        }
        ip = mtod(m, struct ip *);
-#ifndef BBNNET
        if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
                ip_stripoptions(ip, (struct mbuf *)0);
                if (m->m_len < s) {
        if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
                ip_stripoptions(ip, (struct mbuf *)0);
                if (m->m_len < s) {
-                       if ((m = m_pullup(m, s))==0) {
+                       if ((m = m_pullup(m, s)) == 0) {
                                nsipif.if_ierrors++;
                                return;
                        }
                        ip = mtod(m, struct ip *);
                }
        }
                                nsipif.if_ierrors++;
                                return;
                        }
                        ip = mtod(m, struct ip *);
                }
        }
-#endif
 
        /*
         * Make mbuf data length reflect IDP length.
 
        /*
         * Make mbuf data length reflect IDP length.
@@ -163,23 +165,45 @@ idpip_input(m0)
        if (ip->ip_len != len) {
                if (len > ip->ip_len) {
                        nsipif.if_ierrors++;
        if (ip->ip_len != len) {
                if (len > ip->ip_len) {
                        nsipif.if_ierrors++;
-                       if(nsip_badlen) m_freem(nsip_badlen);
+                       if (nsip_badlen) m_freem(nsip_badlen);
                        nsip_badlen = m;
                        return;
                }
                /* Any extra will be trimmed off by the NS routines */
        }
                        nsip_badlen = m;
                        return;
                }
                /* Any extra will be trimmed off by the NS routines */
        }
+
+       /*
+        * Place interface pointer before the data
+        * for the receiving protocol.
+        */
+       if (m->m_off >= MMINOFF + sizeof(struct ifnet *)) {
+               m->m_off -= sizeof(struct ifnet *);
+               m->m_len += sizeof(struct ifnet *);
+       } else {
+               struct mbuf *n;
+
+               n = m_get(M_DONTWAIT, MT_HEADER);
+               if (n == (struct mbuf *)0)
+                       goto bad;
+               n->m_off = MMINOFF;
+               n->m_len = sizeof(struct ifnet *);
+               n->m_next = m;
+               m = n;
+       }
+       *(mtod(m, struct ifnet **)) = ifp;
+
        /*
         * Deliver to NS
         */
        s = splimp();
        if (IF_QFULL(ifq)) {
                IF_DROP(ifq);
        /*
         * Deliver to NS
         */
        s = splimp();
        if (IF_QFULL(ifq)) {
                IF_DROP(ifq);
-               m_freem(m0);
+bad:
+               m_freem(m);
                splx(s);
                return;
        }
                splx(s);
                return;
        }
-       IF_ENQUEUE(ifq, m0);
+       IF_ENQUEUE(ifq, m);
        schednetisr(NETISR_NS);
        splx(s);
        return;
        schednetisr(NETISR_NS);
        splx(s);
        return;
@@ -214,7 +238,7 @@ nsipoutput(ifn, m0, dst)
        len =  ntohs(idp->idp_len);
        if (len & 1) len++;             /* Preserve Garbage Byte */
        m = m0;
        len =  ntohs(idp->idp_len);
        if (len & 1) len++;             /* Preserve Garbage Byte */
        m = m0;
-       if(m->m_off < MMINOFF + sizeof (struct ip)) {
+       if (m->m_off < MMINOFF + sizeof (struct ip)) {
                m = m_get(M_DONTWAIT, MT_HEADER);
                if (m == 0) {
                        m_freem(m0);
                m = m_get(M_DONTWAIT, MT_HEADER);
                if (m == 0) {
                        m_freem(m0);
@@ -235,10 +259,6 @@ nsipoutput(ifn, m0, dst)
        ip->ip_p = IPPROTO_IDP;
        ip->ip_src = ifn->ifen_src;
        ip->ip_dst = ifn->ifen_dst;
        ip->ip_p = IPPROTO_IDP;
        ip->ip_src = ifn->ifen_src;
        ip->ip_dst = ifn->ifen_dst;
-#ifdef BBNNET
-       ip->ip_tos = 0;
-       NOPCB_IPSEND(m, len, 0, error);
-#else
        ip->ip_len = (u_short)len + sizeof (struct ip);
        ip->ip_ttl = MAXTTL;
 
        ip->ip_len = (u_short)len + sizeof (struct ip);
        ip->ip_ttl = MAXTTL;
 
@@ -246,7 +266,6 @@ nsipoutput(ifn, m0, dst)
         * Output final datagram.
         */
        error =  (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST));
         * Output final datagram.
         */
        error =  (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST));
-#endif
        if (error) {
                ifn->ifen_ifnet.if_oerrors++;
                ifn->ifen_ifnet.if_ierrors = error;
        if (error) {
                ifn->ifen_ifnet.if_oerrors++;
                ifn->ifen_ifnet.if_ierrors = error;
@@ -254,7 +273,7 @@ nsipoutput(ifn, m0, dst)
        return (error);
 bad:
        m_freem(m0);
        return (error);
 bad:
        m_freem(m0);
-       return(ENETUNREACH);
+       return (ENETUNREACH);
 }
 
 struct ifreq ifr = {"nsip0"};
 }
 
 struct ifreq ifr = {"nsip0"};
@@ -268,8 +287,14 @@ nsip_route(m)
        struct route ro;
        struct ifnet_en *ifn;
        struct sockaddr_in *src;
        struct route ro;
        struct ifnet_en *ifn;
        struct sockaddr_in *src;
+
        /*
        /*
-        * First, determine if we can get to the destination
+        * First, make sure we already have an ns address:
+        */
+       if (ns_hosteqnh(ns_thishost, ns_zerohost))
+               return (EADDRNOTAVAIL);
+       /*
+        * Now, determine if we can get to the destination
         */
        bzero((caddr_t)&ro, sizeof (ro));
        ro.ro_dst = *(struct sockaddr *)ip_dst;
         */
        bzero((caddr_t)&ro, sizeof (ro));
        ro.ro_dst = *(struct sockaddr *)ip_dst;
@@ -277,8 +302,10 @@ nsip_route(m)
        if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
                return (ENETUNREACH);
        }
        if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
                return (ENETUNREACH);
        }
+
        /*
         * And see how he's going to get back to us:
        /*
         * And see how he's going to get back to us:
+        * i.e., what return ip address do we use?
         */
        {
                register struct in_ifaddr *ia;
         */
        {
                register struct in_ifaddr *ia;
@@ -290,18 +317,28 @@ nsip_route(m)
                if (ia == 0)
                        ia = in_ifaddr;
                if (ia == 0) {
                if (ia == 0)
                        ia = in_ifaddr;
                if (ia == 0) {
+                       RTFREE(ro.ro_rt);
                        return (EADDRNOTAVAIL);
                }
                src = (struct sockaddr_in *)&ia->ia_addr;
        }
                        return (EADDRNOTAVAIL);
                }
                src = (struct sockaddr_in *)&ia->ia_addr;
        }
+
        /*
        /*
-        * Is there space?
+        * Is there a free (pseudo-)interface or space?
         */
         */
-       m = nsipattach();
-       if (m==NULL) {return (ENOBUFS);}
+       for (m = nsip_list; m; m = m->m_next) {
+               struct ifnet *ifp = mtod(m, struct ifnet *);
+               if ((ifp->if_flags & IFF_UP) == 0)
+                       break;
+       }
+       if (m == (struct mbuf *) 0)
+               m = nsipattach();
+       if (m == NULL) {
+               RTFREE(ro.ro_rt);
+               return (ENOBUFS);
+       }
        ifn = mtod(m, struct ifnet_en *);
 
        ifn = mtod(m, struct ifnet_en *);
 
-       ro.ro_rt->rt_use++;
        ifn->ifen_route = ro;
        ifn->ifen_dst =  ip_dst->sin_addr;
        ifn->ifen_src = src->sin_addr;
        ifn->ifen_route = ro;
        ifn->ifen_dst =  ip_dst->sin_addr;
        ifn->ifen_src = src->sin_addr;
@@ -311,7 +348,68 @@ nsip_route(m)
         */
        ifr.ifr_name[4] = '0' + nsipif.if_unit - 1;
        ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst;
         */
        ifr.ifr_name[4] = '0' + nsipif.if_unit - 1;
        ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst;
-       return(ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr,
+       (void)ns_control((struct socket *)0, (int)SIOCSIFDSTADDR, (caddr_t)&ifr,
+                       (struct ifnet *)ifn);
+       satons_addr(ifr.ifr_addr).x_host = ns_thishost;
+       return (ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr,
                        (struct ifnet *)ifn));
 }
                        (struct ifnet *)ifn));
 }
+
+nsip_free(ifp)
+struct ifnet *ifp;
+{
+       register struct ifnet_en *ifn = (struct ifnet_en *)ifp;
+       struct route *ro = & ifn->ifen_route;
+
+       if (ro->ro_rt) {
+               RTFREE(ro->ro_rt);
+               ro->ro_rt = 0;
+       }
+       ifp->if_flags &= ~IFF_UP;
+       return (0);
+}
+
+nsip_ctlinput(cmd, sa)
+       int cmd;
+       struct sockaddr *sa;
+{
+       extern u_char inetctlerrmap[];
+       struct sockaddr_in *sin;
+       int in_rtchange();
+
+       if ((unsigned)cmd >= PRC_NCMDS)
+               return;
+       if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
+               return;
+       sin = (struct sockaddr_in *)sa;
+       if (sin->sin_addr.s_addr == INADDR_ANY)
+               return;
+
+       switch (cmd) {
+
+       case PRC_ROUTEDEAD:
+       case PRC_REDIRECT_NET:
+       case PRC_REDIRECT_HOST:
+       case PRC_REDIRECT_TOSNET:
+       case PRC_REDIRECT_TOSHOST:
+               nsip_rtchange(&sin->sin_addr);
+               break;
+       }
+}
+
+nsip_rtchange(dst)
+       register struct in_addr *dst;
+{
+       register struct mbuf *m;
+       register struct ifnet_en *ifn;
+
+       for (m = nsip_list; m; m = m->m_next) {
+               ifn = mtod(m, struct ifnet_en *);
+               if (ifn->ifen_dst.s_addr == dst->s_addr &&
+                       ifn->ifen_route.ro_rt) {
+                               RTFREE(ifn->ifen_route.ro_rt);
+                               ifn->ifen_route.ro_rt = 0;
+               }
+       }
+}
 #endif
 #endif