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