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