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