This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sys / netiso / if_eon.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1991 The 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 *
43371f85 33 * from: @(#)if_eon.c 7.16 (Berkeley) 6/27/91
fde1aeb2 34 * $Id: if_eon.c,v 1.4 1993/11/25 01:35:54 wollman Exp $
15637ed4
RG
35 */
36
37/***********************************************************
38 Copyright IBM Corporation 1987
39
40 All Rights Reserved
41
42Permission to use, copy, modify, and distribute this software and its
43documentation for any purpose and without fee is hereby granted,
44provided that the above copyright notice appear in all copies and that
45both that copyright notice and this permission notice appear in
46supporting documentation, and that the name of IBM not be
47used in advertising or publicity pertaining to distribution of the
48software without specific, written prior permission.
49
50IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
51ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
52IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
53ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
54WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
55ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
56SOFTWARE.
57
58******************************************************************/
59
60/*
61 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
62 */
43371f85 63
15637ed4 64/*
15637ed4
RG
65 * EON rfc
66 * Layer between IP and CLNL
67 *
68 * TODO:
69 * Put together a current rfc986 address format and get the right offset
70 * for the nsel
71 */
72
73#ifdef EON
74#define NEON 1
75
76
77#include "param.h"
78#include "systm.h"
79#include "types.h"
80#include "mbuf.h"
81#include "buf.h"
82#include "protosw.h"
83#include "socket.h"
84#include "ioctl.h"
85#include "errno.h"
86#include "types.h"
87
88#include "../net/if.h"
89#include "../net/if_types.h"
90#include "../net/if_dl.h"
91#include "../net/netisr.h"
92#include "../net/route.h"
93#include "machine/mtpr.h"
94
95#include "../netinet/in.h"
96#include "../netinet/in_systm.h"
97#include "../netinet/in_var.h"
98#include "../netinet/ip.h"
99#include "../netinet/ip_var.h"
100#include "../netinet/if_ether.h"
101
102#include "iso.h"
103#include "iso_var.h"
104#include "iso_snpac.h"
105#include "argo_debug.h"
106#include "iso_errno.h"
107#include "eonvar.h"
108extern struct timeval time;
109extern struct ifnet loif;
110
8ace4366
GW
111struct eon_stat eonstat;
112
15637ed4
RG
113#define EOK 0
114
4c45483e
GW
115void eoninput(struct mbuf *, int);
116static int eonoutput(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *);
117static int eonioctl(struct ifnet *, int, caddr_t);
118static void eonattach(void);
119static void eoninit(int);
120static void eonrtrequest(int, struct rtentry *, struct sockaddr *);
15637ed4
RG
121extern int ip_output();
122struct ifnet eonif[1];
123
4c45483e 124void
15637ed4
RG
125eonprotoinit() {
126 (void) eonattach();
127}
128
129struct eon_llinfo eon_llinfo;
130#define PROBE_OK 0;
131
132
133/*
134 * FUNCTION: eonattach
135 *
136 * PURPOSE: autoconf attach routine
137 *
138 * RETURNS: void
139 */
140
4c45483e 141void
15637ed4
RG
142eonattach()
143{
144 register struct ifnet *ifp = eonif;
145
146 IFDEBUG(D_EON)
147 printf("eonattach()\n");
148 ENDDEBUG
149 ifp->if_unit = 0;
150 ifp->if_name = "eon";
151 ifp->if_mtu = ETHERMTU;
152 /* since everything will go out over ether or token ring */
153
154 ifp->if_init = eoninit;
155 ifp->if_ioctl = eonioctl;
156 ifp->if_output = eonoutput;
157 ifp->if_type = IFT_EON;
158 ifp->if_addrlen = 5;
159 ifp->if_hdrlen = EONIPLEN;
160 ifp->if_flags = IFF_BROADCAST;
161 if_attach(ifp);
162 eonioctl(ifp, SIOCSIFADDR, (caddr_t)ifp->if_addrlist);
163 eon_llinfo.el_qhdr.link =
164 eon_llinfo.el_qhdr.rlink = &(eon_llinfo.el_qhdr);
165
166 IFDEBUG(D_EON)
167 printf("eonattach()\n");
168 ENDDEBUG
169}
170
171
172/*
173 * FUNCTION: eonioctl
174 *
175 * PURPOSE: io controls - ifconfig
176 * need commands to
177 * link-UP (core addr) (flags: ES, IS)
178 * link-DOWN (core addr) (flags: ES, IS)
179 * must be callable from kernel or user
180 *
181 * RETURNS: nothing
182 */
4c45483e 183int
15637ed4
RG
184eonioctl(ifp, cmd, data)
185 register struct ifnet *ifp;
186 int cmd;
187 register caddr_t data;
188{
189 int s = splimp();
190 register int error = 0;
191
192 IFDEBUG(D_EON)
193 printf("eonioctl (cmd 0x%x) \n", cmd);
194 ENDDEBUG
195
196 switch (cmd) {
197 register struct ifaddr *ifa;
198
199 case SIOCSIFADDR:
200 if (ifa = (struct ifaddr *)data) {
201 ifp->if_flags |= IFF_UP;
202 if (ifa->ifa_addr->sa_family != AF_LINK)
203 ifa->ifa_rtrequest = eonrtrequest;
204 ifa->ifa_llinfolen = sizeof(struct eon_llinfo);
205 }
206 break;
207 }
208 splx(s);
209 return(error);
210}
211
4c45483e 212void
15637ed4 213eoniphdr(hdr, loc, ro, class, zero)
4c45483e
GW
214 struct route *ro;
215 register struct eon_iphdr *hdr;
216 caddr_t loc;
217 int class;
218 int zero;
15637ed4
RG
219{
220 struct mbuf mhead;
221 register struct sockaddr_in *sin = (struct sockaddr_in *)&ro->ro_dst;
222 if (zero) {
223 bzero((caddr_t)hdr, sizeof (*hdr));
224 bzero((caddr_t)ro, sizeof (*ro));
225 }
226 sin->sin_family = AF_INET;
227 sin->sin_len = sizeof (*sin);
228 bcopy(loc, (caddr_t)&sin->sin_addr, sizeof(struct in_addr));
229 /*
230 * If there is a cached route,
231 * check that it is to the same destination
232 * and is still up. If not, free it and try again.
233 */
234 if (ro->ro_rt) {
235 struct sockaddr_in *dst =
236 (struct sockaddr_in *)rt_key(ro->ro_rt);
237 if ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
238 sin->sin_addr.s_addr != dst->sin_addr.s_addr) {
239 RTFREE(ro->ro_rt);
240 ro->ro_rt = (struct rtentry *)0;
241 }
242 }
243 rtalloc(ro);
244 if (ro->ro_rt)
245 ro->ro_rt->rt_use++;
246 hdr->ei_ip.ip_dst = sin->sin_addr;
247 hdr->ei_ip.ip_p = IPPROTO_EON;
248 hdr->ei_ip.ip_ttl = MAXTTL;
249 hdr->ei_eh.eonh_class = class;
250 hdr->ei_eh.eonh_vers = EON_VERSION;
251 hdr->ei_eh.eonh_csum = 0;
252 mhead.m_data = (caddr_t) &hdr->ei_eh;
253 mhead.m_len = sizeof(struct eon_hdr);
254 mhead.m_next = 0;
255 IFDEBUG(D_EON)
256 printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n",
257 &mhead,
258 _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
259 ENDDEBUG
260 iso_gen_csum(&mhead,
261 _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
262}
263/*
264 * FUNCTION: eonrtrequest
265 *
266 * PURPOSE: maintains list of direct eon recipients.
267 * sets up IP route for rest.
268 *
269 * RETURNS: nothing
270 */
4c45483e 271void
15637ed4 272eonrtrequest(cmd, rt, gate)
4c45483e
GW
273 int cmd;
274 register struct rtentry *rt;
275 register struct sockaddr *gate;
15637ed4
RG
276{
277 unsigned long zerodst = 0;
278 caddr_t ipaddrloc = (caddr_t) &zerodst;
279 register struct eon_llinfo *el = (struct eon_llinfo *)rt->rt_llinfo;
280
281 /*
282 * Common Housekeeping
283 */
284 switch (cmd) {
285 case RTM_DELETE:
286 if (el) {
287 remque(&(el->el_qhdr));
288 if (el->el_iproute.ro_rt)
289 RTFREE(el->el_iproute.ro_rt);
290 Free(el);
291 rt->rt_llinfo = 0;
292 }
293 return;
294
295 case RTM_ADD:
296 case RTM_RESOLVE:
297 rt->rt_rmx.rmx_mtu = loif.if_mtu; /* unless better below */
298 R_Malloc(el, struct eon_llinfo *, sizeof(*el));
299 rt->rt_llinfo = (caddr_t)el;
300 if (el == 0)
301 return;
302 Bzero(el, sizeof(*el));
303 insque(&(el->el_qhdr), &eon_llinfo.el_qhdr);
304 el->el_rt = rt;
305 break;
306 }
307 if (gate || (gate = rt->rt_gateway)) switch (gate->sa_family) {
308 case AF_LINK:
309#define SDL(x) ((struct sockaddr_dl *)x)
310 if (SDL(gate)->sdl_alen = 1)
311 el->el_snpaoffset = *(u_char *)LLADDR(SDL(gate));
312 else
313 ipaddrloc = LLADDR(SDL(gate));
314 break;
315 case AF_INET:
316#define SIN(x) ((struct sockaddr_in *)x)
317 ipaddrloc = (caddr_t) &SIN(gate)->sin_addr;
318 break;
319 default:
320 return;
321 }
322 el->el_flags |= RTF_UP;
323 eoniphdr(&el->el_ei, ipaddrloc, &el->el_iproute, EON_NORMAL_ADDR, 0);
324 if (el->el_iproute.ro_rt)
325 rt->rt_rmx.rmx_mtu = el->el_iproute.ro_rt->rt_rmx.rmx_mtu
326 - sizeof(el->el_ei);
327}
328
329/*
330 * FUNCTION: eoninit
331 *
332 * PURPOSE: initialization
333 *
334 * RETURNS: nothing
335 */
336
4c45483e 337void
15637ed4
RG
338eoninit(unit)
339 int unit;
340{
341 printf("eon driver-init eon%d\n", unit);
342}
343
344
345/*
346 * FUNCTION: eonoutput
347 *
348 * PURPOSE: prepend an eon header and hand to IP
349 * ARGUMENTS: (ifp) is points to the ifnet structure for this unit/device
350 * (m) is an mbuf *, *m is a CLNL packet
351 * (dst) is a destination address - have to interp. as
352 * multicast or broadcast or real address.
353 *
354 * RETURNS: unix error code
355 *
356 * NOTES:
357 *
358 */
4c45483e
GW
359int
360eonoutput(ifp, m, xdst, rt)
15637ed4
RG
361 struct ifnet *ifp;
362 register struct mbuf *m; /* packet */
4c45483e 363 struct sockaddr *xdst;
15637ed4
RG
364 struct rtentry *rt;
365{
4c45483e 366 struct sockaddr_iso *dst = (struct sockaddr_iso *)xdst;
15637ed4
RG
367 register struct eon_llinfo *el;
368 register struct eon_iphdr *ei;
369 struct route *ro;
370 int datalen;
371 struct mbuf *mh;
372 int error = 0, class = 0, alen = 0;
4c45483e 373 caddr_t ipaddrloc = 0;
15637ed4
RG
374 static struct eon_iphdr eon_iphdr;
375 static struct route route;
376
377 IFDEBUG(D_EON)
378 printf("eonoutput \n" );
379 ENDDEBUG
380
381 ifp->if_lastchange = time;
382 ifp->if_opackets++;
383 if (rt == 0 || (el = (struct eon_llinfo *)rt->rt_llinfo) == 0) {
384 if (dst->siso_family == AF_LINK) {
385 register struct sockaddr_dl *sdl = (struct sockaddr_dl *)dst;
386
387 ipaddrloc = LLADDR(sdl);
388 alen = sdl->sdl_alen;
389 } else if (dst->siso_family == AF_ISO && dst->siso_data[0] == AFI_SNA) {
390 alen = dst->siso_nlen - 1;
391 ipaddrloc = (caddr_t) dst->siso_data + 1;
392 }
393 switch (alen) {
394 case 5:
395 class = 4[(u_char *)ipaddrloc];
396 case 4:
397 ro = &route;
398 ei = &eon_iphdr;
399 eoniphdr(ei, ipaddrloc, ro, class, 1);
400 goto send;
401 }
402einval:
403 error = EINVAL;
404 goto flush;
405 }
406 if ((el->el_flags & RTF_UP) == 0) {
407 eonrtrequest(RTM_CHANGE, rt, (struct sockaddr *)0);
408 if ((el->el_flags & RTF_UP) == 0) {
409 error = EHOSTUNREACH;
410 goto flush;
411 }
412 }
413 if ((m->m_flags & M_PKTHDR) == 0) {
414 printf("eon: got non headered packet\n");
415 goto einval;
416 }
417 ei = &el->el_ei;
418 ro = &el->el_iproute;
419 if (el->el_snpaoffset) {
420 if (dst->siso_family == AF_ISO) {
421 bcopy((caddr_t) &dst->siso_data[el->el_snpaoffset],
422 (caddr_t) &ei->ei_ip.ip_dst, sizeof(ei->ei_ip.ip_dst));
423 } else
424 goto einval;
425 }
426send:
427 /* put an eon_hdr in the buffer, prepended by an ip header */
428 datalen = m->m_pkthdr.len + EONIPLEN;
429 MGETHDR(mh, M_DONTWAIT, MT_HEADER);
430 if(mh == (struct mbuf *)0)
431 goto flush;
432 mh->m_next = m;
433 m = mh;
434 MH_ALIGN(m, sizeof(struct eon_iphdr));
435 m->m_len = sizeof(struct eon_iphdr);
436 ifp->if_obytes +=
437 (ei->ei_ip.ip_len = (u_short)(m->m_pkthdr.len = datalen));
438 *mtod(m, struct eon_iphdr *) = *ei;
439
440 IFDEBUG(D_EON)
441 printf("eonoutput dst ip addr : %x\n", ei->ei_ip.ip_dst.s_addr);
442 printf("eonoutput ip_output : eonip header:\n");
443 dump_buf(ei, sizeof(struct eon_iphdr));
444 ENDDEBUG
445
446 error = ip_output(m, (struct mbuf *)0, ro, 0);
447 m = 0;
448 if (error) {
449 ifp->if_oerrors++;
450 ifp->if_opackets--;
451 ifp->if_obytes -= datalen;
452 }
453flush:
454 if (m)
455 m_freem(m);
456 return error;
457}
458
4c45483e 459void
15637ed4
RG
460eoninput(m, iphlen)
461 register struct mbuf *m;
462 int iphlen;
463{
464 register struct eon_hdr *eonhdr;
465 register struct ip *iphdr;
466 struct ifnet *eonifp;
467 int s;
468
469 eonifp = &eonif[0]; /* kludge - really want to give CLNP
470 * the ifp for eon, not for the real device
471 */
472
473 IFDEBUG(D_EON)
474 printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n",
475 m, m?m->m_data:0, m?m->m_len:0);
476 ENDDEBUG
477
478 if (m == 0)
479 return;
480 if (iphlen > sizeof (struct ip))
481 ip_stripoptions(m, (struct mbuf *)0);
482 if (m->m_len < EONIPLEN) {
483 if ((m = m_pullup(m, EONIPLEN)) == 0) {
484 IncStat(es_badhdr);
485drop:
486 IFDEBUG(D_EON)
487 printf("eoninput: DROP \n" );
488 ENDDEBUG
489 eonifp->if_ierrors ++;
490 m_freem(m);
491 return;
492 }
493 }
494 eonif->if_ibytes += m->m_pkthdr.len;
495 eonif->if_lastchange = time;
496 iphdr = mtod(m, struct ip *);
497 /* do a few checks for debugging */
498 if( iphdr->ip_p != IPPROTO_EON ) {
499 IncStat(es_badhdr);
500 goto drop;
501 }
502 /* temporarily drop ip header from the mbuf */
503 m->m_data += sizeof(struct ip);
504 eonhdr = mtod(m, struct eon_hdr *);
505 if( iso_check_csum( m, sizeof(struct eon_hdr) ) != EOK ) {
506 IncStat(es_badcsum);
507 goto drop;
508 }
509 m->m_data -= sizeof(struct ip);
510
511 IFDEBUG(D_EON)
512 printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class );
513 printf("eoninput: eon header:\n");
514 dump_buf(eonhdr, sizeof(struct eon_hdr));
515 ENDDEBUG
516
517 /* checks for debugging */
518 if( eonhdr->eonh_vers != EON_VERSION) {
519 IncStat(es_badhdr);
520 goto drop;
521 }
522 m->m_flags &= ~(M_BCAST|M_MCAST);
523 switch( eonhdr->eonh_class) {
524 case EON_BROADCAST:
525 IncStat(es_in_broad);
526 m->m_flags |= M_BCAST;
527 break;
528 case EON_NORMAL_ADDR:
529 IncStat(es_in_normal);
530 break;
531 case EON_MULTICAST_ES:
532 IncStat(es_in_multi_es);
533 m->m_flags |= M_MCAST;
534 break;
535 case EON_MULTICAST_IS:
536 IncStat(es_in_multi_is);
537 m->m_flags |= M_MCAST;
538 break;
539 }
540 eonifp->if_ipackets++;
541
542 {
543 /* put it on the CLNP queue and set soft interrupt */
544 struct ifqueue *ifq;
545 extern struct ifqueue clnlintrq;
546
547 m->m_pkthdr.rcvif = eonifp; /* KLUDGE */
548 IFDEBUG(D_EON)
549 printf("eoninput to clnl IFQ\n");
550 ENDDEBUG
551 ifq = &clnlintrq;
552 s = splimp();
553 if (IF_QFULL(ifq)) {
554 IF_DROP(ifq);
555 m_freem(m);
556 eonifp->if_iqdrops++;
557 eonifp->if_ipackets--;
558 splx(s);
559 return;
560 }
561 IF_ENQUEUE(ifq, m);
562 IFDEBUG(D_EON)
563 printf(
564 "0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n",
565 m, m->m_len, m->m_type, m->m_data);
566 dump_buf(mtod(m, caddr_t), m->m_len);
567 ENDDEBUG
568 schednetisr(NETISR_ISO);
569 splx(s);
570 }
571}
572
573int
574eonctlinput(cmd, sin)
575 int cmd;
576 struct sockaddr_in *sin;
577{
578 extern u_char inetctlerrmap[];
579
580 IFDEBUG(D_EON)
581 printf("eonctlinput: cmd 0x%x addr: ", cmd);
fde1aeb2 582 dump_isoaddr((struct sockaddr_iso *)sin);
15637ed4
RG
583 printf("\n");
584 ENDDEBUG
585
586 if (cmd < 0 || cmd > PRC_NCMDS)
587 return 0;
588
589 IncStat(es_icmp[cmd]);
590 switch (cmd) {
591
592 case PRC_QUENCH:
593 case PRC_QUENCH2:
594 /* TODO: set the dec bit */
595 break;
596 case PRC_TIMXCEED_REASS:
597 case PRC_ROUTEDEAD:
598 case PRC_HOSTUNREACH:
599 case PRC_UNREACH_NET:
600 case PRC_IFDOWN:
601 case PRC_UNREACH_HOST:
602 case PRC_HOSTDEAD:
603 case PRC_TIMXCEED_INTRANS:
604 /* TODO: mark the link down */
605 break;
606
607 case PRC_UNREACH_PROTOCOL:
608 case PRC_UNREACH_PORT:
609 case PRC_UNREACH_SRCFAIL:
610 case PRC_REDIRECT_NET:
611 case PRC_REDIRECT_HOST:
612 case PRC_REDIRECT_TOSNET:
613 case PRC_REDIRECT_TOSHOST:
614 case PRC_MSGSIZE:
615 case PRC_PARAMPROB:
616 /* printf("eonctlinput: ICMP cmd 0x%x\n", cmd );*/
617 break;
618 }
619 return 0;
620}
621
622#endif