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