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