vn_open now returns locked, so must unlock when done
[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 *
dbf0c423 5 * %sccs.include.redist.c%
240edf1f 6 *
dbf0c423 7 * @(#)ns_ip.c 7.6 (Berkeley) %G%
8ae0e4b4 8 */
c5d24c39
KS
9
10/*
11 * Software interface driver for encapsulating ns in ip.
12 */
13
14#ifdef NSIP
15#include "param.h"
16#include "systm.h"
4dcdd98e 17#include "malloc.h"
c5d24c39
KS
18#include "mbuf.h"
19#include "socket.h"
f97be0c9 20#include "socketvar.h"
c5d24c39
KS
21#include "errno.h"
22#include "ioctl.h"
143067e7 23#include "protosw.h"
c5d24c39
KS
24
25#include "../net/if.h"
26#include "../net/netisr.h"
27#include "../net/route.h"
28
29#include "../netinet/in.h"
30#include "../netinet/in_systm.h"
31#include "../netinet/in_var.h"
32#include "../netinet/ip.h"
33#include "../netinet/ip_var.h"
34
d301d150 35#include "machine/mtpr.h"
c5d24c39
KS
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;
4dcdd98e 46 struct ifnet_en *ifen_next;
c5d24c39
KS
47};
48
4dcdd98e 49int nsipoutput(), nsipioctl(), nsipstart();
c5d24c39
KS
50#define LOMTU (1024+512);
51
52struct ifnet nsipif;
4dcdd98e 53struct ifnet_en *nsip_list; /* list of all hosts and gateways or
c5d24c39
KS
54 broadcast addrs */
55
4dcdd98e 56struct ifnet_en *
c5d24c39
KS
57nsipattach()
58{
4dcdd98e 59 register struct ifnet_en *m;
c5d24c39 60 register struct ifnet *ifp;
c5d24c39 61
4dcdd98e
KS
62 if (nsipif.if_mtu == 0) {
63 ifp = &nsipif;
64 ifp->if_name = "nsip";
65 ifp->if_mtu = LOMTU;
66 ifp->if_ioctl = nsipioctl;
67 ifp->if_output = nsipoutput;
68 ifp->if_start = nsipstart;
69 ifp->if_flags = IFF_POINTOPOINT;
70 }
71
72 MALLOC((m), struct ifnet_en *, sizeof(*m), M_PCB, M_NOWAIT);
8b659320 73 if (m == NULL) return (NULL);
4dcdd98e 74 m->ifen_next = nsip_list;
c5d24c39 75 nsip_list = m;
4dcdd98e 76 ifp = &m->ifen_ifnet;
c5d24c39
KS
77
78 ifp->if_name = "nsip";
79 ifp->if_mtu = LOMTU;
80 ifp->if_ioctl = nsipioctl;
81 ifp->if_output = nsipoutput;
4dcdd98e 82 ifp->if_start = nsipstart;
c5d24c39
KS
83 ifp->if_flags = IFF_POINTOPOINT;
84 ifp->if_unit = nsipif.if_unit++;
85 if_attach(ifp);
4dcdd98e
KS
86
87 return (m);
c5d24c39
KS
88}
89
90
91/*
92 * Process an ioctl request.
93 */
94/* ARGSUSED */
95nsipioctl(ifp, cmd, data)
96 register struct ifnet *ifp;
97 int cmd;
98 caddr_t data;
99{
100 int error = 0;
143067e7 101 struct ifreq *ifr;
c5d24c39
KS
102
103 switch (cmd) {
104
105 case SIOCSIFADDR:
106 ifp->if_flags |= IFF_UP;
8b659320
KS
107 /* fall into: */
108
109 case SIOCSIFDSTADDR:
c5d24c39
KS
110 /*
111 * Everything else is done at a higher level.
112 */
113 break;
114
143067e7
KS
115 case SIOCSIFFLAGS:
116 ifr = (struct ifreq *)data;
117 if ((ifr->ifr_flags & IFF_UP) == 0)
118 error = nsip_free(ifp);
119
120
c5d24c39
KS
121 default:
122 error = EINVAL;
123 }
124 return (error);
125}
126
127struct mbuf *nsip_badlen;
128struct mbuf *nsip_lastin;
129int nsip_hold_input;
130
f95f0f6f
MK
131idpip_input(m, ifp)
132 register struct mbuf *m;
133 struct ifnet *ifp;
c5d24c39
KS
134{
135 register struct ip *ip;
136 register struct idp *idp;
c5d24c39
KS
137 register struct ifqueue *ifq = &nsintrq;
138 int len, s;
139
8b659320
KS
140 if (nsip_hold_input) {
141 if (nsip_lastin) {
f97be0c9 142 m_freem(nsip_lastin);
c5d24c39 143 }
4dcdd98e 144 nsip_lastin = m_copym(m, 0, (int)M_COPYALL, M_DONTWAIT);
c5d24c39
KS
145 }
146 /*
147 * Get IP and IDP header together in first mbuf.
148 */
149 nsipif.if_ipackets++;
c5d24c39 150 s = sizeof (struct ip) + sizeof (struct idp);
4dcdd98e 151 if (((m->m_flags & M_EXT) || m->m_len < s) &&
8b659320 152 (m = m_pullup(m, s)) == 0) {
c5d24c39
KS
153 nsipif.if_ierrors++;
154 return;
155 }
156 ip = mtod(m, struct ip *);
f44e4988
MK
157 if (ip->ip_hl > (sizeof (struct ip) >> 2)) {
158 ip_stripoptions(ip, (struct mbuf *)0);
159 if (m->m_len < s) {
8b659320 160 if ((m = m_pullup(m, s)) == 0) {
f44e4988
MK
161 nsipif.if_ierrors++;
162 return;
163 }
164 ip = mtod(m, struct ip *);
165 }
166 }
c5d24c39
KS
167
168 /*
169 * Make mbuf data length reflect IDP length.
170 * If not enough data to reflect IDP length, drop.
171 */
4dcdd98e 172 m->m_data += sizeof (struct ip);
c5d24c39 173 m->m_len -= sizeof (struct ip);
4dcdd98e 174 m->m_pkthdr.len -= sizeof (struct ip);
c5d24c39
KS
175 idp = mtod(m, struct idp *);
176 len = ntohs(idp->idp_len);
f2c50bef 177 if (len & 1) len++; /* Preserve Garbage Byte */
c5d24c39
KS
178 if (ip->ip_len != len) {
179 if (len > ip->ip_len) {
180 nsipif.if_ierrors++;
8b659320 181 if (nsip_badlen) m_freem(nsip_badlen);
c5d24c39
KS
182 nsip_badlen = m;
183 return;
184 }
e56ec4e3 185 /* Any extra will be trimmed off by the NS routines */
c5d24c39 186 }
f95f0f6f
MK
187
188 /*
189 * Place interface pointer before the data
190 * for the receiving protocol.
191 */
4dcdd98e 192 m->m_pkthdr.rcvif = ifp;
c5d24c39
KS
193 /*
194 * Deliver to NS
195 */
196 s = splimp();
197 if (IF_QFULL(ifq)) {
198 IF_DROP(ifq);
f95f0f6f
MK
199bad:
200 m_freem(m);
c5d24c39 201 splx(s);
f97be0c9 202 return;
c5d24c39 203 }
f95f0f6f 204 IF_ENQUEUE(ifq, m);
c5d24c39
KS
205 schednetisr(NETISR_NS);
206 splx(s);
f97be0c9 207 return;
c5d24c39
KS
208}
209
f97be0c9 210/* ARGSUSED */
4dcdd98e 211nsipoutput(ifn, m, dst)
c5d24c39 212 struct ifnet_en *ifn;
4dcdd98e 213 register struct mbuf *m;
c5d24c39
KS
214 struct sockaddr *dst;
215{
216
c5d24c39
KS
217 register struct ip *ip;
218 register struct route *ro = &(ifn->ifen_route);
219 register int len = 0;
4dcdd98e 220 register struct idp *idp = mtod(m, struct idp *);
c5d24c39
KS
221 int error;
222
c5d24c39
KS
223 ifn->ifen_ifnet.if_opackets++;
224 nsipif.if_opackets++;
225
226
227 /*
228 * Calculate data length and make space
229 * for IP header.
230 */
231 len = ntohs(idp->idp_len);
f2c50bef 232 if (len & 1) len++; /* Preserve Garbage Byte */
4dcdd98e
KS
233 /* following clause not necessary on vax */
234 if (3 & (int)m->m_data) {
235 /* force longword alignment of ip hdr */
236 struct mbuf *m0 = m_gethdr(MT_HEADER, M_DONTWAIT);
237 if (m0 == 0) {
238 m_freem(m);
c5d24c39
KS
239 return (ENOBUFS);
240 }
4dcdd98e
KS
241 MH_ALIGN(m0, sizeof (struct ip));
242 m0->m_flags = m->m_flags & M_COPYFLAGS;
243 m0->m_next = m;
244 m0->m_len = sizeof (struct ip);
245 m0->m_pkthdr.len = m0->m_len + m->m_len;
246 m->m_flags &= ~M_PKTHDR;
c5d24c39 247 } else {
4dcdd98e
KS
248 M_PREPEND(m, sizeof (struct ip), M_DONTWAIT);
249 if (m == 0)
250 return (ENOBUFS);
c5d24c39
KS
251 }
252 /*
253 * Fill in IP header.
254 */
255 ip = mtod(m, struct ip *);
256 *(long *)ip = 0;
e56ec4e3 257 ip->ip_p = IPPROTO_IDP;
c5d24c39
KS
258 ip->ip_src = ifn->ifen_src;
259 ip->ip_dst = ifn->ifen_dst;
260 ip->ip_len = (u_short)len + sizeof (struct ip);
261 ip->ip_ttl = MAXTTL;
262
263 /*
264 * Output final datagram.
265 */
266 error = (ip_output(m, (struct mbuf *)0, ro, SO_BROADCAST));
267 if (error) {
268 ifn->ifen_ifnet.if_oerrors++;
269 ifn->ifen_ifnet.if_ierrors = error;
270 }
271 return (error);
272bad:
4dcdd98e 273 m_freem(m);
8b659320 274 return (ENETUNREACH);
c5d24c39
KS
275}
276
4dcdd98e
KS
277nsipstart(ifp)
278struct ifnet *ifp;
279{
280 panic("nsip_start called\n");
281}
282
c5d24c39
KS
283struct ifreq ifr = {"nsip0"};
284
285nsip_route(m)
286 register struct mbuf *m;
287{
288 register struct nsip_req *rq = mtod(m, struct nsip_req *);
289 struct sockaddr_ns *ns_dst = (struct sockaddr_ns *)&rq->rq_ns;
290 struct sockaddr_in *ip_dst = (struct sockaddr_in *)&rq->rq_ip;
c5d24c39
KS
291 struct route ro;
292 struct ifnet_en *ifn;
c5d24c39 293 struct sockaddr_in *src;
8b659320
KS
294
295 /*
296 * First, make sure we already have an ns address:
297 */
298 if (ns_hosteqnh(ns_thishost, ns_zerohost))
299 return (EADDRNOTAVAIL);
c5d24c39 300 /*
8b659320 301 * Now, determine if we can get to the destination
c5d24c39
KS
302 */
303 bzero((caddr_t)&ro, sizeof (ro));
304 ro.ro_dst = *(struct sockaddr *)ip_dst;
c5d24c39 305 rtalloc(&ro);
f97be0c9 306 if (ro.ro_rt == 0 || ro.ro_rt->rt_ifp == 0) {
c5d24c39
KS
307 return (ENETUNREACH);
308 }
8b659320 309
c5d24c39
KS
310 /*
311 * And see how he's going to get back to us:
8b659320 312 * i.e., what return ip address do we use?
c5d24c39
KS
313 */
314 {
315 register struct in_ifaddr *ia;
316 struct ifnet *ifp = ro.ro_rt->rt_ifp;
317
318 for (ia = in_ifaddr; ia; ia = ia->ia_next)
319 if (ia->ia_ifp == ifp)
320 break;
321 if (ia == 0)
322 ia = in_ifaddr;
323 if (ia == 0) {
8b659320 324 RTFREE(ro.ro_rt);
c5d24c39
KS
325 return (EADDRNOTAVAIL);
326 }
327 src = (struct sockaddr_in *)&ia->ia_addr;
328 }
8b659320 329
c5d24c39 330 /*
143067e7 331 * Is there a free (pseudo-)interface or space?
c5d24c39 332 */
4dcdd98e
KS
333 for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) {
334 if ((ifn->ifen_ifnet.if_flags & IFF_UP) == 0)
143067e7
KS
335 break;
336 }
4dcdd98e
KS
337 if (ifn == NULL)
338 ifn = nsipattach();
339 if (ifn == NULL) {
8b659320
KS
340 RTFREE(ro.ro_rt);
341 return (ENOBUFS);
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{
143067e7
KS
404 register struct ifnet_en *ifn;
405
4dcdd98e 406 for (ifn = nsip_list; ifn; ifn = ifn->ifen_next) {
143067e7
KS
407 if (ifn->ifen_dst.s_addr == dst->s_addr &&
408 ifn->ifen_route.ro_rt) {
409 RTFREE(ifn->ifen_route.ro_rt);
410 ifn->ifen_route.ro_rt = 0;
411 }
f6188621 412 }
143067e7 413}
c5d24c39 414#endif