xref: /csrg-svn/sys/netns/ns_ip.c (revision 23839)
123210Smckusick /*
223210Smckusick  * Copyright (c) 1982 Regents of the University of California.
323210Smckusick  * All rights reserved.  The Berkeley software License Agreement
423210Smckusick  * specifies the terms and conditions for redistribution.
523210Smckusick  *
6*23839Ssklower  *	@(#)ns_ip.c	6.3 (Berkeley) 07/02/85
723210Smckusick  */
821487Ssklower 
921487Ssklower /*
1021487Ssklower  * Software interface driver for encapsulating ns in ip.
1121487Ssklower  */
1221487Ssklower 
1321487Ssklower #ifdef NSIP
1421487Ssklower #include "param.h"
1521487Ssklower #include "systm.h"
1621487Ssklower #include "mbuf.h"
1721487Ssklower #include "socket.h"
1821487Ssklower #include "errno.h"
1921487Ssklower #include "ioctl.h"
2021487Ssklower 
2121487Ssklower #include "../net/if.h"
2221487Ssklower #include "../net/netisr.h"
2321487Ssklower #include "../net/route.h"
2421487Ssklower 
2521487Ssklower #include "../netinet/in.h"
2621487Ssklower #include "../netinet/in_systm.h"
2721487Ssklower #include "../netinet/in_var.h"
2821487Ssklower #include "../netinet/ip.h"
2921487Ssklower #include "../netinet/ip_var.h"
3021487Ssklower 
3121487Ssklower #ifdef vax
3221487Ssklower #include "../vax/mtpr.h"
3321487Ssklower #endif
3421487Ssklower 
3521487Ssklower #include "../netns/ns.h"
3621487Ssklower #include "../netns/ns_if.h"
3721487Ssklower #include "../netns/idp.h"
3821487Ssklower 
3921487Ssklower struct ifnet_en {
4021487Ssklower 	struct ifnet ifen_ifnet;
4121487Ssklower 	struct route ifen_route;
4221487Ssklower 	struct in_addr ifen_src;
4321487Ssklower 	struct in_addr ifen_dst;
4421487Ssklower };
4521487Ssklower 
4621487Ssklower int	nsipoutput(), nsipioctl();
4721487Ssklower #define LOMTU	(1024+512);
4821487Ssklower 
4921487Ssklower struct ifnet nsipif;
5021487Ssklower union ns_net nsip_net;
5121487Ssklower struct mbuf *nsip_list;		/* list of all hosts and gateways or
5221487Ssklower 					broadcast addrs */
5321487Ssklower 
5421487Ssklower struct mbuf *
5521487Ssklower nsipattach()
5621487Ssklower {
5721487Ssklower 	register struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
5821487Ssklower 	register struct ifnet *ifp;
5921487Ssklower 	register struct sockaddr_in *sin;
6021487Ssklower 
6121487Ssklower 	if (m==0) return (0);
6221487Ssklower 	m->m_off = MMINOFF;
6321487Ssklower 	m->m_len = sizeof(struct ifnet_en);
6421487Ssklower 	m->m_next = nsip_list;
6521487Ssklower 	nsip_list = m;
6621487Ssklower 	ifp = mtod(m, struct ifnet *);
6721487Ssklower 
6821487Ssklower 	ifp->if_name = "nsip";
6921487Ssklower 	ifp->if_mtu = LOMTU;
7021487Ssklower 	ifp->if_ioctl = nsipioctl;
7121487Ssklower 	ifp->if_output = nsipoutput;
7221487Ssklower 	ifp->if_flags = IFF_POINTOPOINT;
7321487Ssklower 	ifp->if_unit = nsipif.if_unit++;
7421487Ssklower 	if_attach(ifp);
7521487Ssklower 	return(dtom(ifp));
7621487Ssklower }
7721487Ssklower 
7821487Ssklower 
7921487Ssklower /*
8021487Ssklower  * Process an ioctl request.
8121487Ssklower  */
8221487Ssklower /* ARGSUSED */
8321487Ssklower nsipioctl(ifp, cmd, data)
8421487Ssklower 	register struct ifnet *ifp;
8521487Ssklower 	int cmd;
8621487Ssklower 	caddr_t data;
8721487Ssklower {
8821487Ssklower 	int error = 0;
8921487Ssklower 
9021487Ssklower 	switch (cmd) {
9121487Ssklower 
9221487Ssklower 	case SIOCSIFADDR:
9321487Ssklower 		ifp->if_flags |= IFF_UP;
9421487Ssklower 		/*
9521487Ssklower 		 * Everything else is done at a higher level.
9621487Ssklower 		 */
9721487Ssklower 		break;
9821487Ssklower 
9921487Ssklower 	default:
10021487Ssklower 		error = EINVAL;
10121487Ssklower 	}
10221487Ssklower 	return (error);
10321487Ssklower }
10421487Ssklower 
10521487Ssklower struct mbuf *nsip_badlen;
10621487Ssklower struct mbuf *nsip_lastin;
10721487Ssklower int nsip_hold_input;
10821487Ssklower 
10921487Ssklower idpip_input(m0)
11021487Ssklower 	struct mbuf *m0;
11121487Ssklower {
11221487Ssklower 	register struct ip *ip;
11321487Ssklower 	register struct idp *idp;
11421487Ssklower 	register struct mbuf *m;
11521487Ssklower 	register struct ifqueue *ifq = &nsintrq;
11621487Ssklower 	int len, s;
11721487Ssklower 
11821487Ssklower 	if(nsip_hold_input) {
11921487Ssklower 		if(nsip_lastin) {
12021487Ssklower 			m_free(nsip_lastin);
12121487Ssklower 		}
12221487Ssklower 		nsip_lastin = m_copy(m0, 0, M_COPYALL);
12321487Ssklower 	}
12421487Ssklower 	/*
12521487Ssklower 	 * Get IP and IDP header together in first mbuf.
12621487Ssklower 	 */
12721487Ssklower 	nsipif.if_ipackets++;
12821487Ssklower 	m = m0;
12921487Ssklower 	s = sizeof (struct ip) + sizeof (struct idp);
13021487Ssklower 	if ((m->m_off > MMAXOFF || m->m_len < s) &&
13121487Ssklower 	    (m = m_pullup(m, s))==0) {
13221487Ssklower 		nsipif.if_ierrors++;
13321487Ssklower 		return;
13421487Ssklower 	}
13521487Ssklower 	ip = mtod(m, struct ip *);
13621487Ssklower 	if (ip->ip_hl > (sizeof (struct ip) >> 2))
13721487Ssklower 		ip_stripoptions(ip, (struct mbuf *)0);
13821487Ssklower 
13921487Ssklower 	/*
14021487Ssklower 	 * Make mbuf data length reflect IDP length.
14121487Ssklower 	 * If not enough data to reflect IDP length, drop.
14221487Ssklower 	 */
14321487Ssklower 	m->m_off += sizeof (struct ip);
14421487Ssklower 	m->m_len -= sizeof (struct ip);
14521487Ssklower 	idp = mtod(m, struct idp *);
14621487Ssklower 	len = ntohs(idp->idp_len);
147*23839Ssklower 	if (len & 1) len++;		/* Preserve Garbage Byte */
14821487Ssklower 	if (ip->ip_len != len) {
14921487Ssklower 		if (len > ip->ip_len) {
15021487Ssklower 			nsipif.if_ierrors++;
15121487Ssklower 			if(nsip_badlen) m_freem(nsip_badlen);
15221487Ssklower 			nsip_badlen = m;
15321487Ssklower 			return;
15421487Ssklower 		}
15521487Ssklower 		m_adj(m, len - ip->ip_len);
15621487Ssklower 		/* ip->ip_len = len; */
15721487Ssklower 	}
15821487Ssklower 	/*
15921487Ssklower 	 * Deliver to NS
16021487Ssklower 	 */
16121487Ssklower 	s = splimp();
16221487Ssklower 	if (IF_QFULL(ifq)) {
16321487Ssklower 		IF_DROP(ifq);
16421487Ssklower 		m_freem(m0);
16521487Ssklower 		splx(s);
16621487Ssklower 		return (ENOBUFS);
16721487Ssklower 	}
16821487Ssklower 	IF_ENQUEUE(ifq, m0);
16921487Ssklower 	schednetisr(NETISR_NS);
17021487Ssklower 	splx(s);
17121487Ssklower 	return (0);
17221487Ssklower bad:
17321487Ssklower 	m_freem(m);
17421487Ssklower 	return (0);
17521487Ssklower }
17621487Ssklower 
17721487Ssklower nsipoutput(ifn, m0, dst)
17821487Ssklower 	struct ifnet_en *ifn;
17921487Ssklower 	struct mbuf *m0;
18021487Ssklower 	struct sockaddr *dst;
18121487Ssklower {
18221487Ssklower 
18321487Ssklower 	register struct mbuf *m = dtom(ifn);
18421487Ssklower 	register struct ip *ip;
18521487Ssklower 	register struct route *ro = &(ifn->ifen_route);
18621487Ssklower 	register int len = 0;
18721487Ssklower 	struct in_addr in_src, in_dst;
18821487Ssklower 	register struct idp *idp = mtod(m0, struct idp *);
18921487Ssklower 	int error;
19021487Ssklower 
19121487Ssklower 	if (m->m_len != sizeof(struct ifnet_en)) {
19221487Ssklower 		printf("nsipoutput: bad dst ifp %x\n", ifn);
19321487Ssklower 		goto bad;
19421487Ssklower 	}
19521487Ssklower 	ifn->ifen_ifnet.if_opackets++;
19621487Ssklower 	nsipif.if_opackets++;
19721487Ssklower 
19821487Ssklower 
19921487Ssklower 	/*
20021487Ssklower 	 * Calculate data length and make space
20121487Ssklower 	 * for IP header.
20221487Ssklower 	 */
20321487Ssklower 	len =  ntohs(idp->idp_len);
204*23839Ssklower 	if (len & 1) len++;		/* Preserve Garbage Byte */
20521487Ssklower 	m = m0;
20621487Ssklower 	if(m->m_off < MMINOFF + sizeof (struct ip)) {
20721487Ssklower 		m = m_get(M_DONTWAIT, MT_HEADER);
20821487Ssklower 		if (m == 0) {
20921487Ssklower 			m_freem(m0);
21021487Ssklower 			return (ENOBUFS);
21121487Ssklower 		}
21221487Ssklower 		m->m_off = MMAXOFF - sizeof (struct ip);
21321487Ssklower 		m->m_len = sizeof (struct ip);
21421487Ssklower 		m->m_next = m0;
21521487Ssklower 	} else {
21621487Ssklower 		m->m_off -= sizeof (struct ip);
21721487Ssklower 		m->m_len += sizeof (struct ip);
21821487Ssklower 	}
21921487Ssklower 	/*
22021487Ssklower 	 * Fill in IP header.
22121487Ssklower 	 */
22221487Ssklower 	ip = mtod(m, struct ip *);
22321487Ssklower 	*(long *)ip = 0;
22421487Ssklower 	ip->ip_p = IPPROTO_PUP;
22521487Ssklower 	ip->ip_src = ifn->ifen_src;
22621487Ssklower 	ip->ip_dst = ifn->ifen_dst;
22721487Ssklower 	ip->ip_len = (u_short)len + sizeof (struct ip);
22821487Ssklower 	ip->ip_ttl = MAXTTL;
22921487Ssklower 
23021487Ssklower 	/*
23121487Ssklower 	 * Output final datagram.
23221487Ssklower 	 */
23321487Ssklower 	error =  (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST));
23421487Ssklower 	if (error) {
23521487Ssklower 		ifn->ifen_ifnet.if_oerrors++;
23621487Ssklower 		ifn->ifen_ifnet.if_ierrors = error;
23721487Ssklower 	}
23821487Ssklower 	return (error);
23921487Ssklower bad:
24021487Ssklower 	m_freem(m0);
24121487Ssklower 	return(ENETUNREACH);
24221487Ssklower }
24321487Ssklower 
24421487Ssklower struct ifreq ifr = {"nsip0"};
24521487Ssklower 
24621487Ssklower nsip_route(m)
24721487Ssklower 	register struct mbuf *m;
24821487Ssklower {
24921487Ssklower 	register struct nsip_req *rq = mtod(m, struct nsip_req *);
25021487Ssklower 	struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns;
25121487Ssklower 	struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip;
25221487Ssklower 	int flags = rq->rq_flags;
25321487Ssklower 	struct ifnet *ifp;
25421487Ssklower 	struct route ro;
25521487Ssklower 	struct ifnet_en *ifn;
25621487Ssklower 	int error;
25721487Ssklower 	struct sockaddr_in *dst;
25821487Ssklower 	struct sockaddr_in *src;
25921487Ssklower 	/*
26021487Ssklower 	 * First, determine if we can get to the destination
26121487Ssklower 	 */
26221487Ssklower 	bzero((caddr_t)&ro, sizeof (ro));
26321487Ssklower 	ro.ro_dst = *(struct sockaddr *)ip_dst;
26421487Ssklower 	dst = (struct sockaddr_in *)& ro.ro_dst;
26521487Ssklower 	rtalloc(&ro);
26621487Ssklower 	if (ro.ro_rt == 0 || (ifp = ro.ro_rt->rt_ifp) == 0) {
26721487Ssklower 		return (ENETUNREACH);
26821487Ssklower 	}
26921487Ssklower 	/*
27021487Ssklower 	 * And see how he's going to get back to us:
27121487Ssklower 	 */
27221487Ssklower 	{
27321487Ssklower 		register struct in_ifaddr *ia;
27421487Ssklower 		struct ifnet *ifp = ro.ro_rt->rt_ifp;
27521487Ssklower 
27621487Ssklower 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
27721487Ssklower 			if (ia->ia_ifp == ifp)
27821487Ssklower 				break;
27921487Ssklower 		if (ia == 0)
28021487Ssklower 			ia = in_ifaddr;
28121487Ssklower 		if (ia == 0) {
28221487Ssklower 			return (EADDRNOTAVAIL);
28321487Ssklower 		}
28421487Ssklower 		src = (struct sockaddr_in *)&ia->ia_addr;
28521487Ssklower 	}
28621487Ssklower 	/*
28721487Ssklower 	 * Is there space?
28821487Ssklower 	 */
28921487Ssklower 	m = nsipattach();
29021487Ssklower 	if (m==NULL) {return (ENOBUFS);}
29121487Ssklower 	ifn = mtod(m, struct ifnet_en *);
29221487Ssklower 
29321487Ssklower 	ro.ro_rt->rt_use++;
29421487Ssklower 	ifn->ifen_route = ro;
29521487Ssklower 	ifn->ifen_dst =  ip_dst->sin_addr;
29621487Ssklower 	ifn->ifen_src = src->sin_addr;
29721487Ssklower 
29821487Ssklower 	/*
29921487Ssklower 	 * now configure this as a point to point link
30021487Ssklower 	 */
30121487Ssklower 	ifr.ifr_name[4] = '0' + nsipif.if_unit - 1;
30221487Ssklower 	ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst;
30321487Ssklower 	return(ns_control((struct socket *)0, SIOCSIFADDR, (caddr_t)&ifr,
30421487Ssklower 			(struct ifnet *)ifn));
30521487Ssklower }
30621487Ssklower #endif
307