1 /* $NetBSD: if_eon.c,v 1.68 2008/10/24 17:07:33 dyoung Exp $ */
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
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
31 * @(#)if_eon.c 8.2 (Berkeley) 1/9/95
34 /***********************************************************
35 Copyright IBM Corporation 1987
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
55 ******************************************************************/
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
62 * Layer between IP and CLNL
65 * Put together a current rfc986 address format and get the right offset
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: if_eon.c,v 1.68 2008/10/24 17:07:33 dyoung Exp $");
78 #include <sys/param.h>
79 #include <sys/systm.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. */
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>
114 struct ifnet eonif
[1];
122 struct eon_llinfo eon_llinfo
;
127 * FUNCTION: eonattach
129 * PURPOSE: autoconf attach routine
137 struct ifnet
*ifp
= eonif
;
140 if (argo_debug
[D_EON
]) {
141 printf("eonattach()\n");
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
;
153 ifp
->if_hdrlen
= EONIPLEN
;
154 ifp
->if_flags
= IFF_BROADCAST
;
157 eonioctl(ifp
, SIOCINITIFADDR
, ifp
->if_dl
);
158 eon_llinfo
.el_qhdr
.link
=
159 eon_llinfo
.el_qhdr
.rlink
= &(eon_llinfo
.el_qhdr
);
162 if (argo_debug
[D_EON
]) {
163 printf("eonattach()\n");
172 * PURPOSE: io controls - ifconfig
174 * link-UP (core addr) (flags: ES, IS)
175 * link-DOWN (core addr) (flags: ES, IS)
176 * must be callable from kernel or user
181 eonioctl(struct ifnet
*ifp
, u_long cmd
, void *data
)
183 struct ifaddr
*ifa
= data
;
184 int error
= 0, s
= splnet();
187 if (argo_debug
[D_EON
]) {
188 printf("eonioctl (cmd 0x%lx) \n", cmd
);
196 ifp
->if_flags
|= IFF_UP
;
197 if (ifa
->ifa_addr
->sa_family
!= AF_LINK
)
198 ifa
->ifa_rtrequest
= eonrtrequest
;
201 error
= ifioctl_common(ifp
, cmd
, data
);
210 eoniphdr(struct eon_iphdr
*hdr
, const void *loc
, struct route
*ro
, int class)
216 struct sockaddr_in dst4
;
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
)
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
);
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
));
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.
254 eonrtrequest(int cmd
, struct rtentry
*rt
, const struct rt_addrinfo
*info
)
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
268 iso_remque(&el
->el_qhdr
);
269 rtcache_free(&el
->el_iproute
);
271 rt
->rt_llinfo
= NULL
;
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
;
282 memset(el
, 0, sizeof(*el
));
283 iso_insque(&el
->el_qhdr
, &eon_llinfo
.el_qhdr
);
288 (gate
= info
->rti_info
[RTAX_GATEWAY
]) != NULL
) { /*XXX*/
289 switch (gate
->sa_family
) {
291 if (satocsdl(gate
)->sdl_alen
== 1)
292 el
->el_snpaoffset
= *(const u_char
*)CLLADDR(satocsdl(gate
));
294 ipaddrloc
= CLLADDR(satocsdl(gate
));
297 ipaddrloc
= &satocsin(gate
)->sin_addr
;
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
324 eonoutput(struct ifnet
*ifp
, struct mbuf
*m
, const struct sockaddr
*sdst
,
327 const struct sockaddr_iso
*dst
= (const struct sockaddr_iso
*)sdst
;
328 struct eon_llinfo
*el
;
329 struct eon_iphdr
*ei
;
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
;
339 if (argo_debug
[D_EON
]) {
340 printf("eonoutput \n");
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;
358 class = ipaddrloc
[4];
362 memset(ei
, 0, sizeof(*ei
));
363 eoniphdr(ei
, ipaddrloc
, ro
, class);
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
;
377 if ((m
->m_flags
& M_PKTHDR
) == 0) {
378 printf("eon: got non headered packet\n");
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
));
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
) {
397 MGETHDR(mh
, M_DONTWAIT
, MT_HEADER
);
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
;
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
));
419 error
= ip_output(m
, NULL
, ro
, 0, NULL
, NULL
);
424 ifp
->if_obytes
-= datalen
;
433 * Strip out IP options, at higher
434 * level protocol in the kernel.
437 ip_stripoptions(struct mbuf
*m
)
439 struct ip
*ip
= mtod(m
, struct ip
*);
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
);
452 eoninput(struct mbuf
*m
, ...)
455 struct eon_hdr
*eonhdr
;
457 struct ifnet
*eonifp
;
462 iphlen
= va_arg(ap
, int);
465 eonifp
= &eonif
[0]; /* kludge - really want to give CLNP the ifp
466 * for eon, not for the real device */
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);
477 if (iphlen
> sizeof(struct ip
))
479 if (m
->m_len
< EONIPLEN
) {
480 if ((m
= m_pullup(m
, EONIPLEN
)) == NULL
) {
484 if (argo_debug
[D_EON
]) {
485 printf("eoninput: DROP \n");
488 eonifp
->if_ierrors
++;
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
) {
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
) {
507 m
->m_data
-= sizeof(struct ip
);
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
));
517 /* checks for debugging */
518 if (eonhdr
->eonh_vers
!= EON_VERSION
) {
522 m
->m_flags
&= ~(M_BCAST
| M_MCAST
);
523 switch (eonhdr
->eonh_class
) {
525 IncStat(es_in_broad
);
526 m
->m_flags
|= M_BCAST
;
528 case EON_NORMAL_ADDR
:
529 IncStat(es_in_normal
);
531 case EON_MULTICAST_ES
:
532 IncStat(es_in_multi_es
);
533 m
->m_flags
|= M_MCAST
;
535 case EON_MULTICAST_IS
:
536 IncStat(es_in_multi_is
);
537 m
->m_flags
|= M_MCAST
;
540 eonifp
->if_ipackets
++;
543 /* put it on the CLNP queue and set soft interrupt */
545 extern struct ifqueue clnlintrq
;
547 m
->m_pkthdr
.rcvif
= eonifp
; /* KLUDGE */
549 if (argo_debug
[D_EON
]) {
550 printf("eoninput to clnl IFQ\n");
558 eonifp
->if_iqdrops
++;
559 eonifp
->if_ipackets
--;
565 if (argo_debug
[D_EON
]) {
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
);
572 schednetisr(NETISR_ISO
);
578 eonctlinput(int cmd
, const struct sockaddr
*sa
, void *dummy
)
580 const struct sockaddr_in
*sin
= (const struct sockaddr_in
*)sa
;
582 if (argo_debug
[D_EON
]) {
583 printf("eonctlinput: cmd 0x%x addr: ", cmd
);
584 dump_isoaddr((const struct sockaddr_iso
*)sin
);
589 if ((unsigned)cmd
>= PRC_NCMDS
)
592 IncStat(es_icmp
[cmd
]);
597 /* TODO: set the dec bit */
599 case PRC_TIMXCEED_REASS
:
601 case PRC_HOSTUNREACH
:
602 case PRC_UNREACH_NET
:
604 case PRC_UNREACH_HOST
:
606 case PRC_TIMXCEED_INTRANS
:
607 /* TODO: mark the link down */
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
:
620 printf("eonctlinput: ICMP cmd 0x%x\n", cmd
);