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