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