xref: /original-bsd/sys/netns/ns_ip.c (revision c0f053f7)
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.5 (Berkeley) 04/25/89
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 "malloc.h"
28 #include "mbuf.h"
29 #include "socket.h"
30 #include "socketvar.h"
31 #include "errno.h"
32 #include "ioctl.h"
33 #include "protosw.h"
34 
35 #include "../net/if.h"
36 #include "../net/netisr.h"
37 #include "../net/route.h"
38 
39 #include "../netinet/in.h"
40 #include "../netinet/in_systm.h"
41 #include "../netinet/in_var.h"
42 #include "../netinet/ip.h"
43 #include "../netinet/ip_var.h"
44 
45 #include "machine/mtpr.h"
46 
47 #include "../netns/ns.h"
48 #include "../netns/ns_if.h"
49 #include "../netns/idp.h"
50 
51 struct ifnet_en {
52 	struct ifnet ifen_ifnet;
53 	struct route ifen_route;
54 	struct in_addr ifen_src;
55 	struct in_addr ifen_dst;
56 	struct ifnet_en *ifen_next;
57 };
58 
59 int	nsipoutput(), nsipioctl(), nsipstart();
60 #define LOMTU	(1024+512);
61 
62 struct ifnet nsipif;
63 struct ifnet_en *nsip_list;		/* list of all hosts and gateways or
64 					broadcast addrs */
65 
66 struct ifnet_en *
67 nsipattach()
68 {
69 	register struct ifnet_en *m;
70 	register struct ifnet *ifp;
71 
72 	if (nsipif.if_mtu == 0) {
73 		ifp = &nsipif;
74 		ifp->if_name = "nsip";
75 		ifp->if_mtu = LOMTU;
76 		ifp->if_ioctl = nsipioctl;
77 		ifp->if_output = nsipoutput;
78 		ifp->if_start = nsipstart;
79 		ifp->if_flags = IFF_POINTOPOINT;
80 	}
81 
82 	MALLOC((m), struct ifnet_en *, sizeof(*m), M_PCB, M_NOWAIT);
83 	if (m == NULL) return (NULL);
84 	m->ifen_next = nsip_list;
85 	nsip_list = m;
86 	ifp = &m->ifen_ifnet;
87 
88 	ifp->if_name = "nsip";
89 	ifp->if_mtu = LOMTU;
90 	ifp->if_ioctl = nsipioctl;
91 	ifp->if_output = nsipoutput;
92 	ifp->if_start = nsipstart;
93 	ifp->if_flags = IFF_POINTOPOINT;
94 	ifp->if_unit = nsipif.if_unit++;
95 	if_attach(ifp);
96 
97 	return (m);
98 }
99 
100 
101 /*
102  * Process an ioctl request.
103  */
104 /* ARGSUSED */
105 nsipioctl(ifp, cmd, data)
106 	register struct ifnet *ifp;
107 	int cmd;
108 	caddr_t data;
109 {
110 	int error = 0;
111 	struct ifreq *ifr;
112 
113 	switch (cmd) {
114 
115 	case SIOCSIFADDR:
116 		ifp->if_flags |= IFF_UP;
117 		/* fall into: */
118 
119 	case SIOCSIFDSTADDR:
120 		/*
121 		 * Everything else is done at a higher level.
122 		 */
123 		break;
124 
125 	case SIOCSIFFLAGS:
126 		ifr = (struct ifreq *)data;
127 		if ((ifr->ifr_flags & IFF_UP) == 0)
128 			error = nsip_free(ifp);
129 
130 
131 	default:
132 		error = EINVAL;
133 	}
134 	return (error);
135 }
136 
137 struct mbuf *nsip_badlen;
138 struct mbuf *nsip_lastin;
139 int nsip_hold_input;
140 
141 idpip_input(m, ifp)
142 	register struct mbuf *m;
143 	struct ifnet *ifp;
144 {
145 	register struct ip *ip;
146 	register struct idp *idp;
147 	register struct ifqueue *ifq = &nsintrq;
148 	int len, s;
149 
150 	if (nsip_hold_input) {
151 		if (nsip_lastin) {
152 			m_freem(nsip_lastin);
153 		}
154 		nsip_lastin = m_copym(m, 0, (int)M_COPYALL, M_DONTWAIT);
155 	}
156 	/*
157 	 * Get IP and IDP header together in first mbuf.
158 	 */
159 	nsipif.if_ipackets++;
160 	s = sizeof (struct ip) + sizeof (struct idp);
161 	if (((m->m_flags & M_EXT) || m->m_len < s) &&
162 	    (m = m_pullup(m, s)) == 0) {
163 		nsipif.if_ierrors++;
164 		return;
165 	}
166 	ip = mtod(m, struct ip *);
167 	if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
168 		ip_stripoptions(ip, (struct mbuf *)0);
169 		if (m->m_len < s) {
170 			if ((m = m_pullup(m, s)) == 0) {
171 				nsipif.if_ierrors++;
172 				return;
173 			}
174 			ip = mtod(m, struct ip *);
175 		}
176 	}
177 
178 	/*
179 	 * Make mbuf data length reflect IDP length.
180 	 * If not enough data to reflect IDP length, drop.
181 	 */
182 	m->m_data += sizeof (struct ip);
183 	m->m_len -= sizeof (struct ip);
184 	m->m_pkthdr.len -= sizeof (struct ip);
185 	idp = mtod(m, struct idp *);
186 	len = ntohs(idp->idp_len);
187 	if (len & 1) len++;		/* Preserve Garbage Byte */
188 	if (ip->ip_len != len) {
189 		if (len > ip->ip_len) {
190 			nsipif.if_ierrors++;
191 			if (nsip_badlen) m_freem(nsip_badlen);
192 			nsip_badlen = m;
193 			return;
194 		}
195 		/* Any extra will be trimmed off by the NS routines */
196 	}
197 
198 	/*
199 	 * Place interface pointer before the data
200 	 * for the receiving protocol.
201 	 */
202 	m->m_pkthdr.rcvif = ifp;
203 	/*
204 	 * Deliver to NS
205 	 */
206 	s = splimp();
207 	if (IF_QFULL(ifq)) {
208 		IF_DROP(ifq);
209 bad:
210 		m_freem(m);
211 		splx(s);
212 		return;
213 	}
214 	IF_ENQUEUE(ifq, m);
215 	schednetisr(NETISR_NS);
216 	splx(s);
217 	return;
218 }
219 
220 /* ARGSUSED */
221 nsipoutput(ifn, m, dst)
222 	struct ifnet_en *ifn;
223 	register struct mbuf *m;
224 	struct sockaddr *dst;
225 {
226 
227 	register struct ip *ip;
228 	register struct route *ro = &(ifn->ifen_route);
229 	register int len = 0;
230 	register struct idp *idp = mtod(m, struct idp *);
231 	int error;
232 
233 	ifn->ifen_ifnet.if_opackets++;
234 	nsipif.if_opackets++;
235 
236 
237 	/*
238 	 * Calculate data length and make space
239 	 * for IP header.
240 	 */
241 	len =  ntohs(idp->idp_len);
242 	if (len & 1) len++;		/* Preserve Garbage Byte */
243 	/* following clause not necessary on vax */
244 	if (3 & (int)m->m_data) {
245 		/* force longword alignment of ip hdr */
246 		struct mbuf *m0 = m_gethdr(MT_HEADER, M_DONTWAIT);
247 		if (m0 == 0) {
248 			m_freem(m);
249 			return (ENOBUFS);
250 		}
251 		MH_ALIGN(m0, sizeof (struct ip));
252 		m0->m_flags = m->m_flags & M_COPYFLAGS;
253 		m0->m_next = m;
254 		m0->m_len = sizeof (struct ip);
255 		m0->m_pkthdr.len = m0->m_len + m->m_len;
256 		m->m_flags &= ~M_PKTHDR;
257 	} else {
258 		M_PREPEND(m, sizeof (struct ip), M_DONTWAIT);
259 		if (m == 0)
260 			return (ENOBUFS);
261 	}
262 	/*
263 	 * Fill in IP header.
264 	 */
265 	ip = mtod(m, struct ip *);
266 	*(long *)ip = 0;
267 	ip->ip_p = IPPROTO_IDP;
268 	ip->ip_src = ifn->ifen_src;
269 	ip->ip_dst = ifn->ifen_dst;
270 	ip->ip_len = (u_short)len + sizeof (struct ip);
271 	ip->ip_ttl = MAXTTL;
272 
273 	/*
274 	 * Output final datagram.
275 	 */
276 	error =  (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST));
277 	if (error) {
278 		ifn->ifen_ifnet.if_oerrors++;
279 		ifn->ifen_ifnet.if_ierrors = error;
280 	}
281 	return (error);
282 bad:
283 	m_freem(m);
284 	return (ENETUNREACH);
285 }
286 
287 nsipstart(ifp)
288 struct ifnet *ifp;
289 {
290 	panic("nsip_start called\n");
291 }
292 
293 struct ifreq ifr = {"nsip0"};
294 
295 nsip_route(m)
296 	register struct mbuf *m;
297 {
298 	register struct nsip_req *rq = mtod(m, struct nsip_req *);
299 	struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns;
300 	struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip;
301 	struct route ro;
302 	struct ifnet_en *ifn;
303 	struct sockaddr_in *src;
304 
305 	/*
306 	 * First, make sure we already have an ns address:
307 	 */
308 	if (ns_hosteqnh(ns_thishost, ns_zerohost))
309 		return (EADDRNOTAVAIL);
310 	/*
311 	 * Now, determine if we can get to the destination
312 	 */
313 	bzero((caddr_t)&ro, sizeof (ro));
314 	ro.ro_dst = *(struct sockaddr *)ip_dst;
315 	rtalloc(&ro);
316 	if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
317 		return (ENETUNREACH);
318 	}
319 
320 	/*
321 	 * And see how he's going to get back to us:
322 	 * i.e., what return ip address do we use?
323 	 */
324 	{
325 		register struct in_ifaddr *ia;
326 		struct ifnet *ifp = ro.ro_rt->rt_ifp;
327 
328 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
329 			if (ia->ia_ifp == ifp)
330 				break;
331 		if (ia == 0)
332 			ia = in_ifaddr;
333 		if (ia == 0) {
334 			RTFREE(ro.ro_rt);
335 			return (EADDRNOTAVAIL);
336 		}
337 		src = (struct sockaddr_in *)&ia->ia_addr;
338 	}
339 
340 	/*
341 	 * Is there a free (pseudo-)interface or space?
342 	 */
343 	for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) {
344 		if ((ifn->ifen_ifnet.if_flags & IFF_UP) == 0)
345 			break;
346 	}
347 	if (ifn == NULL)
348 		ifn = nsipattach();
349 	if (ifn == NULL) {
350 		RTFREE(ro.ro_rt);
351 		return (ENOBUFS);
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 ifnet_en *ifn;
415 
416 	for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) {
417 		if (ifn->ifen_dst.s_addr == dst->s_addr &&
418 			ifn->ifen_route.ro_rt) {
419 				RTFREE(ifn->ifen_route.ro_rt);
420 				ifn->ifen_route.ro_rt = 0;
421 		}
422 	}
423 }
424 #endif
425