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