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