xref: /csrg-svn/sys/netns/ns_ip.c (revision 24562)
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.7 (Berkeley) 09/06/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 
141 	/*
142 	 * Make mbuf data length reflect IDP length.
143 	 * If not enough data to reflect IDP length, drop.
144 	 */
145 	m->m_off += sizeof (struct ip);
146 	m->m_len -= sizeof (struct ip);
147 	idp = mtod(m, struct idp *);
148 	len = ntohs(idp->idp_len);
149 	if (len & 1) len++;		/* Preserve Garbage Byte */
150 	if (ip->ip_len != len) {
151 		if (len > ip->ip_len) {
152 			nsipif.if_ierrors++;
153 			if(nsip_badlen) m_freem(nsip_badlen);
154 			nsip_badlen = m;
155 			return;
156 		}
157 		/* Any extra will be trimmed off by the NS routines */
158 	}
159 
160 	/*
161 	 * Place interface pointer before the data
162 	 * for the receiving protocol.
163 	 */
164 	if (m->m_off >= MMINOFF + sizeof(struct ifnet *)) {
165 		m->m_off -= sizeof(struct ifnet *);
166 		m->m_len += sizeof(struct ifnet *);
167 	} else {
168 		struct mbuf *n;
169 
170 		n = m_get(M_DONTWAIT, MT_HEADER);
171 		if (n == (struct mbuf *)0)
172 			goto bad;
173 		n->m_off = MMINOFF;
174 		n->m_len = sizeof(struct ifnet *);
175 		n->m_next = m;
176 		m = n;
177 	}
178 	*(mtod(m, struct ifnet **)) = ifp;
179 
180 	/*
181 	 * Deliver to NS
182 	 */
183 	s = splimp();
184 	if (IF_QFULL(ifq)) {
185 		IF_DROP(ifq);
186 bad:
187 		m_freem(m);
188 		splx(s);
189 		return;
190 	}
191 	IF_ENQUEUE(ifq, m);
192 	schednetisr(NETISR_NS);
193 	splx(s);
194 	return;
195 }
196 
197 /* ARGSUSED */
198 nsipoutput(ifn, m0, dst)
199 	struct ifnet_en *ifn;
200 	struct mbuf *m0;
201 	struct sockaddr *dst;
202 {
203 
204 	register struct mbuf *m = dtom(ifn);
205 	register struct ip *ip;
206 	register struct route *ro = &(ifn->ifen_route);
207 	register int len = 0;
208 	register struct idp *idp = mtod(m0, struct idp *);
209 	int error;
210 
211 	if (m->m_len != sizeof(struct ifnet_en)) {
212 		printf("nsipoutput: bad dst ifp %x\n", ifn);
213 		goto bad;
214 	}
215 	ifn->ifen_ifnet.if_opackets++;
216 	nsipif.if_opackets++;
217 
218 
219 	/*
220 	 * Calculate data length and make space
221 	 * for IP header.
222 	 */
223 	len =  ntohs(idp->idp_len);
224 	if (len & 1) len++;		/* Preserve Garbage Byte */
225 	m = m0;
226 	if(m->m_off < MMINOFF + sizeof (struct ip)) {
227 		m = m_get(M_DONTWAIT, MT_HEADER);
228 		if (m == 0) {
229 			m_freem(m0);
230 			return (ENOBUFS);
231 		}
232 		m->m_off = MMAXOFF - sizeof (struct ip);
233 		m->m_len = sizeof (struct ip);
234 		m->m_next = m0;
235 	} else {
236 		m->m_off -= sizeof (struct ip);
237 		m->m_len += sizeof (struct ip);
238 	}
239 	/*
240 	 * Fill in IP header.
241 	 */
242 	ip = mtod(m, struct ip *);
243 	*(long *)ip = 0;
244 	ip->ip_p = IPPROTO_IDP;
245 	ip->ip_src = ifn->ifen_src;
246 	ip->ip_dst = ifn->ifen_dst;
247 #ifdef BBNNET
248 	ip->ip_tos = 0;
249 	NOPCB_IPSEND(m, len, 0, error);
250 #else
251 	ip->ip_len = (u_short)len + sizeof (struct ip);
252 	ip->ip_ttl = MAXTTL;
253 
254 	/*
255 	 * Output final datagram.
256 	 */
257 	error =  (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST));
258 #endif
259 	if (error) {
260 		ifn->ifen_ifnet.if_oerrors++;
261 		ifn->ifen_ifnet.if_ierrors = error;
262 	}
263 	return (error);
264 bad:
265 	m_freem(m0);
266 	return(ENETUNREACH);
267 }
268 
269 struct ifreq ifr = {"nsip0"};
270 
271 nsip_route(m)
272 	register struct mbuf *m;
273 {
274 	register struct nsip_req *rq = mtod(m, struct nsip_req *);
275 	struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns;
276 	struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip;
277 	struct route ro;
278 	struct ifnet_en *ifn;
279 	struct sockaddr_in *src;
280 	/*
281 	 * First, determine if we can get to the destination
282 	 */
283 	bzero((caddr_t)&ro, sizeof (ro));
284 	ro.ro_dst = *(struct sockaddr *)ip_dst;
285 	rtalloc(&ro);
286 	if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
287 		return (ENETUNREACH);
288 	}
289 	/*
290 	 * And see how he's going to get back to us:
291 	 */
292 	{
293 		register struct in_ifaddr *ia;
294 		struct ifnet *ifp = ro.ro_rt->rt_ifp;
295 
296 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
297 			if (ia->ia_ifp == ifp)
298 				break;
299 		if (ia == 0)
300 			ia = in_ifaddr;
301 		if (ia == 0) {
302 			return (EADDRNOTAVAIL);
303 		}
304 		src = (struct sockaddr_in *)&ia->ia_addr;
305 	}
306 	/*
307 	 * Is there space?
308 	 */
309 	m = nsipattach();
310 	if (m==NULL) {return (ENOBUFS);}
311 	ifn = mtod(m, struct ifnet_en *);
312 
313 	ro.ro_rt->rt_use++;
314 	ifn->ifen_route = ro;
315 	ifn->ifen_dst =  ip_dst->sin_addr;
316 	ifn->ifen_src = src->sin_addr;
317 
318 	/*
319 	 * now configure this as a point to point link
320 	 */
321 	ifr.ifr_name[4] = '0' + nsipif.if_unit - 1;
322 	ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst;
323 	return(ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr,
324 			(struct ifnet *)ifn));
325 }
326 #endif
327