xref: /original-bsd/sys/netns/ns_ip.c (revision fac0c393)
1 /*
2  * Copyright (c) 1984, 1985, 1986, 1987, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)ns_ip.c	8.2 (Berkeley) 01/09/95
8  */
9 
10 /*
11  * Software interface driver for encapsulating ns in ip.
12  */
13 
14 #ifdef NSIP
15 #include <sys/param.h>
16 #include <sys/systm.h>
17 #include <sys/malloc.h>
18 #include <sys/mbuf.h>
19 #include <sys/socket.h>
20 #include <sys/socketvar.h>
21 #include <sys/errno.h>
22 #include <sys/ioctl.h>
23 #include <sys/protosw.h>
24 
25 #include <net/if.h>
26 #include <net/netisr.h>
27 #include <net/route.h>
28 
29 #include <netinet/in.h>
30 #include <netinet/in_systm.h>
31 #include <netinet/in_var.h>
32 #include <netinet/ip.h>
33 #include <netinet/ip_var.h>
34 
35 #include <machine/mtpr.h>
36 
37 #include <netns/ns.h>
38 #include <netns/ns_if.h>
39 #include <netns/idp.h>
40 
41 struct ifnet_en {
42 	struct ifnet ifen_ifnet;
43 	struct route ifen_route;
44 	struct in_addr ifen_src;
45 	struct in_addr ifen_dst;
46 	struct ifnet_en *ifen_next;
47 };
48 
49 int	nsipoutput(), nsipioctl(), nsipstart();
50 #define LOMTU	(1024+512);
51 
52 struct ifnet nsipif;
53 struct ifnet_en *nsip_list;		/* list of all hosts and gateways or
54 					broadcast addrs */
55 
56 struct ifnet_en *
57 nsipattach()
58 {
59 	register struct ifnet_en *m;
60 	register struct ifnet *ifp;
61 
62 	if (nsipif.if_mtu == 0) {
63 		ifp = &nsipif;
64 		ifp->if_name = "nsip";
65 		ifp->if_mtu = LOMTU;
66 		ifp->if_ioctl = nsipioctl;
67 		ifp->if_output = nsipoutput;
68 		ifp->if_start = nsipstart;
69 		ifp->if_flags = IFF_POINTOPOINT;
70 	}
71 
72 	MALLOC((m), struct ifnet_en *, sizeof(*m), M_PCB, M_NOWAIT);
73 	if (m == NULL) return (NULL);
74 	m->ifen_next = nsip_list;
75 	nsip_list = m;
76 	ifp = &m->ifen_ifnet;
77 
78 	ifp->if_name = "nsip";
79 	ifp->if_mtu = LOMTU;
80 	ifp->if_ioctl = nsipioctl;
81 	ifp->if_output = nsipoutput;
82 	ifp->if_start = nsipstart;
83 	ifp->if_flags = IFF_POINTOPOINT;
84 	ifp->if_unit = nsipif.if_unit++;
85 	if_attach(ifp);
86 
87 	return (m);
88 }
89 
90 
91 /*
92  * Process an ioctl request.
93  */
94 /* ARGSUSED */
95 nsipioctl(ifp, cmd, data)
96 	register struct ifnet *ifp;
97 	int cmd;
98 	caddr_t data;
99 {
100 	int error = 0;
101 	struct ifreq *ifr;
102 
103 	switch (cmd) {
104 
105 	case SIOCSIFADDR:
106 		ifp->if_flags |= IFF_UP;
107 		/* fall into: */
108 
109 	case SIOCSIFDSTADDR:
110 		/*
111 		 * Everything else is done at a higher level.
112 		 */
113 		break;
114 
115 	case SIOCSIFFLAGS:
116 		ifr = (struct ifreq *)data;
117 		if ((ifr->ifr_flags & IFF_UP) == 0)
118 			error = nsip_free(ifp);
119 
120 
121 	default:
122 		error = EINVAL;
123 	}
124 	return (error);
125 }
126 
127 struct mbuf *nsip_badlen;
128 struct mbuf *nsip_lastin;
129 int nsip_hold_input;
130 
131 idpip_input(m, ifp)
132 	register struct mbuf *m;
133 	struct ifnet *ifp;
134 {
135 	register struct ip *ip;
136 	register struct idp *idp;
137 	register struct ifqueue *ifq = &nsintrq;
138 	int len, s;
139 
140 	if (nsip_hold_input) {
141 		if (nsip_lastin) {
142 			m_freem(nsip_lastin);
143 		}
144 		nsip_lastin = m_copym(m, 0, (int)M_COPYALL, M_DONTWAIT);
145 	}
146 	/*
147 	 * Get IP and IDP header together in first mbuf.
148 	 */
149 	nsipif.if_ipackets++;
150 	s = sizeof (struct ip) + sizeof (struct idp);
151 	if (((m->m_flags & M_EXT) || m->m_len < s) &&
152 	    (m = m_pullup(m, s)) == 0) {
153 		nsipif.if_ierrors++;
154 		return;
155 	}
156 	ip = mtod(m, struct ip *);
157 	if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
158 		ip_stripoptions(m, (struct mbuf *)0);
159 		if (m->m_len < s) {
160 			if ((m = m_pullup(m, s)) == 0) {
161 				nsipif.if_ierrors++;
162 				return;
163 			}
164 			ip = mtod(m, struct ip *);
165 		}
166 	}
167 
168 	/*
169 	 * Make mbuf data length reflect IDP length.
170 	 * If not enough data to reflect IDP length, drop.
171 	 */
172 	m->m_data += sizeof (struct ip);
173 	m->m_len -= sizeof (struct ip);
174 	m->m_pkthdr.len -= sizeof (struct ip);
175 	idp = mtod(m, struct idp *);
176 	len = ntohs(idp->idp_len);
177 	if (len & 1) len++;		/* Preserve Garbage Byte */
178 	if (ip->ip_len != len) {
179 		if (len > ip->ip_len) {
180 			nsipif.if_ierrors++;
181 			if (nsip_badlen) m_freem(nsip_badlen);
182 			nsip_badlen = m;
183 			return;
184 		}
185 		/* Any extra will be trimmed off by the NS routines */
186 	}
187 
188 	/*
189 	 * Place interface pointer before the data
190 	 * for the receiving protocol.
191 	 */
192 	m->m_pkthdr.rcvif = ifp;
193 	/*
194 	 * Deliver to NS
195 	 */
196 	s = splimp();
197 	if (IF_QFULL(ifq)) {
198 		IF_DROP(ifq);
199 bad:
200 		m_freem(m);
201 		splx(s);
202 		return;
203 	}
204 	IF_ENQUEUE(ifq, m);
205 	schednetisr(NETISR_NS);
206 	splx(s);
207 	return;
208 }
209 
210 /* ARGSUSED */
211 nsipoutput(ifn, m, dst)
212 	struct ifnet_en *ifn;
213 	register struct mbuf *m;
214 	struct sockaddr *dst;
215 {
216 
217 	register struct ip *ip;
218 	register struct route *ro = &(ifn->ifen_route);
219 	register int len = 0;
220 	register struct idp *idp = mtod(m, struct idp *);
221 	int error;
222 
223 	ifn->ifen_ifnet.if_opackets++;
224 	nsipif.if_opackets++;
225 
226 
227 	/*
228 	 * Calculate data length and make space
229 	 * for IP header.
230 	 */
231 	len =  ntohs(idp->idp_len);
232 	if (len & 1) len++;		/* Preserve Garbage Byte */
233 	/* following clause not necessary on vax */
234 	if (3 & (int)m->m_data) {
235 		/* force longword alignment of ip hdr */
236 		struct mbuf *m0 = m_gethdr(MT_HEADER, M_DONTWAIT);
237 		if (m0 == 0) {
238 			m_freem(m);
239 			return (ENOBUFS);
240 		}
241 		MH_ALIGN(m0, sizeof (struct ip));
242 		m0->m_flags = m->m_flags & M_COPYFLAGS;
243 		m0->m_next = m;
244 		m0->m_len = sizeof (struct ip);
245 		m0->m_pkthdr.len = m0->m_len + m->m_len;
246 		m->m_flags &= ~M_PKTHDR;
247 	} else {
248 		M_PREPEND(m, sizeof (struct ip), M_DONTWAIT);
249 		if (m == 0)
250 			return (ENOBUFS);
251 	}
252 	/*
253 	 * Fill in IP header.
254 	 */
255 	ip = mtod(m, struct ip *);
256 	*(long *)ip = 0;
257 	ip->ip_p = IPPROTO_IDP;
258 	ip->ip_src = ifn->ifen_src;
259 	ip->ip_dst = ifn->ifen_dst;
260 	ip->ip_len = (u_short)len + sizeof (struct ip);
261 	ip->ip_ttl = MAXTTL;
262 
263 	/*
264 	 * Output final datagram.
265 	 */
266 	error =  (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST, NULL));
267 	if (error) {
268 		ifn->ifen_ifnet.if_oerrors++;
269 		ifn->ifen_ifnet.if_ierrors = error;
270 	}
271 	return (error);
272 bad:
273 	m_freem(m);
274 	return (ENETUNREACH);
275 }
276 
277 nsipstart(ifp)
278 struct ifnet *ifp;
279 {
280 	panic("nsip_start called\n");
281 }
282 
283 struct ifreq ifr = {"nsip0"};
284 
285 nsip_route(m)
286 	register struct mbuf *m;
287 {
288 	register struct nsip_req *rq = mtod(m, struct nsip_req *);
289 	struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns;
290 	struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip;
291 	struct route ro;
292 	struct ifnet_en *ifn;
293 	struct sockaddr_in *src;
294 
295 	/*
296 	 * First, make sure we already have an ns address:
297 	 */
298 	if (ns_hosteqnh(ns_thishost, ns_zerohost))
299 		return (EADDRNOTAVAIL);
300 	/*
301 	 * Now, determine if we can get to the destination
302 	 */
303 	bzero((caddr_t)&ro, sizeof (ro));
304 	ro.ro_dst = *(struct sockaddr *)ip_dst;
305 	rtalloc(&ro);
306 	if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
307 		return (ENETUNREACH);
308 	}
309 
310 	/*
311 	 * And see how he's going to get back to us:
312 	 * i.e., what return ip address do we use?
313 	 */
314 	{
315 		register struct in_ifaddr *ia;
316 		struct ifnet *ifp = ro.ro_rt->rt_ifp;
317 
318 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
319 			if (ia->ia_ifp == ifp)
320 				break;
321 		if (ia == 0)
322 			ia = in_ifaddr;
323 		if (ia == 0) {
324 			RTFREE(ro.ro_rt);
325 			return (EADDRNOTAVAIL);
326 		}
327 		src = (struct sockaddr_in *)&ia->ia_addr;
328 	}
329 
330 	/*
331 	 * Is there a free (pseudo-)interface or space?
332 	 */
333 	for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) {
334 		if ((ifn->ifen_ifnet.if_flags & IFF_UP) == 0)
335 			break;
336 	}
337 	if (ifn == NULL)
338 		ifn = nsipattach();
339 	if (ifn == NULL) {
340 		RTFREE(ro.ro_rt);
341 		return (ENOBUFS);
342 	}
343 	ifn->ifen_route = ro;
344 	ifn->ifen_dst =  ip_dst->sin_addr;
345 	ifn->ifen_src = src->sin_addr;
346 
347 	/*
348 	 * now configure this as a point to point link
349 	 */
350 	ifr.ifr_name[4] = '0' + nsipif.if_unit - 1;
351 	ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst;
352 	(void)ns_control((struct socket *)0, SIOCSIFDSTADDR, (caddr_t)&ifr,
353 			(struct ifnet *)ifn);
354 	satons_addr(ifr.ifr_addr).x_host = ns_thishost;
355 	return (ns_control((struct socket *)0, SIOCSIFADDR, (caddr_t)&ifr,
356 			(struct ifnet *)ifn));
357 }
358 
359 nsip_free(ifp)
360 struct ifnet *ifp;
361 {
362 	register struct ifnet_en *ifn = (struct ifnet_en *)ifp;
363 	struct route *ro = & ifn->ifen_route;
364 
365 	if (ro->ro_rt) {
366 		RTFREE(ro->ro_rt);
367 		ro->ro_rt = 0;
368 	}
369 	ifp->if_flags &= ~IFF_UP;
370 	return (0);
371 }
372 
373 nsip_ctlinput(cmd, sa)
374 	int cmd;
375 	struct sockaddr *sa;
376 {
377 	extern u_char inetctlerrmap[];
378 	struct sockaddr_in *sin;
379 	int in_rtchange();
380 
381 	if ((unsigned)cmd >= PRC_NCMDS)
382 		return;
383 	if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
384 		return;
385 	sin = (struct sockaddr_in *)sa;
386 	if (sin->sin_addr.s_addr == INADDR_ANY)
387 		return;
388 
389 	switch (cmd) {
390 
391 	case PRC_ROUTEDEAD:
392 	case PRC_REDIRECT_NET:
393 	case PRC_REDIRECT_HOST:
394 	case PRC_REDIRECT_TOSNET:
395 	case PRC_REDIRECT_TOSHOST:
396 		nsip_rtchange(&sin->sin_addr);
397 		break;
398 	}
399 }
400 
401 nsip_rtchange(dst)
402 	register struct in_addr *dst;
403 {
404 	register struct ifnet_en *ifn;
405 
406 	for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) {
407 		if (ifn->ifen_dst.s_addr == dst->s_addr &&
408 			ifn->ifen_route.ro_rt) {
409 				RTFREE(ifn->ifen_route.ro_rt);
410 				ifn->ifen_route.ro_rt = 0;
411 		}
412 	}
413 }
414 #endif
415