xref: /csrg-svn/sys/netns/ns_ip.c (revision 24827)
1 /*
2  * Copyright (c) 1982 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.8 (Berkeley) 09/17/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 
22 #include "../net/if.h"
23 #include "../net/netisr.h"
24 #include "../net/route.h"
25 
26 #include "../netinet/in.h"
27 #include "../netinet/in_systm.h"
28 #include "../netinet/in_var.h"
29 #include "../netinet/ip.h"
30 #include "../netinet/ip_var.h"
31 
32 #ifdef vax
33 #include "../vax/mtpr.h"
34 #endif
35 
36 #include "../netns/ns.h"
37 #include "../netns/ns_if.h"
38 #include "../netns/idp.h"
39 
40 #ifdef BBNNET
41 #include "../bbnnet/in_pcb.h"
42 #include "../bbnnet/nopcb.h"
43 #endif
44 
45 struct ifnet_en {
46 	struct ifnet ifen_ifnet;
47 	struct route ifen_route;
48 	struct in_addr ifen_src;
49 	struct in_addr ifen_dst;
50 };
51 
52 int	nsipoutput(), nsipioctl();
53 #define LOMTU	(1024+512);
54 
55 struct ifnet nsipif;
56 union ns_net nsip_net;
57 struct mbuf *nsip_list;		/* list of all hosts and gateways or
58 					broadcast addrs */
59 
60 struct mbuf *
61 nsipattach()
62 {
63 	register struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
64 	register struct ifnet *ifp;
65 
66 	if (m==0) return (0);
67 	m->m_off = MMINOFF;
68 	m->m_len = sizeof(struct ifnet_en);
69 	m->m_next = nsip_list;
70 	nsip_list = m;
71 	ifp = mtod(m, struct ifnet *);
72 
73 	ifp->if_name = "nsip";
74 	ifp->if_mtu = LOMTU;
75 	ifp->if_ioctl = nsipioctl;
76 	ifp->if_output = nsipoutput;
77 	ifp->if_flags = IFF_POINTOPOINT;
78 	ifp->if_unit = nsipif.if_unit++;
79 	if_attach(ifp);
80 	return(dtom(ifp));
81 }
82 
83 
84 /*
85  * Process an ioctl request.
86  */
87 /* ARGSUSED */
88 nsipioctl(ifp, cmd, data)
89 	register struct ifnet *ifp;
90 	int cmd;
91 	caddr_t data;
92 {
93 	int error = 0;
94 
95 	switch (cmd) {
96 
97 	case SIOCSIFADDR:
98 		ifp->if_flags |= IFF_UP;
99 		/*
100 		 * Everything else is done at a higher level.
101 		 */
102 		break;
103 
104 	default:
105 		error = EINVAL;
106 	}
107 	return (error);
108 }
109 
110 struct mbuf *nsip_badlen;
111 struct mbuf *nsip_lastin;
112 int nsip_hold_input;
113 
114 idpip_input(m, ifp)
115 	register struct mbuf *m;
116 	struct ifnet *ifp;
117 {
118 	register struct ip *ip;
119 	register struct idp *idp;
120 	register struct ifqueue *ifq = &nsintrq;
121 	int len, s;
122 
123 	if(nsip_hold_input) {
124 		if(nsip_lastin) {
125 			m_freem(nsip_lastin);
126 		}
127 		nsip_lastin = m_copy(m, 0, (int)M_COPYALL);
128 	}
129 	/*
130 	 * Get IP and IDP header together in first mbuf.
131 	 */
132 	nsipif.if_ipackets++;
133 	s = sizeof (struct ip) + sizeof (struct idp);
134 	if ((m->m_off > MMAXOFF || m->m_len < s) &&
135 	    (m = m_pullup(m, s))==0) {
136 		nsipif.if_ierrors++;
137 		return;
138 	}
139 	ip = mtod(m, struct ip *);
140 	if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
141 		ip_stripoptions(ip, (struct mbuf *)0);
142 		if (m->m_len < s) {
143 			if ((m = m_pullup(m, s))==0) {
144 				nsipif.if_ierrors++;
145 				return;
146 			}
147 			ip = mtod(m, struct ip *);
148 		}
149 	}
150 
151 	/*
152 	 * Make mbuf data length reflect IDP length.
153 	 * If not enough data to reflect IDP length, drop.
154 	 */
155 	m->m_off += sizeof (struct ip);
156 	m->m_len -= sizeof (struct ip);
157 	idp = mtod(m, struct idp *);
158 	len = ntohs(idp->idp_len);
159 	if (len & 1) len++;		/* Preserve Garbage Byte */
160 	if (ip->ip_len != len) {
161 		if (len > ip->ip_len) {
162 			nsipif.if_ierrors++;
163 			if(nsip_badlen) m_freem(nsip_badlen);
164 			nsip_badlen = m;
165 			return;
166 		}
167 		/* Any extra will be trimmed off by the NS routines */
168 	}
169 
170 	/*
171 	 * Place interface pointer before the data
172 	 * for the receiving protocol.
173 	 */
174 	if (m->m_off >= MMINOFF + sizeof(struct ifnet *)) {
175 		m->m_off -= sizeof(struct ifnet *);
176 		m->m_len += sizeof(struct ifnet *);
177 	} else {
178 		struct mbuf *n;
179 
180 		n = m_get(M_DONTWAIT, MT_HEADER);
181 		if (n == (struct mbuf *)0)
182 			goto bad;
183 		n->m_off = MMINOFF;
184 		n->m_len = sizeof(struct ifnet *);
185 		n->m_next = m;
186 		m = n;
187 	}
188 	*(mtod(m, struct ifnet **)) = ifp;
189 
190 	/*
191 	 * Deliver to NS
192 	 */
193 	s = splimp();
194 	if (IF_QFULL(ifq)) {
195 		IF_DROP(ifq);
196 bad:
197 		m_freem(m);
198 		splx(s);
199 		return;
200 	}
201 	IF_ENQUEUE(ifq, m);
202 	schednetisr(NETISR_NS);
203 	splx(s);
204 	return;
205 }
206 
207 /* ARGSUSED */
208 nsipoutput(ifn, m0, dst)
209 	struct ifnet_en *ifn;
210 	struct mbuf *m0;
211 	struct sockaddr *dst;
212 {
213 
214 	register struct mbuf *m = dtom(ifn);
215 	register struct ip *ip;
216 	register struct route *ro = &(ifn->ifen_route);
217 	register int len = 0;
218 	register struct idp *idp = mtod(m0, struct idp *);
219 	int error;
220 
221 	if (m->m_len != sizeof(struct ifnet_en)) {
222 		printf("nsipoutput: bad dst ifp %x\n", ifn);
223 		goto bad;
224 	}
225 	ifn->ifen_ifnet.if_opackets++;
226 	nsipif.if_opackets++;
227 
228 
229 	/*
230 	 * Calculate data length and make space
231 	 * for IP header.
232 	 */
233 	len =  ntohs(idp->idp_len);
234 	if (len & 1) len++;		/* Preserve Garbage Byte */
235 	m = m0;
236 	if(m->m_off < MMINOFF + sizeof (struct ip)) {
237 		m = m_get(M_DONTWAIT, MT_HEADER);
238 		if (m == 0) {
239 			m_freem(m0);
240 			return (ENOBUFS);
241 		}
242 		m->m_off = MMAXOFF - sizeof (struct ip);
243 		m->m_len = sizeof (struct ip);
244 		m->m_next = m0;
245 	} else {
246 		m->m_off -= sizeof (struct ip);
247 		m->m_len += sizeof (struct ip);
248 	}
249 	/*
250 	 * Fill in IP header.
251 	 */
252 	ip = mtod(m, struct ip *);
253 	*(long *)ip = 0;
254 	ip->ip_p = IPPROTO_IDP;
255 	ip->ip_src = ifn->ifen_src;
256 	ip->ip_dst = ifn->ifen_dst;
257 #ifdef BBNNET
258 	ip->ip_tos = 0;
259 	NOPCB_IPSEND(m, len, 0, error);
260 #else
261 	ip->ip_len = (u_short)len + sizeof (struct ip);
262 	ip->ip_ttl = MAXTTL;
263 
264 	/*
265 	 * Output final datagram.
266 	 */
267 	error =  (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST));
268 #endif
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 	 * First, determine if we can get to the destination
292 	 */
293 	bzero((caddr_t)&ro, sizeof (ro));
294 	ro.ro_dst = *(struct sockaddr *)ip_dst;
295 	rtalloc(&ro);
296 	if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
297 		return (ENETUNREACH);
298 	}
299 	/*
300 	 * And see how he's going to get back to us:
301 	 */
302 	{
303 		register struct in_ifaddr *ia;
304 		struct ifnet *ifp = ro.ro_rt->rt_ifp;
305 
306 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
307 			if (ia->ia_ifp == ifp)
308 				break;
309 		if (ia == 0)
310 			ia = in_ifaddr;
311 		if (ia == 0) {
312 			return (EADDRNOTAVAIL);
313 		}
314 		src = (struct sockaddr_in *)&ia->ia_addr;
315 	}
316 	/*
317 	 * Is there space?
318 	 */
319 	m = nsipattach();
320 	if (m==NULL) {return (ENOBUFS);}
321 	ifn = mtod(m, struct ifnet_en *);
322 
323 	ro.ro_rt->rt_use++;
324 	ifn->ifen_route = ro;
325 	ifn->ifen_dst =  ip_dst->sin_addr;
326 	ifn->ifen_src = src->sin_addr;
327 
328 	/*
329 	 * now configure this as a point to point link
330 	 */
331 	ifr.ifr_name[4] = '0' + nsipif.if_unit - 1;
332 	ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst;
333 	return(ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr,
334 			(struct ifnet *)ifn));
335 }
336 #endif
337