xref: /csrg-svn/sys/netns/ns_ip.c (revision 24226)
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.5 (Berkeley) 08/09/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 struct ifnet_en {
41 	struct ifnet ifen_ifnet;
42 	struct route ifen_route;
43 	struct in_addr ifen_src;
44 	struct in_addr ifen_dst;
45 };
46 
47 int	nsipoutput(), nsipioctl();
48 #define LOMTU	(1024+512);
49 
50 struct ifnet nsipif;
51 union ns_net nsip_net;
52 struct mbuf *nsip_list;		/* list of all hosts and gateways or
53 					broadcast addrs */
54 
55 struct mbuf *
56 nsipattach()
57 {
58 	register struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
59 	register struct ifnet *ifp;
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_freem(nsip_lastin);
121 		}
122 		nsip_lastin = m_copy(m0, 0, (int)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;
174 	}
175 	IF_ENQUEUE(ifq, m0);
176 	schednetisr(NETISR_NS);
177 	splx(s);
178 	return;
179 }
180 
181 /* ARGSUSED */
182 nsipoutput(ifn, m0, dst)
183 	struct ifnet_en *ifn;
184 	struct mbuf *m0;
185 	struct sockaddr *dst;
186 {
187 
188 	register struct mbuf *m = dtom(ifn);
189 	register struct ip *ip;
190 	register struct route *ro = &(ifn->ifen_route);
191 	register int len = 0;
192 	register struct idp *idp = mtod(m0, struct idp *);
193 	int error;
194 
195 	if (m->m_len != sizeof(struct ifnet_en)) {
196 		printf("nsipoutput: bad dst ifp %x\n", ifn);
197 		goto bad;
198 	}
199 	ifn->ifen_ifnet.if_opackets++;
200 	nsipif.if_opackets++;
201 
202 
203 	/*
204 	 * Calculate data length and make space
205 	 * for IP header.
206 	 */
207 	len =  ntohs(idp->idp_len);
208 	if (len & 1) len++;		/* Preserve Garbage Byte */
209 	m = m0;
210 	if(m->m_off < MMINOFF + sizeof (struct ip)) {
211 		m = m_get(M_DONTWAIT, MT_HEADER);
212 		if (m == 0) {
213 			m_freem(m0);
214 			return (ENOBUFS);
215 		}
216 		m->m_off = MMAXOFF - sizeof (struct ip);
217 		m->m_len = sizeof (struct ip);
218 		m->m_next = m0;
219 	} else {
220 		m->m_off -= sizeof (struct ip);
221 		m->m_len += sizeof (struct ip);
222 	}
223 	/*
224 	 * Fill in IP header.
225 	 */
226 	ip = mtod(m, struct ip *);
227 	*(long *)ip = 0;
228 	ip->ip_p = IPPROTO_IDP;
229 	ip->ip_src = ifn->ifen_src;
230 	ip->ip_dst = ifn->ifen_dst;
231 	ip->ip_len = (u_short)len + sizeof (struct ip);
232 	ip->ip_ttl = MAXTTL;
233 
234 	/*
235 	 * Output final datagram.
236 	 */
237 	error =  (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST));
238 	if (error) {
239 		ifn->ifen_ifnet.if_oerrors++;
240 		ifn->ifen_ifnet.if_ierrors = error;
241 	}
242 	return (error);
243 bad:
244 	m_freem(m0);
245 	return(ENETUNREACH);
246 }
247 
248 struct ifreq ifr = {"nsip0"};
249 
250 nsip_route(m)
251 	register struct mbuf *m;
252 {
253 	register struct nsip_req *rq = mtod(m, struct nsip_req *);
254 	struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns;
255 	struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip;
256 	struct route ro;
257 	struct ifnet_en *ifn;
258 	struct sockaddr_in *src;
259 	/*
260 	 * First, determine if we can get to the destination
261 	 */
262 	bzero((caddr_t)&ro, sizeof (ro));
263 	ro.ro_dst = *(struct sockaddr *)ip_dst;
264 	rtalloc(&ro);
265 	if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
266 		return (ENETUNREACH);
267 	}
268 	/*
269 	 * And see how he's going to get back to us:
270 	 */
271 	{
272 		register struct in_ifaddr *ia;
273 		struct ifnet *ifp = ro.ro_rt->rt_ifp;
274 
275 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
276 			if (ia->ia_ifp == ifp)
277 				break;
278 		if (ia == 0)
279 			ia = in_ifaddr;
280 		if (ia == 0) {
281 			return (EADDRNOTAVAIL);
282 		}
283 		src = (struct sockaddr_in *)&ia->ia_addr;
284 	}
285 	/*
286 	 * Is there space?
287 	 */
288 	m = nsipattach();
289 	if (m==NULL) {return (ENOBUFS);}
290 	ifn = mtod(m, struct ifnet_en *);
291 
292 	ro.ro_rt->rt_use++;
293 	ifn->ifen_route = ro;
294 	ifn->ifen_dst =  ip_dst->sin_addr;
295 	ifn->ifen_src = src->sin_addr;
296 
297 	/*
298 	 * now configure this as a point to point link
299 	 */
300 	ifr.ifr_name[4] = '0' + nsipif.if_unit - 1;
301 	ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst;
302 	return(ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr,
303 			(struct ifnet *)ifn));
304 }
305 #endif
306