date and time created 85/05/30 19:10:57 by sklower
authorKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Fri, 31 May 1985 10:10:57 +0000 (02:10 -0800)
committerKeith Sklower <sklower@ucbvax.Berkeley.EDU>
Fri, 31 May 1985 10:10:57 +0000 (02:10 -0800)
SCCS-vsn: sys/netns/ns_ip.c 6.1

usr/src/sys/netns/ns_ip.c [new file with mode: 0644]

diff --git a/usr/src/sys/netns/ns_ip.c b/usr/src/sys/netns/ns_ip.c
new file mode 100644 (file)
index 0000000..58a6da8
--- /dev/null
@@ -0,0 +1,298 @@
+/*      ns_ip.c     6.1     85/05/30     */
+
+/*
+ * Software interface driver for encapsulating ns in ip.
+ */
+
+#ifdef NSIP
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "errno.h"
+#include "ioctl.h"
+
+#include "../net/if.h"
+#include "../net/netisr.h"
+#include "../net/route.h"
+
+#include "../netinet/in.h"
+#include "../netinet/in_systm.h"
+#include "../netinet/in_var.h"
+#include "../netinet/ip.h"
+#include "../netinet/ip_var.h"
+
+#ifdef vax
+#include "../vax/mtpr.h"
+#endif
+
+#include "../netns/ns.h"
+#include "../netns/ns_if.h"
+#include "../netns/idp.h"
+
+struct ifnet_en {
+       struct ifnet ifen_ifnet;
+       struct route ifen_route;
+       struct in_addr ifen_src;
+       struct in_addr ifen_dst;
+};
+
+int    nsipoutput(), nsipioctl();
+#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 *
+nsipattach()
+{
+       register struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
+       register struct ifnet *ifp;
+       register struct sockaddr_in *sin;
+
+       if (m==0) return (0);
+       m->m_off = MMINOFF;
+       m->m_len = sizeof(struct ifnet_en);
+       m->m_next = nsip_list;
+       nsip_list = m;
+       ifp = mtod(m, struct ifnet *);
+
+       ifp->if_name = "nsip";
+       ifp->if_mtu = LOMTU;
+       ifp->if_ioctl = nsipioctl;
+       ifp->if_output = nsipoutput;
+       ifp->if_flags = IFF_POINTOPOINT;
+       ifp->if_unit = nsipif.if_unit++;
+       if_attach(ifp);
+       return(dtom(ifp));
+}
+
+
+/*
+ * Process an ioctl request.
+ */
+/* ARGSUSED */
+nsipioctl(ifp, cmd, data)
+       register struct ifnet *ifp;
+       int cmd;
+       caddr_t data;
+{
+       int error = 0;
+
+       switch (cmd) {
+
+       case SIOCSIFADDR:
+               ifp->if_flags |= IFF_UP;
+               /*
+                * Everything else is done at a higher level.
+                */
+               break;
+
+       default:
+               error = EINVAL;
+       }
+       return (error);
+}
+
+struct mbuf *nsip_badlen;
+struct mbuf *nsip_lastin;
+int nsip_hold_input;
+
+idpip_input(m0)
+       struct mbuf *m0;
+{
+       register struct ip *ip;
+       register struct idp *idp;
+       register struct mbuf *m;
+       register struct ifqueue *ifq = &nsintrq;
+       int len, s;
+
+       if(nsip_hold_input) {
+               if(nsip_lastin) {
+                       m_free(nsip_lastin);
+               }
+               nsip_lastin = m_copy(m0, 0, M_COPYALL);
+       }
+       /*
+        * 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) &&
+           (m = m_pullup(m, s))==0) {
+               nsipif.if_ierrors++;
+               return;
+       }
+       ip = mtod(m, struct ip *);
+       if (ip->ip_hl > (sizeof (struct ip) >> 2))
+               ip_stripoptions(ip, (struct mbuf *)0);
+
+       /*
+        * Make mbuf data length reflect IDP length.
+        * If not enough data to reflect IDP length, drop.
+        */
+       m->m_off += sizeof (struct ip);
+       m->m_len -= sizeof (struct ip);
+       idp = mtod(m, struct idp *);
+       len = ntohs(idp->idp_len);
+       if (ip->ip_len != len) {
+               if (len > ip->ip_len) {
+                       nsipif.if_ierrors++;
+                       if(nsip_badlen) m_freem(nsip_badlen);
+                       nsip_badlen = m;
+                       return;
+               }
+               m_adj(m, len - ip->ip_len);
+               /* ip->ip_len = len; */
+       }
+       /*
+        * Deliver to NS
+        */
+       s = splimp();
+       if (IF_QFULL(ifq)) {
+               IF_DROP(ifq);
+               m_freem(m0);
+               splx(s);
+               return (ENOBUFS);
+       }
+       IF_ENQUEUE(ifq, m0);
+       schednetisr(NETISR_NS);
+       splx(s);
+       return (0);
+bad:
+       m_freem(m);
+       return (0);
+}
+
+nsipoutput(ifn, m0, dst)
+       struct ifnet_en *ifn;
+       struct mbuf *m0;
+       struct sockaddr *dst;
+{
+
+       register struct mbuf *m = dtom(ifn);
+       register struct ip *ip;
+       register struct route *ro = &(ifn->ifen_route);
+       register int len = 0;
+       struct in_addr in_src, in_dst;
+       register struct idp *idp = mtod(m0, struct idp *);
+       int error;
+
+       if (m->m_len != sizeof(struct ifnet_en)) {
+               printf("nsipoutput: bad dst ifp %x\n", ifn);
+               goto bad;
+       }
+       ifn->ifen_ifnet.if_opackets++;
+       nsipif.if_opackets++;
+
+
+       /*
+        * Calculate data length and make space
+        * for IP header.
+        */
+       len =  ntohs(idp->idp_len);
+       m = m0;
+       if(m->m_off < MMINOFF + sizeof (struct ip)) {
+               m = m_get(M_DONTWAIT, MT_HEADER);
+               if (m == 0) {
+                       m_freem(m0);
+                       return (ENOBUFS);
+               }
+               m->m_off = MMAXOFF - sizeof (struct ip);
+               m->m_len = sizeof (struct ip);
+               m->m_next = m0;
+       } else {
+               m->m_off -= sizeof (struct ip);
+               m->m_len += sizeof (struct ip);
+       }
+       /*
+        * Fill in IP header.
+        */
+       ip = mtod(m, struct ip *);
+       *(long *)ip = 0;
+       ip->ip_p = IPPROTO_PUP;
+       ip->ip_src = ifn->ifen_src;
+       ip->ip_dst = ifn->ifen_dst;
+       ip->ip_len = (u_short)len + sizeof (struct ip);
+       ip->ip_ttl = MAXTTL;
+
+       /*
+        * Output final datagram.
+        */
+       error =  (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST));
+       if (error) {
+               ifn->ifen_ifnet.if_oerrors++;
+               ifn->ifen_ifnet.if_ierrors = error;
+       }
+       return (error);
+bad:
+       m_freem(m0);
+       return(ENETUNREACH);
+}
+
+struct ifreq ifr = {"nsip0"};
+
+nsip_route(m)
+       register struct mbuf *m;
+{
+       register struct nsip_req *rq = mtod(m, struct nsip_req *);
+       struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns;
+       struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip;
+       int flags = rq->rq_flags;
+       struct ifnet *ifp;
+       struct route ro;
+       struct ifnet_en *ifn;
+       int error;
+       struct sockaddr_in *dst;
+       struct sockaddr_in *src;
+       /*
+        * First, determine if we can get to the destination
+        */
+       bzero((caddr_t)&ro, sizeof (ro));
+       ro.ro_dst = *(struct sockaddr *)ip_dst;
+       dst = (struct sockaddr_in *)& ro.ro_dst;
+       rtalloc(&ro);
+       if (ro.ro_rt == 0 || (ifp = ro.ro_rt->rt_ifp) == 0) {
+               return (ENETUNREACH);
+       }
+       /*
+        * And see how he's going to get back to us:
+        */
+       {
+               register struct in_ifaddr *ia;
+               struct ifnet *ifp = ro.ro_rt->rt_ifp;
+
+               for (ia = in_ifaddr; ia; ia = ia->ia_next)
+                       if (ia->ia_ifp == ifp)
+                               break;
+               if (ia == 0)
+                       ia = in_ifaddr;
+               if (ia == 0) {
+                       return (EADDRNOTAVAIL);
+               }
+               src = (struct sockaddr_in *)&ia->ia_addr;
+       }
+       /*
+        * Is there space?
+        */
+       m = nsipattach();
+       if (m==NULL) {return (ENOBUFS);}
+       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;
+
+       /*
+        * now configure this as a point to point link
+        */
+       ifr.ifr_name[4] = '0' + nsipif.if_unit - 1;
+       ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst;
+       return(ns_control((struct socket *)0, SIOCSIFADDR, (caddr_t)&ifr,
+                       (struct ifnet *)ifn));
+}
+#endif