xref: /csrg-svn/sys/netns/ns_ip.c (revision 68167)
123210Smckusick /*
263231Sbostic  * Copyright (c) 1984, 1985, 1986, 1987, 1993
363231Sbostic  *	The Regents of the University of California.  All rights reserved.
423210Smckusick  *
544505Sbostic  * %sccs.include.redist.c%
633371Ssklower  *
7*68167Scgd  *	@(#)ns_ip.c	8.2 (Berkeley) 01/09/95
823210Smckusick  */
921487Ssklower 
1021487Ssklower /*
1121487Ssklower  * Software interface driver for encapsulating ns in ip.
1221487Ssklower  */
1321487Ssklower 
1421487Ssklower #ifdef NSIP
1556534Sbostic #include <sys/param.h>
1656534Sbostic #include <sys/systm.h>
1756534Sbostic #include <sys/malloc.h>
1856534Sbostic #include <sys/mbuf.h>
1956534Sbostic #include <sys/socket.h>
2056534Sbostic #include <sys/socketvar.h>
2156534Sbostic #include <sys/errno.h>
2256534Sbostic #include <sys/ioctl.h>
2356534Sbostic #include <sys/protosw.h>
2421487Ssklower 
2556534Sbostic #include <net/if.h>
2656534Sbostic #include <net/netisr.h>
2756534Sbostic #include <net/route.h>
2821487Ssklower 
2956534Sbostic #include <netinet/in.h>
3056534Sbostic #include <netinet/in_systm.h>
3156534Sbostic #include <netinet/in_var.h>
3256534Sbostic #include <netinet/ip.h>
3356534Sbostic #include <netinet/ip_var.h>
3421487Ssklower 
3556534Sbostic #include <machine/mtpr.h>
3621487Ssklower 
3756534Sbostic #include <netns/ns.h>
3856534Sbostic #include <netns/ns_if.h>
3956534Sbostic #include <netns/idp.h>
4021487Ssklower 
4121487Ssklower struct ifnet_en {
4221487Ssklower 	struct ifnet ifen_ifnet;
4321487Ssklower 	struct route ifen_route;
4421487Ssklower 	struct in_addr ifen_src;
4521487Ssklower 	struct in_addr ifen_dst;
4637473Ssklower 	struct ifnet_en *ifen_next;
4721487Ssklower };
4821487Ssklower 
4937473Ssklower int	nsipoutput(), nsipioctl(), nsipstart();
5021487Ssklower #define LOMTU	(1024+512);
5121487Ssklower 
5221487Ssklower struct ifnet nsipif;
5337473Ssklower struct ifnet_en *nsip_list;		/* list of all hosts and gateways or
5421487Ssklower 					broadcast addrs */
5521487Ssklower 
5637473Ssklower struct ifnet_en *
nsipattach()5721487Ssklower nsipattach()
5821487Ssklower {
5937473Ssklower 	register struct ifnet_en *m;
6021487Ssklower 	register struct ifnet *ifp;
6121487Ssklower 
6237473Ssklower 	if (nsipif.if_mtu == 0) {
6337473Ssklower 		ifp = &nsipif;
6437473Ssklower 		ifp->if_name = "nsip";
6537473Ssklower 		ifp->if_mtu = LOMTU;
6637473Ssklower 		ifp->if_ioctl = nsipioctl;
6737473Ssklower 		ifp->if_output = nsipoutput;
6837473Ssklower 		ifp->if_start = nsipstart;
6937473Ssklower 		ifp->if_flags = IFF_POINTOPOINT;
7037473Ssklower 	}
7137473Ssklower 
7237473Ssklower 	MALLOC((m), struct ifnet_en *, sizeof(*m), M_PCB, M_NOWAIT);
7325454Ssklower 	if (m == NULL) return (NULL);
7437473Ssklower 	m->ifen_next = nsip_list;
7521487Ssklower 	nsip_list = m;
7637473Ssklower 	ifp = &m->ifen_ifnet;
7721487Ssklower 
7821487Ssklower 	ifp->if_name = "nsip";
7921487Ssklower 	ifp->if_mtu = LOMTU;
8021487Ssklower 	ifp->if_ioctl = nsipioctl;
8121487Ssklower 	ifp->if_output = nsipoutput;
8237473Ssklower 	ifp->if_start = nsipstart;
8321487Ssklower 	ifp->if_flags = IFF_POINTOPOINT;
8421487Ssklower 	ifp->if_unit = nsipif.if_unit++;
8521487Ssklower 	if_attach(ifp);
8637473Ssklower 
8737473Ssklower 	return (m);
8821487Ssklower }
8921487Ssklower 
9021487Ssklower 
9121487Ssklower /*
9221487Ssklower  * Process an ioctl request.
9321487Ssklower  */
9421487Ssklower /* ARGSUSED */
nsipioctl(ifp,cmd,data)9521487Ssklower nsipioctl(ifp, cmd, data)
9621487Ssklower 	register struct ifnet *ifp;
9721487Ssklower 	int cmd;
9821487Ssklower 	caddr_t data;
9921487Ssklower {
10021487Ssklower 	int error = 0;
10125055Ssklower 	struct ifreq *ifr;
10221487Ssklower 
10321487Ssklower 	switch (cmd) {
10421487Ssklower 
10521487Ssklower 	case SIOCSIFADDR:
10621487Ssklower 		ifp->if_flags |= IFF_UP;
10725454Ssklower 		/* fall into: */
10825454Ssklower 
10925454Ssklower 	case SIOCSIFDSTADDR:
11021487Ssklower 		/*
11121487Ssklower 		 * Everything else is done at a higher level.
11221487Ssklower 		 */
11321487Ssklower 		break;
11421487Ssklower 
11525055Ssklower 	case SIOCSIFFLAGS:
11625055Ssklower 		ifr = (struct ifreq *)data;
11725055Ssklower 		if ((ifr->ifr_flags & IFF_UP) == 0)
11825055Ssklower 			error = nsip_free(ifp);
11925055Ssklower 
12025055Ssklower 
12121487Ssklower 	default:
12221487Ssklower 		error = EINVAL;
12321487Ssklower 	}
12421487Ssklower 	return (error);
12521487Ssklower }
12621487Ssklower 
12721487Ssklower struct mbuf *nsip_badlen;
12821487Ssklower struct mbuf *nsip_lastin;
12921487Ssklower int nsip_hold_input;
13021487Ssklower 
idpip_input(m,ifp)13124562Skarels idpip_input(m, ifp)
13224562Skarels 	register struct mbuf *m;
13324562Skarels 	struct ifnet *ifp;
13421487Ssklower {
13521487Ssklower 	register struct ip *ip;
13621487Ssklower 	register struct idp *idp;
13721487Ssklower 	register struct ifqueue *ifq = &nsintrq;
13821487Ssklower 	int len, s;
13921487Ssklower 
14025454Ssklower 	if (nsip_hold_input) {
14125454Ssklower 		if (nsip_lastin) {
14224226Ssklower 			m_freem(nsip_lastin);
14321487Ssklower 		}
14437473Ssklower 		nsip_lastin = m_copym(m, 0, (int)M_COPYALL, M_DONTWAIT);
14521487Ssklower 	}
14621487Ssklower 	/*
14721487Ssklower 	 * Get IP and IDP header together in first mbuf.
14821487Ssklower 	 */
14921487Ssklower 	nsipif.if_ipackets++;
15021487Ssklower 	s = sizeof (struct ip) + sizeof (struct idp);
15137473Ssklower 	if (((m->m_flags & M_EXT) || m->m_len < s) &&
15225454Ssklower 	    (m = m_pullup(m, s)) == 0) {
15321487Ssklower 		nsipif.if_ierrors++;
15421487Ssklower 		return;
15521487Ssklower 	}
15621487Ssklower 	ip = mtod(m, struct ip *);
15724827Skarels 	if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
15861653Ssklower 		ip_stripoptions(m, (struct mbuf *)0);
15924827Skarels 		if (m->m_len < s) {
16025454Ssklower 			if ((m = m_pullup(m, s)) == 0) {
16124827Skarels 				nsipif.if_ierrors++;
16224827Skarels 				return;
16324827Skarels 			}
16424827Skarels 			ip = mtod(m, struct ip *);
16524827Skarels 		}
16624827Skarels 	}
16721487Ssklower 
16821487Ssklower 	/*
16921487Ssklower 	 * Make mbuf data length reflect IDP length.
17021487Ssklower 	 * If not enough data to reflect IDP length, drop.
17121487Ssklower 	 */
17237473Ssklower 	m->m_data += sizeof (struct ip);
17321487Ssklower 	m->m_len -= sizeof (struct ip);
17437473Ssklower 	m->m_pkthdr.len -= sizeof (struct ip);
17521487Ssklower 	idp = mtod(m, struct idp *);
17621487Ssklower 	len = ntohs(idp->idp_len);
17723839Ssklower 	if (len & 1) len++;		/* Preserve Garbage Byte */
17821487Ssklower 	if (ip->ip_len != len) {
17921487Ssklower 		if (len > ip->ip_len) {
18021487Ssklower 			nsipif.if_ierrors++;
18125454Ssklower 			if (nsip_badlen) m_freem(nsip_badlen);
18221487Ssklower 			nsip_badlen = m;
18321487Ssklower 			return;
18421487Ssklower 		}
18524043Ssklower 		/* Any extra will be trimmed off by the NS routines */
18621487Ssklower 	}
18724562Skarels 
18821487Ssklower 	/*
18924562Skarels 	 * Place interface pointer before the data
19024562Skarels 	 * for the receiving protocol.
19124562Skarels 	 */
19237473Ssklower 	m->m_pkthdr.rcvif = ifp;
19324562Skarels 	/*
19421487Ssklower 	 * Deliver to NS
19521487Ssklower 	 */
19621487Ssklower 	s = splimp();
19721487Ssklower 	if (IF_QFULL(ifq)) {
19821487Ssklower 		IF_DROP(ifq);
19924562Skarels bad:
20024562Skarels 		m_freem(m);
20121487Ssklower 		splx(s);
20224226Ssklower 		return;
20321487Ssklower 	}
20424562Skarels 	IF_ENQUEUE(ifq, m);
20521487Ssklower 	schednetisr(NETISR_NS);
20621487Ssklower 	splx(s);
20724226Ssklower 	return;
20821487Ssklower }
20921487Ssklower 
21024226Ssklower /* ARGSUSED */
21137473Ssklower nsipoutput(ifn, m, dst)
21221487Ssklower 	struct ifnet_en *ifn;
21337473Ssklower 	register struct mbuf *m;
21421487Ssklower 	struct sockaddr *dst;
21521487Ssklower {
21621487Ssklower 
21721487Ssklower 	register struct ip *ip;
21821487Ssklower 	register struct route *ro = &(ifn->ifen_route);
21921487Ssklower 	register int len = 0;
22037473Ssklower 	register struct idp *idp = mtod(m, struct idp *);
22121487Ssklower 	int error;
22221487Ssklower 
22321487Ssklower 	ifn->ifen_ifnet.if_opackets++;
22421487Ssklower 	nsipif.if_opackets++;
22521487Ssklower 
22621487Ssklower 
22721487Ssklower 	/*
22821487Ssklower 	 * Calculate data length and make space
22921487Ssklower 	 * for IP header.
23021487Ssklower 	 */
23121487Ssklower 	len =  ntohs(idp->idp_len);
23223839Ssklower 	if (len & 1) len++;		/* Preserve Garbage Byte */
23337473Ssklower 	/* following clause not necessary on vax */
23437473Ssklower 	if (3 & (int)m->m_data) {
23537473Ssklower 		/* force longword alignment of ip hdr */
23637473Ssklower 		struct mbuf *m0 = m_gethdr(MT_HEADER, M_DONTWAIT);
23737473Ssklower 		if (m0 == 0) {
23837473Ssklower 			m_freem(m);
23921487Ssklower 			return (ENOBUFS);
24021487Ssklower 		}
24137473Ssklower 		MH_ALIGN(m0, sizeof (struct ip));
24237473Ssklower 		m0->m_flags = m->m_flags & M_COPYFLAGS;
24337473Ssklower 		m0->m_next = m;
24437473Ssklower 		m0->m_len = sizeof (struct ip);
24537473Ssklower 		m0->m_pkthdr.len = m0->m_len + m->m_len;
24637473Ssklower 		m->m_flags &= ~M_PKTHDR;
24721487Ssklower 	} else {
24837473Ssklower 		M_PREPEND(m, sizeof (struct ip), M_DONTWAIT);
24937473Ssklower 		if (m == 0)
25037473Ssklower 			return (ENOBUFS);
25121487Ssklower 	}
25221487Ssklower 	/*
25321487Ssklower 	 * Fill in IP header.
25421487Ssklower 	 */
25521487Ssklower 	ip = mtod(m, struct ip *);
25621487Ssklower 	*(long *)ip = 0;
25724043Ssklower 	ip->ip_p = IPPROTO_IDP;
25821487Ssklower 	ip->ip_src = ifn->ifen_src;
25921487Ssklower 	ip->ip_dst = ifn->ifen_dst;
26021487Ssklower 	ip->ip_len = (u_short)len + sizeof (struct ip);
26121487Ssklower 	ip->ip_ttl = MAXTTL;
26221487Ssklower 
26321487Ssklower 	/*
26421487Ssklower 	 * Output final datagram.
26521487Ssklower 	 */
26661653Ssklower 	error =  (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST, NULL));
26721487Ssklower 	if (error) {
26821487Ssklower 		ifn->ifen_ifnet.if_oerrors++;
26921487Ssklower 		ifn->ifen_ifnet.if_ierrors = error;
27021487Ssklower 	}
27121487Ssklower 	return (error);
27221487Ssklower bad:
27337473Ssklower 	m_freem(m);
27425454Ssklower 	return (ENETUNREACH);
27521487Ssklower }
27621487Ssklower 
27737473Ssklower nsipstart(ifp)
27837473Ssklower struct ifnet *ifp;
27937473Ssklower {
28037473Ssklower 	panic("nsip_start called\n");
28137473Ssklower }
28237473Ssklower 
28321487Ssklower struct ifreq ifr = {"nsip0"};
28421487Ssklower 
nsip_route(m)28521487Ssklower nsip_route(m)
28621487Ssklower 	register struct mbuf *m;
28721487Ssklower {
28821487Ssklower 	register struct nsip_req *rq = mtod(m, struct nsip_req *);
28921487Ssklower 	struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns;
29021487Ssklower 	struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip;
29121487Ssklower 	struct route ro;
29221487Ssklower 	struct ifnet_en *ifn;
29321487Ssklower 	struct sockaddr_in *src;
29425454Ssklower 
29521487Ssklower 	/*
29625454Ssklower 	 * First, make sure we already have an ns address:
29721487Ssklower 	 */
29825454Ssklower 	if (ns_hosteqnh(ns_thishost, ns_zerohost))
29925454Ssklower 		return (EADDRNOTAVAIL);
30025454Ssklower 	/*
30125454Ssklower 	 * Now, determine if we can get to the destination
30225454Ssklower 	 */
30321487Ssklower 	bzero((caddr_t)&ro, sizeof (ro));
30421487Ssklower 	ro.ro_dst = *(struct sockaddr *)ip_dst;
30521487Ssklower 	rtalloc(&ro);
30624226Ssklower 	if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
30721487Ssklower 		return (ENETUNREACH);
30821487Ssklower 	}
30925454Ssklower 
31021487Ssklower 	/*
31121487Ssklower 	 * And see how he's going to get back to us:
31225454Ssklower 	 * i.e., what return ip address do we use?
31321487Ssklower 	 */
31421487Ssklower 	{
31521487Ssklower 		register struct in_ifaddr *ia;
31621487Ssklower 		struct ifnet *ifp = ro.ro_rt->rt_ifp;
31721487Ssklower 
31821487Ssklower 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
31921487Ssklower 			if (ia->ia_ifp == ifp)
32021487Ssklower 				break;
32121487Ssklower 		if (ia == 0)
32221487Ssklower 			ia = in_ifaddr;
32321487Ssklower 		if (ia == 0) {
32425454Ssklower 			RTFREE(ro.ro_rt);
32521487Ssklower 			return (EADDRNOTAVAIL);
32621487Ssklower 		}
32721487Ssklower 		src = (struct sockaddr_in *)&ia->ia_addr;
32821487Ssklower 	}
32925454Ssklower 
33021487Ssklower 	/*
33125055Ssklower 	 * Is there a free (pseudo-)interface or space?
33221487Ssklower 	 */
33337473Ssklower 	for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) {
33437473Ssklower 		if ((ifn->ifen_ifnet.if_flags & IFF_UP) == 0)
33525055Ssklower 			break;
33625055Ssklower 	}
33737473Ssklower 	if (ifn == NULL)
33837473Ssklower 		ifn = nsipattach();
33937473Ssklower 	if (ifn == NULL) {
34025454Ssklower 		RTFREE(ro.ro_rt);
34125454Ssklower 		return (ENOBUFS);
34225454Ssklower 	}
34321487Ssklower 	ifn->ifen_route = ro;
34421487Ssklower 	ifn->ifen_dst =  ip_dst->sin_addr;
34521487Ssklower 	ifn->ifen_src = src->sin_addr;
34621487Ssklower 
34721487Ssklower 	/*
34821487Ssklower 	 * now configure this as a point to point link
34921487Ssklower 	 */
35021487Ssklower 	ifr.ifr_name[4] = '0' + nsipif.if_unit - 1;
35121487Ssklower 	ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst;
352*68167Scgd 	(void)ns_control((struct socket *)0, SIOCSIFDSTADDR, (caddr_t)&ifr,
35325454Ssklower 			(struct ifnet *)ifn);
35425454Ssklower 	satons_addr(ifr.ifr_addr).x_host = ns_thishost;
355*68167Scgd 	return (ns_control((struct socket *)0, SIOCSIFADDR, (caddr_t)&ifr,
35621487Ssklower 			(struct ifnet *)ifn));
35721487Ssklower }
35825055Ssklower 
35925055Ssklower nsip_free(ifp)
36025055Ssklower struct ifnet *ifp;
36125055Ssklower {
36225055Ssklower 	register struct ifnet_en *ifn = (struct ifnet_en *)ifp;
36325055Ssklower 	struct route *ro = & ifn->ifen_route;
36425055Ssklower 
36525055Ssklower 	if (ro->ro_rt) {
36625055Ssklower 		RTFREE(ro->ro_rt);
36725055Ssklower 		ro->ro_rt = 0;
36825055Ssklower 	}
36925055Ssklower 	ifp->if_flags &= ~IFF_UP;
37025055Ssklower 	return (0);
37125055Ssklower }
37225055Ssklower 
nsip_ctlinput(cmd,sa)37325055Ssklower nsip_ctlinput(cmd, sa)
37425055Ssklower 	int cmd;
37525055Ssklower 	struct sockaddr *sa;
37625055Ssklower {
37725055Ssklower 	extern u_char inetctlerrmap[];
37825055Ssklower 	struct sockaddr_in *sin;
37925055Ssklower 	int in_rtchange();
38025055Ssklower 
38125454Ssklower 	if ((unsigned)cmd >= PRC_NCMDS)
38225055Ssklower 		return;
38325055Ssklower 	if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
38425055Ssklower 		return;
38525055Ssklower 	sin = (struct sockaddr_in *)sa;
38625055Ssklower 	if (sin->sin_addr.s_addr == INADDR_ANY)
38725055Ssklower 		return;
38825055Ssklower 
38925055Ssklower 	switch (cmd) {
39025055Ssklower 
39125055Ssklower 	case PRC_ROUTEDEAD:
39225055Ssklower 	case PRC_REDIRECT_NET:
39325055Ssklower 	case PRC_REDIRECT_HOST:
39425055Ssklower 	case PRC_REDIRECT_TOSNET:
39525055Ssklower 	case PRC_REDIRECT_TOSHOST:
39625055Ssklower 		nsip_rtchange(&sin->sin_addr);
39725055Ssklower 		break;
39825055Ssklower 	}
39925055Ssklower }
40025055Ssklower 
nsip_rtchange(dst)40125055Ssklower nsip_rtchange(dst)
40225055Ssklower 	register struct in_addr *dst;
40325055Ssklower {
40425055Ssklower 	register struct ifnet_en *ifn;
40525055Ssklower 
40637473Ssklower 	for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) {
40725055Ssklower 		if (ifn->ifen_dst.s_addr == dst->s_addr &&
40825055Ssklower 			ifn->ifen_route.ro_rt) {
40925055Ssklower 				RTFREE(ifn->ifen_route.ro_rt);
41025055Ssklower 				ifn->ifen_route.ro_rt = 0;
41125055Ssklower 		}
41225211Smckusick 	}
41325055Ssklower }
41421487Ssklower #endif
415