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