lint
[unix-history] / usr / src / sys / netns / ns_ip.c
CommitLineData
8ae0e4b4 1/*
143067e7 2 * Copyright (c) 1985 Regents of the University of California.
8ae0e4b4
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
c43a1c83 6 * @(#)ns_ip.c 6.12 (Berkeley) %G%
8ae0e4b4 7 */
c5d24c39
KS
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"
f97be0c9 18#include "socketvar.h"
c5d24c39
KS
19#include "errno.h"
20#include "ioctl.h"
143067e7 21#include "protosw.h"
c5d24c39
KS
22
23#include "../net/if.h"
24#include "../net/netisr.h"
25#include "../net/route.h"
26
27#include "../netinet/in.h"
28#include "../netinet/in_systm.h"
29#include "../netinet/in_var.h"
30#include "../netinet/ip.h"
31#include "../netinet/ip_var.h"
32
33#ifdef vax
34#include "../vax/mtpr.h"
35#endif
36
37#include "../netns/ns.h"
38#include "../netns/ns_if.h"
39#include "../netns/idp.h"
40
41struct ifnet_en {
42 struct ifnet ifen_ifnet;
43 struct route ifen_route;
44 struct in_addr ifen_src;
45 struct in_addr ifen_dst;
46};
47
48int nsipoutput(), nsipioctl();
49#define LOMTU (1024+512);
50
51struct ifnet nsipif;
52union ns_net nsip_net;
53struct mbuf *nsip_list; /* list of all hosts and gateways or
54 broadcast addrs */
55
56struct mbuf *
57nsipattach()
58{
59 register struct mbuf *m = m_getclr(M_DONTWAIT, MT_PCB);
60 register struct ifnet *ifp;
c5d24c39 61
8b659320 62 if (m == NULL) return (NULL);
c5d24c39
KS
63 m->m_off = MMINOFF;
64 m->m_len = sizeof(struct ifnet_en);
65 m->m_next = nsip_list;
66 nsip_list = m;
67 ifp = mtod(m, struct ifnet *);
68
69 ifp->if_name = "nsip";
70 ifp->if_mtu = LOMTU;
71 ifp->if_ioctl = nsipioctl;
72 ifp->if_output = nsipoutput;
73 ifp->if_flags = IFF_POINTOPOINT;
74 ifp->if_unit = nsipif.if_unit++;
75 if_attach(ifp);
8b659320 76 return (dtom(ifp));
c5d24c39
KS
77}
78
79
80/*
81 * Process an ioctl request.
82 */
83/* ARGSUSED */
84nsipioctl(ifp, cmd, data)
85 register struct ifnet *ifp;
86 int cmd;
87 caddr_t data;
88{
89 int error = 0;
143067e7 90 struct ifreq *ifr;
c5d24c39
KS
91
92 switch (cmd) {
93
94 case SIOCSIFADDR:
95 ifp->if_flags |= IFF_UP;
8b659320
KS
96 /* fall into: */
97
98 case SIOCSIFDSTADDR:
c5d24c39
KS
99 /*
100 * Everything else is done at a higher level.
101 */
102 break;
103
143067e7
KS
104 case SIOCSIFFLAGS:
105 ifr = (struct ifreq *)data;
106 if ((ifr->ifr_flags & IFF_UP) == 0)
107 error = nsip_free(ifp);
108
109
c5d24c39
KS
110 default:
111 error = EINVAL;
112 }
113 return (error);
114}
115
116struct mbuf *nsip_badlen;
117struct mbuf *nsip_lastin;
118int nsip_hold_input;
119
f95f0f6f
MK
120idpip_input(m, ifp)
121 register struct mbuf *m;
122 struct ifnet *ifp;
c5d24c39
KS
123{
124 register struct ip *ip;
125 register struct idp *idp;
c5d24c39
KS
126 register struct ifqueue *ifq = &nsintrq;
127 int len, s;
128
8b659320
KS
129 if (nsip_hold_input) {
130 if (nsip_lastin) {
f97be0c9 131 m_freem(nsip_lastin);
c5d24c39 132 }
f95f0f6f 133 nsip_lastin = m_copy(m, 0, (int)M_COPYALL);
c5d24c39
KS
134 }
135 /*
136 * Get IP and IDP header together in first mbuf.
137 */
138 nsipif.if_ipackets++;
c5d24c39
KS
139 s = sizeof (struct ip) + sizeof (struct idp);
140 if ((m->m_off > MMAXOFF || m->m_len < s) &&
8b659320 141 (m = m_pullup(m, s)) == 0) {
c5d24c39
KS
142 nsipif.if_ierrors++;
143 return;
144 }
145 ip = mtod(m, struct ip *);
f44e4988
MK
146 if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
147 ip_stripoptions(ip, (struct mbuf *)0);
148 if (m->m_len < s) {
8b659320 149 if ((m = m_pullup(m, s)) == 0) {
f44e4988
MK
150 nsipif.if_ierrors++;
151 return;
152 }
153 ip = mtod(m, struct ip *);
154 }
155 }
c5d24c39
KS
156
157 /*
158 * Make mbuf data length reflect IDP length.
159 * If not enough data to reflect IDP length, drop.
160 */
161 m->m_off += sizeof (struct ip);
162 m->m_len -= sizeof (struct ip);
163 idp = mtod(m, struct idp *);
164 len = ntohs(idp->idp_len);
f2c50bef 165 if (len & 1) len++; /* Preserve Garbage Byte */
c5d24c39
KS
166 if (ip->ip_len != len) {
167 if (len > ip->ip_len) {
168 nsipif.if_ierrors++;
8b659320 169 if (nsip_badlen) m_freem(nsip_badlen);
c5d24c39
KS
170 nsip_badlen = m;
171 return;
172 }
e56ec4e3 173 /* Any extra will be trimmed off by the NS routines */
c5d24c39 174 }
f95f0f6f
MK
175
176 /*
177 * Place interface pointer before the data
178 * for the receiving protocol.
179 */
180 if (m->m_off >= MMINOFF + sizeof(struct ifnet *)) {
181 m->m_off -= sizeof(struct ifnet *);
182 m->m_len += sizeof(struct ifnet *);
183 } else {
184 struct mbuf *n;
185
186 n = m_get(M_DONTWAIT, MT_HEADER);
187 if (n == (struct mbuf *)0)
188 goto bad;
189 n->m_off = MMINOFF;
190 n->m_len = sizeof(struct ifnet *);
191 n->m_next = m;
192 m = n;
193 }
194 *(mtod(m, struct ifnet **)) = ifp;
195
c5d24c39
KS
196 /*
197 * Deliver to NS
198 */
199 s = splimp();
200 if (IF_QFULL(ifq)) {
201 IF_DROP(ifq);
f95f0f6f
MK
202bad:
203 m_freem(m);
c5d24c39 204 splx(s);
f97be0c9 205 return;
c5d24c39 206 }
f95f0f6f 207 IF_ENQUEUE(ifq, m);
c5d24c39
KS
208 schednetisr(NETISR_NS);
209 splx(s);
f97be0c9 210 return;
c5d24c39
KS
211}
212
f97be0c9 213/* ARGSUSED */
c5d24c39
KS
214nsipoutput(ifn, m0, dst)
215 struct ifnet_en *ifn;
216 struct mbuf *m0;
217 struct sockaddr *dst;
218{
219
220 register struct mbuf *m = dtom(ifn);
221 register struct ip *ip;
222 register struct route *ro = &(ifn->ifen_route);
223 register int len = 0;
c5d24c39
KS
224 register struct idp *idp = mtod(m0, struct idp *);
225 int error;
226
227 if (m->m_len != sizeof(struct ifnet_en)) {
228 printf("nsipoutput: bad dst ifp %x\n", ifn);
229 goto bad;
230 }
231 ifn->ifen_ifnet.if_opackets++;
232 nsipif.if_opackets++;
233
234
235 /*
236 * Calculate data length and make space
237 * for IP header.
238 */
239 len = ntohs(idp->idp_len);
f2c50bef 240 if (len & 1) len++; /* Preserve Garbage Byte */
c5d24c39 241 m = m0;
8b659320 242 if (m->m_off < MMINOFF + sizeof (struct ip)) {
c5d24c39
KS
243 m = m_get(M_DONTWAIT, MT_HEADER);
244 if (m == 0) {
245 m_freem(m0);
246 return (ENOBUFS);
247 }
248 m->m_off = MMAXOFF - sizeof (struct ip);
249 m->m_len = sizeof (struct ip);
250 m->m_next = m0;
251 } else {
252 m->m_off -= sizeof (struct ip);
253 m->m_len += sizeof (struct ip);
254 }
255 /*
256 * Fill in IP header.
257 */
258 ip = mtod(m, struct ip *);
259 *(long *)ip = 0;
e56ec4e3 260 ip->ip_p = IPPROTO_IDP;
c5d24c39
KS
261 ip->ip_src = ifn->ifen_src;
262 ip->ip_dst = ifn->ifen_dst;
263 ip->ip_len = (u_short)len + sizeof (struct ip);
264 ip->ip_ttl = MAXTTL;
265
266 /*
267 * Output final datagram.
268 */
269 error = (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST));
270 if (error) {
271 ifn->ifen_ifnet.if_oerrors++;
272 ifn->ifen_ifnet.if_ierrors = error;
273 }
274 return (error);
275bad:
276 m_freem(m0);
8b659320 277 return (ENETUNREACH);
c5d24c39
KS
278}
279
280struct ifreq ifr = {"nsip0"};
281
282nsip_route(m)
283 register struct mbuf *m;
284{
285 register struct nsip_req *rq = mtod(m, struct nsip_req *);
286 struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns;
287 struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip;
c5d24c39
KS
288 struct route ro;
289 struct ifnet_en *ifn;
c5d24c39 290 struct sockaddr_in *src;
8b659320
KS
291
292 /*
293 * First, make sure we already have an ns address:
294 */
295 if (ns_hosteqnh(ns_thishost, ns_zerohost))
296 return (EADDRNOTAVAIL);
c5d24c39 297 /*
8b659320 298 * Now, determine if we can get to the destination
c5d24c39
KS
299 */
300 bzero((caddr_t)&ro, sizeof (ro));
301 ro.ro_dst = *(struct sockaddr *)ip_dst;
c5d24c39 302 rtalloc(&ro);
f97be0c9 303 if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
c5d24c39
KS
304 return (ENETUNREACH);
305 }
8b659320 306
c5d24c39
KS
307 /*
308 * And see how he's going to get back to us:
8b659320 309 * i.e., what return ip address do we use?
c5d24c39
KS
310 */
311 {
312 register struct in_ifaddr *ia;
313 struct ifnet *ifp = ro.ro_rt->rt_ifp;
314
315 for (ia = in_ifaddr; ia; ia = ia->ia_next)
316 if (ia->ia_ifp == ifp)
317 break;
318 if (ia == 0)
319 ia = in_ifaddr;
320 if (ia == 0) {
8b659320 321 RTFREE(ro.ro_rt);
c5d24c39
KS
322 return (EADDRNOTAVAIL);
323 }
324 src = (struct sockaddr_in *)&ia->ia_addr;
325 }
8b659320 326
c5d24c39 327 /*
143067e7 328 * Is there a free (pseudo-)interface or space?
c5d24c39 329 */
143067e7
KS
330 for (m = nsip_list; m; m = m->m_next) {
331 struct ifnet *ifp = mtod(m, struct ifnet *);
332 if ((ifp->if_flags & IFF_UP) == 0)
333 break;
334 }
335 if (m == (struct mbuf *) 0)
336 m = nsipattach();
8b659320
KS
337 if (m == NULL) {
338 RTFREE(ro.ro_rt);
339 return (ENOBUFS);
340 }
c5d24c39
KS
341 ifn = mtod(m, struct ifnet_en *);
342
c5d24c39
KS
343 ifn->ifen_route = ro;
344 ifn->ifen_dst = ip_dst->sin_addr;
345 ifn->ifen_src = src->sin_addr;
346
347 /*
348 * now configure this as a point to point link
349 */
350 ifr.ifr_name[4] = '0' + nsipif.if_unit - 1;
351 ifr.ifr_dstaddr = * (struct sockaddr *) ns_dst;
8b659320
KS
352 (void)ns_control((struct socket *)0, (int)SIOCSIFDSTADDR, (caddr_t)&ifr,
353 (struct ifnet *)ifn);
354 satons_addr(ifr.ifr_addr).x_host = ns_thishost;
355 return (ns_control((struct socket *)0, (int)SIOCSIFADDR, (caddr_t)&ifr,
c5d24c39
KS
356 (struct ifnet *)ifn));
357}
143067e7
KS
358
359nsip_free(ifp)
360struct ifnet *ifp;
361{
362 register struct ifnet_en *ifn = (struct ifnet_en *)ifp;
363 struct route *ro = & ifn->ifen_route;
364
365 if (ro->ro_rt) {
366 RTFREE(ro->ro_rt);
367 ro->ro_rt = 0;
368 }
369 ifp->if_flags &= ~IFF_UP;
370 return (0);
371}
372
373nsip_ctlinput(cmd, sa)
374 int cmd;
375 struct sockaddr *sa;
376{
377 extern u_char inetctlerrmap[];
378 struct sockaddr_in *sin;
379 int in_rtchange();
380
8b659320 381 if ((unsigned)cmd >= PRC_NCMDS)
143067e7
KS
382 return;
383 if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK)
384 return;
385 sin = (struct sockaddr_in *)sa;
386 if (sin->sin_addr.s_addr == INADDR_ANY)
387 return;
388
389 switch (cmd) {
390
391 case PRC_ROUTEDEAD:
392 case PRC_REDIRECT_NET:
393 case PRC_REDIRECT_HOST:
394 case PRC_REDIRECT_TOSNET:
395 case PRC_REDIRECT_TOSHOST:
396 nsip_rtchange(&sin->sin_addr);
397 break;
398 }
399}
400
401nsip_rtchange(dst)
402 register struct in_addr *dst;
403{
404 register struct mbuf *m;
405 register struct ifnet_en *ifn;
406
f6188621
KM
407 for (m = nsip_list; m; m = m->m_next) {
408 ifn = mtod(m, struct ifnet_en *);
143067e7
KS
409 if (ifn->ifen_dst.s_addr == dst->s_addr &&
410 ifn->ifen_route.ro_rt) {
411 RTFREE(ifn->ifen_route.ro_rt);
412 ifn->ifen_route.ro_rt = 0;
413 }
f6188621 414 }
143067e7 415}
c5d24c39 416#endif