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