No empty .Rs/.Re
[netbsd-mini2440.git] / sys / netiso / if_eon.c
blob089044dc8d7e77e50c5f6c70ed260e0d9040eae2
1 /* $NetBSD: if_eon.c,v 1.68 2008/10/24 17:07:33 dyoung Exp $ */
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
31 * @(#)if_eon.c 8.2 (Berkeley) 1/9/95
34 /***********************************************************
35 Copyright IBM Corporation 1987
37 All Rights Reserved
39 Permission to use, copy, modify, and distribute this software and its
40 documentation for any purpose and without fee is hereby granted,
41 provided that the above copyright notice appear in all copies and that
42 both that copyright notice and this permission notice appear in
43 supporting documentation, and that the name of IBM not be
44 used in advertising or publicity pertaining to distribution of the
45 software without specific, written prior permission.
47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53 SOFTWARE.
55 ******************************************************************/
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
61 * EON rfc
62 * Layer between IP and CLNL
64 * TODO:
65 * Put together a current rfc986 address format and get the right offset
66 * for the nsel
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: if_eon.c,v 1.68 2008/10/24 17:07:33 dyoung Exp $");
72 #include "opt_eon.h"
74 #ifdef EON
75 #define NEON 1
78 #include <sys/param.h>
79 #include <sys/systm.h>
80 #include <sys/mbuf.h>
81 #include <sys/buf.h>
82 #include <sys/protosw.h>
83 #include <sys/socket.h>
84 #include <sys/ioctl.h>
85 #include <sys/errno.h>
87 #include <sys/cpu.h> /* XXX for setsoftnet(). This must die. */
89 #include <net/if.h>
90 #include <net/if_types.h>
91 #include <net/if_dl.h>
92 #include <net/netisr.h>
93 #include <net/route.h>
95 #include <net/if_ether.h>
97 #include <netinet/in.h>
98 #include <netinet/in_systm.h>
99 #include <netinet/in_var.h>
100 #include <netinet/ip.h>
101 #include <netinet/ip_var.h>
103 #include <netiso/iso.h>
104 #include <netiso/iso_var.h>
105 #include <netiso/iso_snpac.h>
106 #include <netiso/argo_debug.h>
107 #include <netiso/iso_errno.h>
108 #include <netiso/eonvar.h>
110 #include <machine/stdarg.h>
112 #define EOK 0
114 struct ifnet eonif[1];
116 void
117 eonprotoinit(void)
119 (void) eonattach();
122 struct eon_llinfo eon_llinfo;
123 #define PROBE_OK 0;
127 * FUNCTION: eonattach
129 * PURPOSE: autoconf attach routine
131 * RETURNS: void
134 void
135 eonattach(void)
137 struct ifnet *ifp = eonif;
139 #ifdef ARGO_DEBUG
140 if (argo_debug[D_EON]) {
141 printf("eonattach()\n");
143 #endif
144 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "eon%d", 0);
145 ifp->if_mtu = ETHERMTU;
146 ifp->if_softc = NULL;
147 /* since everything will go out over ether or token ring */
149 ifp->if_ioctl = eonioctl;
150 ifp->if_output = eonoutput;
151 ifp->if_type = IFT_EON;
152 ifp->if_addrlen = 0;
153 ifp->if_hdrlen = EONIPLEN;
154 ifp->if_flags = IFF_BROADCAST;
155 if_attach(ifp);
156 if_alloc_sadl(ifp);
157 eonioctl(ifp, SIOCINITIFADDR, ifp->if_dl);
158 eon_llinfo.el_qhdr.link =
159 eon_llinfo.el_qhdr.rlink = &(eon_llinfo.el_qhdr);
161 #ifdef ARGO_DEBUG
162 if (argo_debug[D_EON]) {
163 printf("eonattach()\n");
165 #endif
170 * FUNCTION: eonioctl
172 * PURPOSE: io controls - ifconfig
173 * need commands to
174 * link-UP (core addr) (flags: ES, IS)
175 * link-DOWN (core addr) (flags: ES, IS)
176 * must be callable from kernel or user
178 * RETURNS: nothing
181 eonioctl(struct ifnet *ifp, u_long cmd, void *data)
183 struct ifaddr *ifa = data;
184 int error = 0, s = splnet();
186 #ifdef ARGO_DEBUG
187 if (argo_debug[D_EON]) {
188 printf("eonioctl (cmd 0x%lx) \n", cmd);
190 #endif
192 switch (cmd) {
193 case SIOCINITIFADDR:
194 if (ifa == NULL)
195 break;
196 ifp->if_flags |= IFF_UP;
197 if (ifa->ifa_addr->sa_family != AF_LINK)
198 ifa->ifa_rtrequest = eonrtrequest;
199 break;
200 default:
201 error = ifioctl_common(ifp, cmd, data);
202 break;
204 splx(s);
205 return (error);
209 void
210 eoniphdr(struct eon_iphdr *hdr, const void *loc, struct route *ro, int class)
212 struct rtentry *rt;
213 struct mbuf mhead;
214 union {
215 struct sockaddr dst;
216 struct sockaddr_in dst4;
217 } u;
218 struct in_addr addr;
220 (void)memcpy(&addr, loc, sizeof(addr));
221 sockaddr_in_init(&u.dst4, &addr, 0);
222 rtcache_setdst(ro, &u.dst);
224 if ((rt = rtcache_init(ro)) != NULL)
225 rt->rt_use++;
226 hdr->ei_ip.ip_dst = u.dst4.sin_addr;
227 hdr->ei_ip.ip_p = IPPROTO_EON;
228 hdr->ei_ip.ip_ttl = MAXTTL;
229 hdr->ei_eh.eonh_class = class;
230 hdr->ei_eh.eonh_vers = EON_VERSION;
231 hdr->ei_eh.eonh_csum = 0;
232 mhead.m_data = (void *)&hdr->ei_eh;
233 mhead.m_len = sizeof(struct eon_hdr);
234 mhead.m_next = NULL;
235 #ifdef ARGO_DEBUG
236 if (argo_debug[D_EON]) {
237 printf("eonoutput : gen csum (%p, offset %lu, datalen %ld)\n",
238 &mhead, (unsigned long)offsetof(struct eon_hdr, eonh_csum),
239 (long)sizeof(struct eon_hdr));
241 #endif
242 iso_gen_csum(&mhead,
243 offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr));
246 * FUNCTION: eonrtrequest
248 * PURPOSE: maintains list of direct eon recipients.
249 * sets up IP route for rest.
251 * RETURNS: nothing
253 void
254 eonrtrequest(int cmd, struct rtentry *rt, const struct rt_addrinfo *info)
256 struct rtentry *nrt;
257 unsigned long zerodst = 0;
258 const void *ipaddrloc = &zerodst;
259 struct eon_llinfo *el = (struct eon_llinfo *) rt->rt_llinfo;
260 const struct sockaddr *gate;
263 * Common Housekeeping
265 switch (cmd) {
266 case RTM_DELETE:
267 if (el) {
268 iso_remque(&el->el_qhdr);
269 rtcache_free(&el->el_iproute);
270 Free(el);
271 rt->rt_llinfo = NULL;
273 return;
275 case RTM_ADD:
276 case RTM_RESOLVE:
277 rt->rt_rmx.rmx_mtu = lo0ifp->if_mtu; /* unless better below */
278 R_Malloc(el, struct eon_llinfo *, sizeof(*el));
279 rt->rt_llinfo = (void *) el;
280 if (el == NULL)
281 return;
282 memset(el, 0, sizeof(*el));
283 iso_insque(&el->el_qhdr, &eon_llinfo.el_qhdr);
284 el->el_rt = rt;
285 break;
287 if (info != NULL &&
288 (gate = info->rti_info[RTAX_GATEWAY]) != NULL) { /*XXX*/
289 switch (gate->sa_family) {
290 case AF_LINK:
291 if (satocsdl(gate)->sdl_alen == 1)
292 el->el_snpaoffset = *(const u_char *)CLLADDR(satocsdl(gate));
293 else
294 ipaddrloc = CLLADDR(satocsdl(gate));
295 break;
296 case AF_INET:
297 ipaddrloc = &satocsin(gate)->sin_addr;
298 break;
299 default:
300 return;
303 el->el_flags |= RTF_UP;
304 eoniphdr(&el->el_ei, ipaddrloc, &el->el_iproute, EON_NORMAL_ADDR);
305 if ((nrt = rtcache_validate(&el->el_iproute)) != NULL)
306 rt->rt_rmx.rmx_mtu = nrt->rt_rmx.rmx_mtu - sizeof(el->el_ei);
310 * FUNCTION: eonoutput
312 * PURPOSE: prepend an eon header and hand to IP
313 * ARGUMENTS: (ifp) is points to the ifnet structure for this
314 * unit/device (m) is an mbuf *, *m is a CLNL packet
315 * (dst) is a destination address - have to interp. as
316 * multicast or broadcast or real address.
318 * RETURNS: unix error code
320 * NOTES:
324 eonoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sdst,
325 struct rtentry *rt)
327 const struct sockaddr_iso *dst = (const struct sockaddr_iso *)sdst;
328 struct eon_llinfo *el;
329 struct eon_iphdr *ei;
330 struct route *ro;
331 int datalen;
332 struct mbuf *mh;
333 int error = 0, class = 0, alen = 0;
334 const u_char *ipaddrloc = NULL;
335 static struct eon_iphdr eon_iphdr;
336 static struct route route;
338 #ifdef ARGO_DEBUG
339 if (argo_debug[D_EON]) {
340 printf("eonoutput \n");
342 #endif
344 ifp->if_opackets++;
345 if (rt == NULL || (el = (struct eon_llinfo *)rt->rt_llinfo) == NULL) {
346 if (dst->siso_family == AF_LINK) {
347 const struct sockaddr_dl *sdl = satocsdl(dst);
349 ipaddrloc = CLLADDR(sdl);
350 alen = sdl->sdl_alen;
351 } else if (dst->siso_family == AF_ISO &&
352 dst->siso_data[0] == AFI_SNA) {
353 alen = dst->siso_nlen - 1;
354 ipaddrloc = (const char *)dst->siso_data + 1;
356 switch (alen) {
357 case 5:
358 class = ipaddrloc[4];
359 case 4:
360 ro = &route;
361 ei = &eon_iphdr;
362 memset(ei, 0, sizeof(*ei));
363 eoniphdr(ei, ipaddrloc, ro, class);
364 goto send;
366 einval:
367 error = EINVAL;
368 goto flush;
370 if ((el->el_flags & RTF_UP) == 0) {
371 eonrtrequest(RTM_CHANGE, rt, NULL);
372 if ((el->el_flags & RTF_UP) == 0) {
373 error = EHOSTUNREACH;
374 goto flush;
377 if ((m->m_flags & M_PKTHDR) == 0) {
378 printf("eon: got non headered packet\n");
379 goto einval;
381 ei = &el->el_ei;
382 ro = &el->el_iproute;
383 if (el->el_snpaoffset == 0)
385 else if (dst->siso_family == AF_ISO) {
386 memcpy(&ei->ei_ip.ip_dst, &dst->siso_data[el->el_snpaoffset],
387 sizeof(ei->ei_ip.ip_dst));
388 } else
389 goto einval;
390 send:
391 /* put an eon_hdr in the buffer, prepended by an ip header */
392 datalen = m->m_pkthdr.len + EONIPLEN;
393 if (datalen > IP_MAXPACKET) {
394 error = EMSGSIZE;
395 goto flush;
397 MGETHDR(mh, M_DONTWAIT, MT_HEADER);
398 if (mh == NULL) {
399 error = ENOBUFS;
400 goto flush;
402 mh->m_next = m;
403 m = mh;
404 MH_ALIGN(m, sizeof(struct eon_iphdr));
405 m->m_len = sizeof(struct eon_iphdr);
406 m->m_pkthdr.len = datalen;
407 ei->ei_ip.ip_len = htons(datalen);
408 ifp->if_obytes += datalen;
409 *mtod(m, struct eon_iphdr *) = *ei;
411 #ifdef ARGO_DEBUG
412 if (argo_debug[D_EON]) {
413 printf("eonoutput dst ip addr : %x\n", ei->ei_ip.ip_dst.s_addr);
414 printf("eonoutput ip_output : eonip header:\n");
415 dump_buf(ei, sizeof(struct eon_iphdr));
417 #endif
419 error = ip_output(m, NULL, ro, 0, NULL, NULL);
420 m = NULL;
421 if (error) {
422 ifp->if_oerrors++;
423 ifp->if_opackets--;
424 ifp->if_obytes -= datalen;
426 flush:
427 if (m != NULL)
428 m_freem(m);
429 return error;
433 * Strip out IP options, at higher
434 * level protocol in the kernel.
436 static void
437 ip_stripoptions(struct mbuf *m)
439 struct ip *ip = mtod(m, struct ip *);
440 void *opts;
441 size_t olen;
443 olen = (ip->ip_hl << 2) - sizeof(struct ip);
444 opts = (void *)(ip + 1);
445 ip->ip_len = htons(ntohs(ip->ip_len) - olen);
446 ip->ip_hl = sizeof(struct ip) >> 2;
447 memmove((char *)ip + olen, ip, (size_t)olen);
448 m_adj(m, olen);
451 void
452 eoninput(struct mbuf *m, ...)
454 int iphlen;
455 struct eon_hdr *eonhdr;
456 struct ip *iphdr;
457 struct ifnet *eonifp;
458 int s;
459 va_list ap;
461 va_start(ap, m);
462 iphlen = va_arg(ap, int);
463 va_end(ap);
465 eonifp = &eonif[0]; /* kludge - really want to give CLNP the ifp
466 * for eon, not for the real device */
468 #ifdef ARGO_DEBUG
469 if (argo_debug[D_EON]) {
470 printf("eoninput() %p m_data %p m_len 0x%x dequeued\n",
471 m, (m ? m->m_data : 0), m ? m->m_len : 0);
473 #endif
475 if (m == NULL)
476 return;
477 if (iphlen > sizeof(struct ip))
478 ip_stripoptions(m);
479 if (m->m_len < EONIPLEN) {
480 if ((m = m_pullup(m, EONIPLEN)) == NULL) {
481 IncStat(es_badhdr);
482 drop:
483 #ifdef ARGO_DEBUG
484 if (argo_debug[D_EON]) {
485 printf("eoninput: DROP \n");
487 #endif
488 eonifp->if_ierrors++;
489 m_freem(m);
490 return;
493 eonif->if_ibytes += m->m_pkthdr.len;
494 iphdr = mtod(m, struct ip *);
495 /* do a few checks for debugging */
496 if (iphdr->ip_p != IPPROTO_EON) {
497 IncStat(es_badhdr);
498 goto drop;
500 /* temporarily drop ip header from the mbuf */
501 m->m_data += sizeof(struct ip);
502 eonhdr = mtod(m, struct eon_hdr *);
503 if (iso_check_csum(m, sizeof(struct eon_hdr)) != EOK) {
504 IncStat(es_badcsum);
505 goto drop;
507 m->m_data -= sizeof(struct ip);
509 #ifdef ARGO_DEBUG
510 if (argo_debug[D_EON]) {
511 printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class);
512 printf("eoninput: eon header:\n");
513 dump_buf(eonhdr, sizeof(struct eon_hdr));
515 #endif
517 /* checks for debugging */
518 if (eonhdr->eonh_vers != EON_VERSION) {
519 IncStat(es_badhdr);
520 goto drop;
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;
540 eonifp->if_ipackets++;
543 /* put it on the CLNP queue and set soft interrupt */
544 struct ifqueue *ifq;
545 extern struct ifqueue clnlintrq;
547 m->m_pkthdr.rcvif = eonifp; /* KLUDGE */
548 #ifdef ARGO_DEBUG
549 if (argo_debug[D_EON]) {
550 printf("eoninput to clnl IFQ\n");
552 #endif
553 ifq = &clnlintrq;
554 s = splnet();
555 if (IF_QFULL(ifq)) {
556 IF_DROP(ifq);
557 m_freem(m);
558 eonifp->if_iqdrops++;
559 eonifp->if_ipackets--;
560 splx(s);
561 return;
563 IF_ENQUEUE(ifq, m);
564 #ifdef ARGO_DEBUG
565 if (argo_debug[D_EON]) {
566 printf(
567 "%p enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data %p\n",
568 m, m->m_len, m->m_type, m->m_data);
569 dump_buf(mtod(m, void *), m->m_len);
571 #endif
572 schednetisr(NETISR_ISO);
573 splx(s);
577 void *
578 eonctlinput(int cmd, const struct sockaddr *sa, void *dummy)
580 const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
581 #ifdef ARGO_DEBUG
582 if (argo_debug[D_EON]) {
583 printf("eonctlinput: cmd 0x%x addr: ", cmd);
584 dump_isoaddr((const struct sockaddr_iso *)sin);
585 printf("\n");
587 #endif
589 if ((unsigned)cmd >= PRC_NCMDS)
590 return NULL;
592 IncStat(es_icmp[cmd]);
593 switch (cmd) {
595 case PRC_QUENCH:
596 case PRC_QUENCH2:
597 /* TODO: set the dec bit */
598 break;
599 case PRC_TIMXCEED_REASS:
600 case PRC_ROUTEDEAD:
601 case PRC_HOSTUNREACH:
602 case PRC_UNREACH_NET:
603 case PRC_IFDOWN:
604 case PRC_UNREACH_HOST:
605 case PRC_HOSTDEAD:
606 case PRC_TIMXCEED_INTRANS:
607 /* TODO: mark the link down */
608 break;
610 case PRC_UNREACH_PROTOCOL:
611 case PRC_UNREACH_PORT:
612 case PRC_UNREACH_SRCFAIL:
613 case PRC_REDIRECT_NET:
614 case PRC_REDIRECT_HOST:
615 case PRC_REDIRECT_TOSNET:
616 case PRC_REDIRECT_TOSHOST:
617 case PRC_MSGSIZE:
618 case PRC_PARAMPROB:
619 #if 0
620 printf("eonctlinput: ICMP cmd 0x%x\n", cmd );
621 #endif
622 break;
624 return NULL;
627 #endif