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