xref: /csrg-svn/sys/netns/ns_ip.c (revision 34856)
123210Smckusick /*
233371Ssklower  * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California.
333371Ssklower  * All rights reserved.
423210Smckusick  *
533371Ssklower  * Redistribution and use in source and binary forms are permitted
6*34856Sbostic  * provided that the above copyright notice and this paragraph are
7*34856Sbostic  * duplicated in all such forms and that any documentation,
8*34856Sbostic  * advertising materials, and other materials related to such
9*34856Sbostic  * distribution and use acknowledge that the software was developed
10*34856Sbostic  * by the University of California, Berkeley.  The name of the
11*34856Sbostic  * University may not be used to endorse or promote products derived
12*34856Sbostic  * from this software without specific prior written permission.
13*34856Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*34856Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*34856Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633371Ssklower  *
17*34856Sbostic  *	@(#)ns_ip.c	7.3 (Berkeley) 06/29/88
1823210Smckusick  */
1921487Ssklower 
2021487Ssklower /*
2121487Ssklower  * Software interface driver for encapsulating ns in ip.
2221487Ssklower  */
2321487Ssklower 
2421487Ssklower #ifdef NSIP
2521487Ssklower #include "param.h"
2621487Ssklower #include "systm.h"
2721487Ssklower #include "mbuf.h"
2821487Ssklower #include "socket.h"
2924226Ssklower #include "socketvar.h"
3021487Ssklower #include "errno.h"
3121487Ssklower #include "ioctl.h"
3225055Ssklower #include "protosw.h"
3321487Ssklower 
3421487Ssklower #include "../net/if.h"
3521487Ssklower #include "../net/netisr.h"
3621487Ssklower #include "../net/route.h"
3721487Ssklower 
3821487Ssklower #include "../netinet/in.h"
3921487Ssklower #include "../netinet/in_systm.h"
4021487Ssklower #include "../netinet/in_var.h"
4121487Ssklower #include "../netinet/ip.h"
4221487Ssklower #include "../netinet/ip_var.h"
4321487Ssklower 
4421487Ssklower #ifdef vax
4521487Ssklower #include "../vax/mtpr.h"
4621487Ssklower #endif
4721487Ssklower 
4821487Ssklower #include "../netns/ns.h"
4921487Ssklower #include "../netns/ns_if.h"
5021487Ssklower #include "../netns/idp.h"
5121487Ssklower 
5221487Ssklower struct ifnet_en {
5321487Ssklower 	struct ifnet ifen_ifnet;
5421487Ssklower 	struct route ifen_route;
5521487Ssklower 	struct in_addr ifen_src;
5621487Ssklower 	struct in_addr ifen_dst;
5721487Ssklower };
5821487Ssklower 
5921487Ssklower int	nsipoutput(), nsipioctl();
6021487Ssklower #define LOMTU	(1024+512);
6121487Ssklower 
6221487Ssklower struct ifnet nsipif;
6321487Ssklower struct mbuf *nsip_list;		/* list of all hosts and gateways or
6421487Ssklower 					broadcast addrs */
6521487Ssklower 
6621487Ssklower struct mbuf *
6721487Ssklower nsipattach()
6821487Ssklower {
6921487Ssklower 	register struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
7021487Ssklower 	register struct ifnet *ifp;
7121487Ssklower 
7225454Ssklower 	if (m == NULL) return (NULL);
7321487Ssklower 	m->m_off = MMINOFF;
7421487Ssklower 	m->m_len = sizeof(struct ifnet_en);
7521487Ssklower 	m->m_next = nsip_list;
7621487Ssklower 	nsip_list = m;
7721487Ssklower 	ifp = mtod(m, struct ifnet *);
7821487Ssklower 
7921487Ssklower 	ifp->if_name = "nsip";
8021487Ssklower 	ifp->if_mtu = LOMTU;
8121487Ssklower 	ifp->if_ioctl = nsipioctl;
8221487Ssklower 	ifp->if_output = nsipoutput;
8321487Ssklower 	ifp->if_flags = IFF_POINTOPOINT;
8421487Ssklower 	ifp->if_unit = nsipif.if_unit++;
8521487Ssklower 	if_attach(ifp);
8625454Ssklower 	return (dtom(ifp));
8721487Ssklower }
8821487Ssklower 
8921487Ssklower 
9021487Ssklower /*
9121487Ssklower  * Process an ioctl request.
9221487Ssklower  */
9321487Ssklower /* ARGSUSED */
9421487Ssklower nsipioctl(ifp, cmd, data)
9521487Ssklower 	register struct ifnet *ifp;
9621487Ssklower 	int cmd;
9721487Ssklower 	caddr_t data;
9821487Ssklower {
9921487Ssklower 	int error = 0;
10025055Ssklower 	struct ifreq *ifr;
10121487Ssklower 
10221487Ssklower 	switch (cmd) {
10321487Ssklower 
10421487Ssklower 	case SIOCSIFADDR:
10521487Ssklower 		ifp->if_flags |= IFF_UP;
10625454Ssklower 		/* fall into: */
10725454Ssklower 
10825454Ssklower 	case SIOCSIFDSTADDR:
10921487Ssklower 		/*
11021487Ssklower 		 * Everything else is done at a higher level.
11121487Ssklower 		 */
11221487Ssklower 		break;
11321487Ssklower 
11425055Ssklower 	case SIOCSIFFLAGS:
11525055Ssklower 		ifr = (struct ifreq *)data;
11625055Ssklower 		if ((ifr->ifr_flags & IFF_UP) == 0)
11725055Ssklower 			error = nsip_free(ifp);
11825055Ssklower 
11925055Ssklower 
12021487Ssklower 	default:
12121487Ssklower 		error = EINVAL;
12221487Ssklower 	}
12321487Ssklower 	return (error);
12421487Ssklower }
12521487Ssklower 
12621487Ssklower struct mbuf *nsip_badlen;
12721487Ssklower struct mbuf *nsip_lastin;
12821487Ssklower int nsip_hold_input;
12921487Ssklower 
13024562Skarels idpip_input(m, ifp)
13124562Skarels 	register struct mbuf *m;
13224562Skarels 	struct ifnet *ifp;
13321487Ssklower {
13421487Ssklower 	register struct ip *ip;
13521487Ssklower 	register struct idp *idp;
13621487Ssklower 	register struct ifqueue *ifq = &nsintrq;
13721487Ssklower 	int len, s;
13821487Ssklower 
13925454Ssklower 	if (nsip_hold_input) {
14025454Ssklower 		if (nsip_lastin) {
14124226Ssklower 			m_freem(nsip_lastin);
14221487Ssklower 		}
14324562Skarels 		nsip_lastin = m_copy(m, 0, (int)M_COPYALL);
14421487Ssklower 	}
14521487Ssklower 	/*
14621487Ssklower 	 * Get IP and IDP header together in first mbuf.
14721487Ssklower 	 */
14821487Ssklower 	nsipif.if_ipackets++;
14921487Ssklower 	s = sizeof (struct ip) + sizeof (struct idp);
15021487Ssklower 	if ((m->m_off > MMAXOFF || m->m_len < s) &&
15125454Ssklower 	    (m = m_pullup(m, s)) == 0) {
15221487Ssklower 		nsipif.if_ierrors++;
15321487Ssklower 		return;
15421487Ssklower 	}
15521487Ssklower 	ip = mtod(m, struct ip *);
15624827Skarels 	if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
15724827Skarels 		ip_stripoptions(ip, (struct mbuf *)0);
15824827Skarels 		if (m->m_len < s) {
15925454Ssklower 			if ((m = m_pullup(m, s)) == 0) {
16024827Skarels 				nsipif.if_ierrors++;
16124827Skarels 				return;
16224827Skarels 			}
16324827Skarels 			ip = mtod(m, struct ip *);
16424827Skarels 		}
16524827Skarels 	}
16621487Ssklower 
16721487Ssklower 	/*
16821487Ssklower 	 * Make mbuf data length reflect IDP length.
16921487Ssklower 	 * If not enough data to reflect IDP length, drop.
17021487Ssklower 	 */
17121487Ssklower 	m->m_off += sizeof (struct ip);
17221487Ssklower 	m->m_len -= sizeof (struct ip);
17321487Ssklower 	idp = mtod(m, struct idp *);
17421487Ssklower 	len = ntohs(idp->idp_len);
17523839Ssklower 	if (len & 1) len++;		/* Preserve Garbage Byte */
17621487Ssklower 	if (ip->ip_len != len) {
17721487Ssklower 		if (len > ip->ip_len) {
17821487Ssklower 			nsipif.if_ierrors++;
17925454Ssklower 			if (nsip_badlen) m_freem(nsip_badlen);
18021487Ssklower 			nsip_badlen = m;
18121487Ssklower 			return;
18221487Ssklower 		}
18324043Ssklower 		/* Any extra will be trimmed off by the NS routines */
18421487Ssklower 	}
18524562Skarels 
18621487Ssklower 	/*
18724562Skarels 	 * Place interface pointer before the data
18824562Skarels 	 * for the receiving protocol.
18924562Skarels 	 */
19024562Skarels 	if (m->m_off >= MMINOFF + sizeof(struct ifnet *)) {
19124562Skarels 		m->m_off -= sizeof(struct ifnet *);
19224562Skarels 		m->m_len += sizeof(struct ifnet *);
19324562Skarels 	} else {
19424562Skarels 		struct mbuf *n;
19524562Skarels 
19624562Skarels 		n = m_get(M_DONTWAIT, MT_HEADER);
19724562Skarels 		if (n == (struct mbuf *)0)
19824562Skarels 			goto bad;
19924562Skarels 		n->m_off = MMINOFF;
20024562Skarels 		n->m_len = sizeof(struct ifnet *);
20124562Skarels 		n->m_next = m;
20224562Skarels 		m = n;
20324562Skarels 	}
20424562Skarels 	*(mtod(m, struct ifnet **)) = ifp;
20524562Skarels 
20624562Skarels 	/*
20721487Ssklower 	 * Deliver to NS
20821487Ssklower 	 */
20921487Ssklower 	s = splimp();
21021487Ssklower 	if (IF_QFULL(ifq)) {
21121487Ssklower 		IF_DROP(ifq);
21224562Skarels bad:
21324562Skarels 		m_freem(m);
21421487Ssklower 		splx(s);
21524226Ssklower 		return;
21621487Ssklower 	}
21724562Skarels 	IF_ENQUEUE(ifq, m);
21821487Ssklower 	schednetisr(NETISR_NS);
21921487Ssklower 	splx(s);
22024226Ssklower 	return;
22121487Ssklower }
22221487Ssklower 
22324226Ssklower /* ARGSUSED */
22421487Ssklower nsipoutput(ifn, m0, dst)
22521487Ssklower 	struct ifnet_en *ifn;
22621487Ssklower 	struct mbuf *m0;
22721487Ssklower 	struct sockaddr *dst;
22821487Ssklower {
22921487Ssklower 
23021487Ssklower 	register struct mbuf *m = dtom(ifn);
23121487Ssklower 	register struct ip *ip;
23221487Ssklower 	register struct route *ro = &(ifn->ifen_route);
23321487Ssklower 	register int len = 0;
23421487Ssklower 	register struct idp *idp = mtod(m0, struct idp *);
23521487Ssklower 	int error;
23621487Ssklower 
23721487Ssklower 	if (m->m_len != sizeof(struct ifnet_en)) {
23821487Ssklower 		printf("nsipoutput: bad dst ifp %x\n", ifn);
23921487Ssklower 		goto bad;
24021487Ssklower 	}
24121487Ssklower 	ifn->ifen_ifnet.if_opackets++;
24221487Ssklower 	nsipif.if_opackets++;
24321487Ssklower 
24421487Ssklower 
24521487Ssklower 	/*
24621487Ssklower 	 * Calculate data length and make space
24721487Ssklower 	 * for IP header.
24821487Ssklower 	 */
24921487Ssklower 	len =  ntohs(idp->idp_len);
25023839Ssklower 	if (len & 1) len++;		/* Preserve Garbage Byte */
25121487Ssklower 	m = m0;
25225454Ssklower 	if (m->m_off < MMINOFF + sizeof (struct ip)) {
25321487Ssklower 		m = m_get(M_DONTWAIT, MT_HEADER);
25421487Ssklower 		if (m == 0) {
25521487Ssklower 			m_freem(m0);
25621487Ssklower 			return (ENOBUFS);
25721487Ssklower 		}
25821487Ssklower 		m->m_off = MMAXOFF - sizeof (struct ip);
25921487Ssklower 		m->m_len = sizeof (struct ip);
26021487Ssklower 		m->m_next = m0;
26121487Ssklower 	} else {
26221487Ssklower 		m->m_off -= sizeof (struct ip);
26321487Ssklower 		m->m_len += sizeof (struct ip);
26421487Ssklower 	}
26521487Ssklower 	/*
26621487Ssklower 	 * Fill in IP header.
26721487Ssklower 	 */
26821487Ssklower 	ip = mtod(m, struct ip *);
26921487Ssklower 	*(long *)ip = 0;
27024043Ssklower 	ip->ip_p = IPPROTO_IDP;
27121487Ssklower 	ip->ip_src = ifn->ifen_src;
27221487Ssklower 	ip->ip_dst = ifn->ifen_dst;
27321487Ssklower 	ip->ip_len = (u_short)len + sizeof (struct ip);
27421487Ssklower 	ip->ip_ttl = MAXTTL;
27521487Ssklower 
27621487Ssklower 	/*
27721487Ssklower 	 * Output final datagram.
27821487Ssklower 	 */
27921487Ssklower 	error =  (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST));
28021487Ssklower 	if (error) {
28121487Ssklower 		ifn->ifen_ifnet.if_oerrors++;
28221487Ssklower 		ifn->ifen_ifnet.if_ierrors = error;
28321487Ssklower 	}
28421487Ssklower 	return (error);
28521487Ssklower bad:
28621487Ssklower 	m_freem(m0);
28725454Ssklower 	return (ENETUNREACH);
28821487Ssklower }
28921487Ssklower 
29021487Ssklower struct ifreq ifr = {"nsip0"};
29121487Ssklower 
29221487Ssklower nsip_route(m)
29321487Ssklower 	register struct mbuf *m;
29421487Ssklower {
29521487Ssklower 	register struct nsip_req *rq = mtod(m, struct nsip_req *);
29621487Ssklower 	struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns;
29721487Ssklower 	struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip;
29821487Ssklower 	struct route ro;
29921487Ssklower 	struct ifnet_en *ifn;
30021487Ssklower 	struct sockaddr_in *src;
30125454Ssklower 
30221487Ssklower 	/*
30325454Ssklower 	 * First, make sure we already have an ns address:
30421487Ssklower 	 */
30525454Ssklower 	if (ns_hosteqnh(ns_thishost, ns_zerohost))
30625454Ssklower 		return (EADDRNOTAVAIL);
30725454Ssklower 	/*
30825454Ssklower 	 * Now, determine if we can get to the destination
30925454Ssklower 	 */
31021487Ssklower 	bzero((caddr_t)&ro, sizeof (ro));
31121487Ssklower 	ro.ro_dst = *(struct sockaddr *)ip_dst;
31221487Ssklower 	rtalloc(&ro);
31324226Ssklower 	if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
31421487Ssklower 		return (ENETUNREACH);
31521487Ssklower 	}
31625454Ssklower 
31721487Ssklower 	/*
31821487Ssklower 	 * And see how he's going to get back to us:
31925454Ssklower 	 * i.e., what return ip address do we use?
32021487Ssklower 	 */
32121487Ssklower 	{
32221487Ssklower 		register struct in_ifaddr *ia;
32321487Ssklower 		struct ifnet *ifp = ro.ro_rt->rt_ifp;
32421487Ssklower 
32521487Ssklower 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
32621487Ssklower 			if (ia->ia_ifp == ifp)
32721487Ssklower 				break;
32821487Ssklower 		if (ia == 0)
32921487Ssklower 			ia = in_ifaddr;
33021487Ssklower 		if (ia == 0) {
33125454Ssklower 			RTFREE(ro.ro_rt);
33221487Ssklower 			return (EADDRNOTAVAIL);
33321487Ssklower 		}
33421487Ssklower 		src = (struct sockaddr_in *)&ia->ia_addr;
33521487Ssklower 	}
33625454Ssklower 
33721487Ssklower 	/*
33825055Ssklower 	 * Is there a free (pseudo-)interface or space?
33921487Ssklower 	 */
34025055Ssklower 	for (m = nsip_list; m; m = m->m_next) {
34125055Ssklower 		struct ifnet *ifp = mtod(m, struct ifnet *);
34225055Ssklower 		if ((ifp->if_flags & IFF_UP) == 0)
34325055Ssklower 			break;
34425055Ssklower 	}
34525055Ssklower 	if (m == (struct mbuf *) 0)
34625055Ssklower 		m = nsipattach();
34725454Ssklower 	if (m == NULL) {
34825454Ssklower 		RTFREE(ro.ro_rt);
34925454Ssklower 		return (ENOBUFS);
35025454Ssklower 	}
35121487Ssklower 	ifn = mtod(m, struct ifnet_en *);
35221487Ssklower 
35321487Ssklower 	ifn->ifen_route = ro;
35421487Ssklower 	ifn->ifen_dst =  ip_dst->sin_addr;
35521487Ssklower 	ifn->ifen_src = src->sin_addr;
35621487Ssklower 
35721487Ssklower 	/*
35821487Ssklower 	 * now configure this as a point to point link
35921487Ssklower 	 */
36021487Ssklower 	ifr.ifr_name[4] = '0' + nsipif.if_unit - 1;
36121487Ssklower 	ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst;
36225454Ssklower 	(void)ns_control((struct socket *)0, (int)SIOCSIFDSTADDR, (caddr_t)&ifr,
36325454Ssklower 			(struct ifnet *)ifn);
36425454Ssklower 	satons_addr(ifr.ifr_addr).x_host = ns_thishost;
36525454Ssklower 	return (ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr,
36621487Ssklower 			(struct ifnet *)ifn));
36721487Ssklower }
36825055Ssklower 
36925055Ssklower nsip_free(ifp)
37025055Ssklower struct ifnet *ifp;
37125055Ssklower {
37225055Ssklower 	register struct ifnet_en *ifn = (struct ifnet_en *)ifp;
37325055Ssklower 	struct route *ro = & ifn->ifen_route;
37425055Ssklower 
37525055Ssklower 	if (ro->ro_rt) {
37625055Ssklower 		RTFREE(ro->ro_rt);
37725055Ssklower 		ro->ro_rt = 0;
37825055Ssklower 	}
37925055Ssklower 	ifp->if_flags &= ~IFF_UP;
38025055Ssklower 	return (0);
38125055Ssklower }
38225055Ssklower 
38325055Ssklower nsip_ctlinput(cmd, sa)
38425055Ssklower 	int cmd;
38525055Ssklower 	struct sockaddr *sa;
38625055Ssklower {
38725055Ssklower 	extern u_char inetctlerrmap[];
38825055Ssklower 	struct sockaddr_in *sin;
38925055Ssklower 	int in_rtchange();
39025055Ssklower 
39125454Ssklower 	if ((unsigned)cmd >= PRC_NCMDS)
39225055Ssklower 		return;
39325055Ssklower 	if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
39425055Ssklower 		return;
39525055Ssklower 	sin = (struct sockaddr_in *)sa;
39625055Ssklower 	if (sin->sin_addr.s_addr == INADDR_ANY)
39725055Ssklower 		return;
39825055Ssklower 
39925055Ssklower 	switch (cmd) {
40025055Ssklower 
40125055Ssklower 	case PRC_ROUTEDEAD:
40225055Ssklower 	case PRC_REDIRECT_NET:
40325055Ssklower 	case PRC_REDIRECT_HOST:
40425055Ssklower 	case PRC_REDIRECT_TOSNET:
40525055Ssklower 	case PRC_REDIRECT_TOSHOST:
40625055Ssklower 		nsip_rtchange(&sin->sin_addr);
40725055Ssklower 		break;
40825055Ssklower 	}
40925055Ssklower }
41025055Ssklower 
41125055Ssklower nsip_rtchange(dst)
41225055Ssklower 	register struct in_addr *dst;
41325055Ssklower {
41425055Ssklower 	register struct mbuf *m;
41525055Ssklower 	register struct ifnet_en *ifn;
41625055Ssklower 
41725211Smckusick 	for (m = nsip_list; m; m = m->m_next) {
41825211Smckusick 		ifn = mtod(m, struct ifnet_en *);
41925055Ssklower 		if (ifn->ifen_dst.s_addr == dst->s_addr &&
42025055Ssklower 			ifn->ifen_route.ro_rt) {
42125055Ssklower 				RTFREE(ifn->ifen_route.ro_rt);
42225055Ssklower 				ifn->ifen_route.ro_rt = 0;
42325055Ssklower 		}
42425211Smckusick 	}
42525055Ssklower }
42621487Ssklower #endif
427