xref: /csrg-svn/sys/netns/ns_ip.c (revision 25055)
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.9 (Berkeley) 10/01/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 #ifdef BBNNET
42 #include "../bbnnet/in_pcb.h"
43 #include "../bbnnet/nopcb.h"
44 #endif
45 
46 struct ifnet_en {
47 	struct ifnet ifen_ifnet;
48 	struct route ifen_route;
49 	struct in_addr ifen_src;
50 	struct in_addr ifen_dst;
51 };
52 
53 int	nsipoutput(), nsipioctl();
54 #define LOMTU	(1024+512);
55 
56 struct ifnet nsipif;
57 union ns_net nsip_net;
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==0) return (0);
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 		/*
102 		 * Everything else is done at a higher level.
103 		 */
104 		break;
105 
106 	case SIOCSIFFLAGS:
107 		ifr = (struct ifreq *)data;
108 		if ((ifr->ifr_flags & IFF_UP) == 0)
109 			error = nsip_free(ifp);
110 
111 
112 	default:
113 		error = EINVAL;
114 	}
115 	return (error);
116 }
117 
118 struct mbuf *nsip_badlen;
119 struct mbuf *nsip_lastin;
120 int nsip_hold_input;
121 
122 idpip_input(m, ifp)
123 	register struct mbuf *m;
124 	struct ifnet *ifp;
125 {
126 	register struct ip *ip;
127 	register struct idp *idp;
128 	register struct ifqueue *ifq = &nsintrq;
129 	int len, s;
130 
131 	if(nsip_hold_input) {
132 		if(nsip_lastin) {
133 			m_freem(nsip_lastin);
134 		}
135 		nsip_lastin = m_copy(m, 0, (int)M_COPYALL);
136 	}
137 	/*
138 	 * Get IP and IDP header together in first mbuf.
139 	 */
140 	nsipif.if_ipackets++;
141 	s = sizeof (struct ip) + sizeof (struct idp);
142 	if ((m->m_off > MMAXOFF || m->m_len < s) &&
143 	    (m = m_pullup(m, s))==0) {
144 		nsipif.if_ierrors++;
145 		return;
146 	}
147 	ip = mtod(m, struct ip *);
148 	if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
149 		ip_stripoptions(ip, (struct mbuf *)0);
150 		if (m->m_len < s) {
151 			if ((m = m_pullup(m, s))==0) {
152 				nsipif.if_ierrors++;
153 				return;
154 			}
155 			ip = mtod(m, struct ip *);
156 		}
157 	}
158 
159 	/*
160 	 * Make mbuf data length reflect IDP length.
161 	 * If not enough data to reflect IDP length, drop.
162 	 */
163 	m->m_off += sizeof (struct ip);
164 	m->m_len -= sizeof (struct ip);
165 	idp = mtod(m, struct idp *);
166 	len = ntohs(idp->idp_len);
167 	if (len & 1) len++;		/* Preserve Garbage Byte */
168 	if (ip->ip_len != len) {
169 		if (len > ip->ip_len) {
170 			nsipif.if_ierrors++;
171 			if(nsip_badlen) m_freem(nsip_badlen);
172 			nsip_badlen = m;
173 			return;
174 		}
175 		/* Any extra will be trimmed off by the NS routines */
176 	}
177 
178 	/*
179 	 * Place interface pointer before the data
180 	 * for the receiving protocol.
181 	 */
182 	if (m->m_off >= MMINOFF + sizeof(struct ifnet *)) {
183 		m->m_off -= sizeof(struct ifnet *);
184 		m->m_len += sizeof(struct ifnet *);
185 	} else {
186 		struct mbuf *n;
187 
188 		n = m_get(M_DONTWAIT, MT_HEADER);
189 		if (n == (struct mbuf *)0)
190 			goto bad;
191 		n->m_off = MMINOFF;
192 		n->m_len = sizeof(struct ifnet *);
193 		n->m_next = m;
194 		m = n;
195 	}
196 	*(mtod(m, struct ifnet **)) = ifp;
197 
198 	/*
199 	 * Deliver to NS
200 	 */
201 	s = splimp();
202 	if (IF_QFULL(ifq)) {
203 		IF_DROP(ifq);
204 bad:
205 		m_freem(m);
206 		splx(s);
207 		return;
208 	}
209 	IF_ENQUEUE(ifq, m);
210 	schednetisr(NETISR_NS);
211 	splx(s);
212 	return;
213 }
214 
215 /* ARGSUSED */
216 nsipoutput(ifn, m0, dst)
217 	struct ifnet_en *ifn;
218 	struct mbuf *m0;
219 	struct sockaddr *dst;
220 {
221 
222 	register struct mbuf *m = dtom(ifn);
223 	register struct ip *ip;
224 	register struct route *ro = &(ifn->ifen_route);
225 	register int len = 0;
226 	register struct idp *idp = mtod(m0, struct idp *);
227 	int error;
228 
229 	if (m->m_len != sizeof(struct ifnet_en)) {
230 		printf("nsipoutput: bad dst ifp %x\n", ifn);
231 		goto bad;
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 	m = m0;
244 	if(m->m_off < MMINOFF + sizeof (struct ip)) {
245 		m = m_get(M_DONTWAIT, MT_HEADER);
246 		if (m == 0) {
247 			m_freem(m0);
248 			return (ENOBUFS);
249 		}
250 		m->m_off = MMAXOFF - sizeof (struct ip);
251 		m->m_len = sizeof (struct ip);
252 		m->m_next = m0;
253 	} else {
254 		m->m_off -= sizeof (struct ip);
255 		m->m_len += sizeof (struct ip);
256 	}
257 	/*
258 	 * Fill in IP header.
259 	 */
260 	ip = mtod(m, struct ip *);
261 	*(long *)ip = 0;
262 	ip->ip_p = IPPROTO_IDP;
263 	ip->ip_src = ifn->ifen_src;
264 	ip->ip_dst = ifn->ifen_dst;
265 #ifdef BBNNET
266 	ip->ip_tos = 0;
267 	NOPCB_IPSEND(m, len, 0, error);
268 #else
269 	ip->ip_len = (u_short)len + sizeof (struct ip);
270 	ip->ip_ttl = MAXTTL;
271 
272 	/*
273 	 * Output final datagram.
274 	 */
275 	error =  (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST));
276 #endif
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(m0);
284 	return(ENETUNREACH);
285 }
286 
287 struct ifreq ifr = {"nsip0"};
288 
289 nsip_route(m)
290 	register struct mbuf *m;
291 {
292 	register struct nsip_req *rq = mtod(m, struct nsip_req *);
293 	struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns;
294 	struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip;
295 	struct route ro;
296 	struct ifnet_en *ifn;
297 	struct sockaddr_in *src;
298 	/*
299 	 * First, determine if we can get to the destination
300 	 */
301 	bzero((caddr_t)&ro, sizeof (ro));
302 	ro.ro_dst = *(struct sockaddr *)ip_dst;
303 	rtalloc(&ro);
304 	if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
305 		return (ENETUNREACH);
306 	}
307 	/*
308 	 * And see how he's going to get back to us:
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 			return (EADDRNOTAVAIL);
321 		}
322 		src = (struct sockaddr_in *)&ia->ia_addr;
323 	}
324 	/*
325 	 * Is there a free (pseudo-)interface or space?
326 	 */
327 	for (m = nsip_list; m; m = m->m_next) {
328 		struct ifnet *ifp = mtod(m, struct ifnet *);
329 		if ((ifp->if_flags & IFF_UP) == 0)
330 			break;
331 	}
332 	if (m == (struct mbuf *) 0)
333 		m = nsipattach();
334 	if (m==NULL) {return (ENOBUFS);}
335 	ifn = mtod(m, struct ifnet_en *);
336 
337 	ro.ro_rt->rt_use++;
338 	ifn->ifen_route = ro;
339 	ifn->ifen_dst =  ip_dst->sin_addr;
340 	ifn->ifen_src = src->sin_addr;
341 
342 	/*
343 	 * now configure this as a point to point link
344 	 */
345 	ifr.ifr_name[4] = '0' + nsipif.if_unit - 1;
346 	ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst;
347 	return(ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr,
348 			(struct ifnet *)ifn));
349 }
350 
351 nsip_free(ifp)
352 struct ifnet *ifp;
353 {
354 	register struct ifnet_en *ifn = (struct ifnet_en *)ifp;
355 	struct route *ro = & ifn->ifen_route;
356 
357 	if (ro->ro_rt) {
358 		RTFREE(ro->ro_rt);
359 		ro->ro_rt = 0;
360 	}
361 	ifp->if_flags &= ~IFF_UP;
362 	return (0);
363 }
364 
365 nsip_ctlinput(cmd, sa)
366 	int cmd;
367 	struct sockaddr *sa;
368 {
369 	extern u_char inetctlerrmap[];
370 	struct sockaddr_in *sin;
371 	int in_rtchange();
372 
373 	if ((unsigned)cmd > PRC_NCMDS)
374 		return;
375 	if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
376 		return;
377 	sin = (struct sockaddr_in *)sa;
378 	if (sin->sin_addr.s_addr == INADDR_ANY)
379 		return;
380 
381 	switch (cmd) {
382 
383 	case PRC_ROUTEDEAD:
384 	case PRC_REDIRECT_NET:
385 	case PRC_REDIRECT_HOST:
386 	case PRC_REDIRECT_TOSNET:
387 	case PRC_REDIRECT_TOSHOST:
388 		nsip_rtchange(&sin->sin_addr);
389 		break;
390 	}
391 }
392 
393 nsip_rtchange(dst)
394 	register struct in_addr *dst;
395 {
396 	register struct mbuf *m;
397 	register struct ifnet_en *ifn;
398 
399 	for (m = nsip_list; m; m = m->m_next)
400 		if (ifn->ifen_dst.s_addr == dst->s_addr &&
401 			ifn->ifen_route.ro_rt) {
402 				RTFREE(ifn->ifen_route.ro_rt);
403 				ifn->ifen_route.ro_rt = 0;
404 		}
405 }
406 #endif
407