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