1 /* $NetBSD: esis.c,v 1.55 2009/03/18 17:06:52 cegger 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 * @(#)esis.c 8.3 (Berkeley) 3/20/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
61 #include <sys/cdefs.h>
62 __KERNEL_RCSID(0, "$NetBSD: esis.c,v 1.55 2009/03/18 17:06:52 cegger Exp $");
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/callout.h>
71 #include <sys/domain.h>
72 #include <sys/protosw.h>
73 #include <sys/socket.h>
74 #include <sys/socketvar.h>
75 #include <sys/errno.h>
76 #include <sys/kernel.h>
78 #include <sys/kauth.h>
81 #include <net/if_dl.h>
82 #include <net/route.h>
83 #include <net/raw_cb.h>
85 #include <netiso/iso.h>
86 #include <netiso/iso_pcb.h>
87 #include <netiso/iso_var.h>
88 #include <netiso/iso_snpac.h>
89 #include <netiso/clnl.h>
90 #include <netiso/clnp.h>
91 #include <netiso/clnp_stat.h>
92 #include <netiso/esis.h>
93 #include <netiso/argo_debug.h>
95 #include <machine/stdarg.h>
98 * Global variables to esis implementation
100 * esis_holding_time - the holding time (sec) parameter for outgoing pdus
101 * esis_config_time - the frequency (sec) that hellos are generated
102 * esis_esconfig_time - suggested es configuration time placed in the ish.
105 LIST_HEAD(, rawcb
) esis_pcb
;
106 struct esis_stat esis_stat
;
107 int esis_sendspace
= 2048;
108 int esis_recvspace
= 2048;
109 short esis_holding_time
= ESIS_HT
;
110 short esis_config_time
= ESIS_CONFIG
;
111 short esis_esconfig_time
= ESIS_CONFIG
;
112 struct sockaddr_dl esis_dl
= {
113 .sdl_len
= sizeof(esis_dl
),
114 .sdl_family
= AF_LINK
,
117 struct callout esis_config_ch
;
119 #define EXTEND_PACKET(m, mhdr, cp)\
120 if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\
121 esis_stat.es_nomem++;\
126 (cp) = mtod((m), void *);\
131 * FUNCTION: esis_init
133 * PURPOSE: Initialize the kernel portion of esis protocol
144 extern struct clnl_protosw clnl_protox
[256];
146 LIST_INIT(&esis_pcb
);
148 callout_init(&snpac_age_ch
, 0);
149 callout_init(&esis_config_ch
, 0);
151 callout_reset(&snpac_age_ch
, hz
, snpac_age
, NULL
);
152 callout_reset(&esis_config_ch
, hz
, esis_config
, NULL
);
154 clnl_protox
[ISO9542_ESIS
].clnl_input
= esis_input
;
155 clnl_protox
[ISO10589_ISIS
].clnl_input
= isis_input
;
157 clnl_protox
[ISO9542X25_ESIS
].clnl_input
= x25esis_input
;
158 #endif /* ISO_X25ESIS */
162 * FUNCTION: esis_usrreq
164 * PURPOSE: Handle user level esis requests
166 * RETURNS: 0 or appropriate errno
173 esis_usrreq(struct socket
*so
, int req
, struct mbuf
*m
, struct mbuf
*nam
,
174 struct mbuf
*control
, struct lwp
*l
)
179 if (req
== PRU_CONTROL
)
184 if (req
!= PRU_SEND
&& req
!= PRU_SENDOOB
&& control
)
185 panic("esis_usrreq: unexpected control mbuf");
187 if (rp
== 0 && req
!= PRU_ATTACH
) {
206 /* XXX: raw socket permission is checked in socreate() */
208 if (so
->so_snd
.sb_hiwat
== 0 || so
->so_rcv
.sb_hiwat
== 0) {
209 error
= soreserve(so
, esis_sendspace
, esis_recvspace
);
213 rp
= malloc(sizeof(*rp
), M_PCB
, M_WAITOK
|M_ZERO
);
219 LIST_INSERT_HEAD(&esis_pcb
, rp
, rcb_list
);
224 if (control
&& control
->m_len
) {
235 /* error checking here */
236 error
= isis_output(m
, mtod(nam
, struct sockaddr_dl
*));
255 * stat: don't bother with a blocksize.
269 * FUNCTION: esis_input
271 * PURPOSE: Process an incoming esis packet
280 esis_input(struct mbuf
*m0
, ...)
282 struct snpa_hdr
*shp
; /* subnetwork header */
283 struct esis_fixed
*pdu
= mtod(m0
, struct esis_fixed
*);
289 shp
= va_arg(ap
, struct snpa_hdr
*);
292 IFADDR_FOREACH(ifa
, shp
->snh_ifp
)
293 if (ifa
->ifa_addr
->sa_family
== AF_ISO
)
295 /* if we have no iso address just send it to the sockets */
300 * check checksum if necessary
302 if (ESIS_CKSUM_REQUIRED(pdu
) &&
303 iso_check_csum(m0
, (int) pdu
->esis_hdr_len
)) {
304 esis_stat
.es_badcsum
++;
308 if (pdu
->esis_vers
!= ESIS_VERSION
) {
309 esis_stat
.es_badvers
++;
312 type
= pdu
->esis_type
& 0x1f;
315 esis_eshinput(m0
, shp
);
319 esis_ishinput(m0
, shp
);
323 esis_rdinput(m0
, shp
);
327 esis_stat
.es_badtype
++;
331 if (esis_pcb
.lh_first
!= 0)
338 * FUNCTION: esis_rdoutput
340 * PURPOSE: Transmit a redirect pdu
346 * NOTES: Assumes there is enough space for fixed part of header,
347 * DA, BSNPA and NET in first mbuf.
351 struct snpa_hdr
*inbound_shp
, /* snpa hdr from incoming packet */
352 struct mbuf
*inbound_m
, /* incoming pkt itself */
353 struct clnp_optidx
*inbound_oidx
, /* clnp options assoc with
355 struct iso_addr
*rd_dstnsap
, /* ultimate destination of pkt */
356 struct rtentry
*rt
) /* snpa cache info regarding next hop of pkt */
360 struct esis_fixed
*pdu
;
362 struct sockaddr_iso siso
;
363 struct ifnet
*ifp
= inbound_shp
->snh_ifp
;
364 struct sockaddr_dl
*sdl
;
365 const struct iso_addr
*rd_gwnsap
;
367 if (rt
->rt_flags
& RTF_GATEWAY
) {
368 rd_gwnsap
= &satosiso(rt
->rt_gateway
)->siso_addr
;
369 rt
= rtalloc1(rt
->rt_gateway
, 0);
371 rd_gwnsap
= &satocsiso(rt_getkey(rt
))->siso_addr
;
372 if (rt
== 0 || (sdl
= (struct sockaddr_dl
*) rt
->rt_gateway
) == 0 ||
373 sdl
->sdl_family
!= AF_LINK
) {
375 * maybe we should have a function that you could put in the
376 * iso_ifaddr structure which could translate iso_addrs into
377 * snpa's where there is a known mapping for that address
380 esis_stat
.es_badtype
++;
383 esis_stat
.es_rdsent
++;
385 if (argo_debug
[D_ESISOUTPUT
]) {
387 "esis_rdoutput: ifp %p (%s), ht %d, m %p, oidx %p\n",
388 ifp
, ifp
->if_xname
, esis_holding_time
,
389 inbound_m
, inbound_oidx
);
390 printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap
));
391 printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap
));
395 if ((m0
= m
= m_gethdr(M_DONTWAIT
, MT_HEADER
)) == NULL
) {
396 esis_stat
.es_nomem
++;
399 memset(mtod(m
, void *), 0, MHLEN
);
401 pdu
= mtod(m
, struct esis_fixed
*);
402 cp
= (void *) (pdu
+ 1); /* pointer arith.; 1st byte after
404 len
= sizeof(struct esis_fixed
);
407 * Build fixed part of header
409 pdu
->esis_proto_id
= ISO9542_ESIS
;
410 pdu
->esis_vers
= ESIS_VERSION
;
411 pdu
->esis_type
= ESIS_RD
;
412 HTOC(pdu
->esis_ht_msb
, pdu
->esis_ht_lsb
, esis_holding_time
);
414 /* Insert destination address */
415 (void) esis_insert_addr((void **)&cp
, &len
, rd_dstnsap
, m
, 0);
417 /* Insert the snpa of better next hop */
418 *cp
++ = sdl
->sdl_alen
;
419 memcpy(cp
, CLLADDR(sdl
), sdl
->sdl_alen
);
421 len
+= (sdl
->sdl_alen
+ 1);
424 * If the next hop is not the destination, then it ought to be an IS
425 * and it should be inserted next. Else, set the NETL to 0
427 /* PHASE2 use mask from ifp of outgoing interface */
428 if (!iso_addrmatch1(rd_dstnsap
, rd_gwnsap
)) {
430 /* this should not happen: */
431 if ((nhop_sc
->sc_flags
& SNPA_IS
) == 0) {
433 "esis_rdoutput: next hop is not dst and not an IS\n");
438 (void) esis_insert_addr((void **)&cp
, &len
, rd_gwnsap
, m
, 0);
440 *cp
++ = 0; /* NETL */
447 * If redirect is to an IS, add an address mask. The mask to be
448 * used should be the mask present in the routing entry used to
449 * forward the original data packet.
453 * Copy Qos, priority, or security options present in original npdu
456 /* THIS CODE IS CURRENTLY (mostly) UNTESTED */
458 if (inbound_oidx
->cni_qos_formatp
)
459 optlen
+= (inbound_oidx
->cni_qos_len
+ 2);
460 if (inbound_oidx
->cni_priorp
) /* priority option is 1 byte
463 if (inbound_oidx
->cni_securep
)
464 optlen
+= (inbound_oidx
->cni_secure_len
+ 2);
465 if (M_TRAILINGSPACE(m
) < optlen
) {
466 EXTEND_PACKET(m
, m0
, cp
);
468 /* assumes MLEN > optlen */
470 /* assume MLEN-len > optlen */
472 * When copying options, copy from ptr - 2 in order to grab
473 * the option code and length
475 if (inbound_oidx
->cni_qos_formatp
) {
476 memcpy(cp
, mtod(inbound_m
, char *) +
477 inbound_oidx
->cni_qos_formatp
- 2,
478 (unsigned) (inbound_oidx
->cni_qos_len
+ 2));
479 cp
+= inbound_oidx
->cni_qos_len
+ 2;
481 if (inbound_oidx
->cni_priorp
) {
482 memcpy(cp
, mtod(inbound_m
, char *) +
483 inbound_oidx
->cni_priorp
- 2, 3);
486 if (inbound_oidx
->cni_securep
) {
487 memcpy(cp
, mtod(inbound_m
, char *) +
488 inbound_oidx
->cni_securep
- 2,
489 (unsigned) (inbound_oidx
->cni_secure_len
+ 2));
490 cp
+= inbound_oidx
->cni_secure_len
+ 2;
495 pdu
->esis_hdr_len
= m0
->m_pkthdr
.len
= len
;
496 iso_gen_csum(m0
, ESIS_CKSUM_OFF
, (int) pdu
->esis_hdr_len
);
498 memset((void *) & siso
, 0, sizeof(siso
));
499 siso
.siso_family
= AF_ISO
;
500 siso
.siso_data
[0] = AFI_SNA
;
501 siso
.siso_nlen
= 6 + 1; /* should be taken from snpa_hdr */
503 memcpy(siso
.siso_data
+ 1, inbound_shp
->snh_shost
, 6);
504 (ifp
->if_output
) (ifp
, m0
, sisotosa(&siso
), 0);
508 * FUNCTION: esis_insert_addr
510 * PURPOSE: Insert an iso_addr into a buffer
512 * RETURNS: true if buffer was big enough, else false
514 * SIDE EFFECTS: Increment buf & len according to size of iso_addr
516 * NOTES: Plus 1 here is for length byte
520 void **bufv
, /* ptr to buffer to put address into */
521 int *len
, /* ptr to length of buffer so far */
522 const struct iso_addr
*isoa
, /* ptr to address */
523 struct mbuf
*m
, /* determine if there remains space */
527 int newlen
, result
= 0;
529 newlen
= isoa
->isoa_len
- nsellen
+ 1;
530 if (newlen
<= M_TRAILINGSPACE(m
)) {
531 memcpy(buf
, isoa
, newlen
);
541 #define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \
542 if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
543 #define ESIS_NEXT_OPTION(b) { b += (2 + b[1]); \
544 if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
548 * FUNCTION: esis_eshinput
550 * PURPOSE: Process an incoming ESH pdu
560 struct mbuf
*m
, /* esh pdu */
561 struct snpa_hdr
*shp
) /* subnetwork header */
563 struct esis_fixed
*pdu
= mtod(m
, struct esis_fixed
*);
564 u_short ht
; /* holding time */
565 struct iso_addr
*nsap
= NULL
;
567 u_char
*buf
= (u_char
*) (pdu
+ 1);
568 u_char
*buflim
= pdu
->esis_hdr_len
+ (u_char
*) pdu
;
571 esis_stat
.es_eshrcvd
++;
573 CTOH(pdu
->esis_ht_msb
, pdu
->esis_ht_lsb
, ht
);
579 ESIS_EXTRACT_ADDR(nsap
, buf
);
580 new_entry
= snpac_add(shp
->snh_ifp
,
581 nsap
, shp
->snh_shost
, SNPA_ES
, ht
, 0);
583 int nsellength
= 0, nlen
= 0;
586 * See if we want to compress out multiple nsaps
587 * differing only by nsel
589 IFADDR_FOREACH(ifa
, shp
->snh_ifp
)
590 if (ifa
->ifa_addr
->sa_family
== AF_ISO
) {
592 ((struct iso_ifaddr
*) ifa
)->ia_addr
.siso_tlen
;
596 if (argo_debug
[D_ESISINPUT
]) {
598 "esis_eshinput: esh: ht %d, naddr %d nsellength %d\n",
599 ht
, naddr
, nsellength
);
602 while (naddr
-- > 0) {
603 struct iso_addr
*nsap2
;
605 ESIS_EXTRACT_ADDR(nsap
, buf
);
607 * see if there is at least one more nsap in ESH
608 * differing only by nsel
611 for (buf2
= buf
; buf2
< buflim
;) {
612 ESIS_EXTRACT_ADDR(nsap2
, buf2
);
614 if (argo_debug
[D_ESISINPUT
]) {
616 "esis_eshinput: comparing %s ",
617 clnp_iso_addrp(nsap
));
619 clnp_iso_addrp(nsap2
));
622 if (memcmp(nsap
->isoa_genaddr
,
624 nsap
->isoa_len
- nsellength
)
630 new_entry
|= snpac_add(shp
->snh_ifp
,
631 nsap
, shp
->snh_shost
, SNPA_ES
, ht
, nlen
);
636 if (argo_debug
[D_ESISINPUT
]) {
637 printf("esis_eshinput: nsap %s is %s\n",
638 clnp_iso_addrp(nsap
), new_entry
? "new" : "old");
641 if (new_entry
&& (iso_systype
& SNPA_IS
))
642 esis_shoutput(shp
->snh_ifp
, ESIS_ISH
, esis_holding_time
,
643 shp
->snh_shost
, 6, (struct iso_addr
*) 0);
649 * FUNCTION: esis_ishinput
651 * PURPOSE: process an incoming ISH pdu
661 struct mbuf
*m
, /* esh pdu */
662 struct snpa_hdr
*shp
) /* subnetwork header */
664 struct esis_fixed
*pdu
= mtod(m
, struct esis_fixed
*);
665 u_short ht
, newct
; /* holding time */
666 struct iso_addr
*nsap
; /* Network Entity Title */
667 u_char
*buf
= (u_char
*) (pdu
+ 1);
668 u_char
*buflim
= pdu
->esis_hdr_len
+ (u_char
*) pdu
;
671 esis_stat
.es_ishrcvd
++;
672 CTOH(pdu
->esis_ht_msb
, pdu
->esis_ht_lsb
, ht
);
675 if (argo_debug
[D_ESISINPUT
]) {
676 printf("esis_ishinput: ish: ht %d\n", ht
);
682 ESIS_EXTRACT_ADDR(nsap
, buf
);
684 while (buf
< buflim
) {
687 if (iso_systype
& SNPA_IS
)
691 CTOH(buf
[2], buf
[3], newct
);
692 if ((u_short
) esis_config_time
!= newct
) {
693 callout_stop(&esis_config_ch
);
694 esis_config_time
= newct
;
700 printf("Unknown ISH option: %x\n", *buf
);
702 ESIS_NEXT_OPTION(buf
);
704 new_entry
= snpac_add(shp
->snh_ifp
, nsap
, shp
->snh_shost
, SNPA_IS
,
707 if (argo_debug
[D_ESISINPUT
]) {
708 printf("esis_ishinput: nsap %s is %s\n",
709 clnp_iso_addrp(nsap
), new_entry
? "new" : "old");
714 esis_shoutput(shp
->snh_ifp
,
715 iso_systype
& SNPA_ES
? ESIS_ESH
: ESIS_ISH
,
716 esis_holding_time
, shp
->snh_shost
, 6, (struct iso_addr
*) 0);
722 * FUNCTION: esis_rdinput
724 * PURPOSE: Process an incoming RD pdu
734 struct mbuf
*m0
, /* esh pdu */
735 struct snpa_hdr
*shp
) /* subnetwork header */
737 struct esis_fixed
*pdu
= mtod(m0
, struct esis_fixed
*);
738 u_short ht
; /* holding time */
739 struct iso_addr
*da
, *net
= 0, *netmask
= 0, *snpamask
= 0;
740 struct iso_addr
*bsnpa
;
741 u_char
*buf
= (u_char
*) (pdu
+ 1);
742 u_char
*buflim
= pdu
->esis_hdr_len
+ (u_char
*) pdu
;
744 esis_stat
.es_rdrcvd
++;
746 /* intermediate systems ignore redirects */
747 if (iso_systype
& SNPA_IS
)
752 CTOH(pdu
->esis_ht_msb
, pdu
->esis_ht_lsb
, ht
);
757 ESIS_EXTRACT_ADDR(da
, buf
);
759 /* Extract better snpa */
760 ESIS_EXTRACT_ADDR(bsnpa
, buf
);
762 /* Extract NET if present */
765 buf
++; /* no NET present, skip NETL anyway */
767 ESIS_EXTRACT_ADDR(net
, buf
);
769 /* process options */
770 while (buf
< buflim
) {
772 case ESISOVAL_SNPAMASK
:
773 if (snpamask
) /* duplicate */
775 snpamask
= (struct iso_addr
*) (buf
+ 1);
778 case ESISOVAL_NETMASK
:
779 if (netmask
) /* duplicate */
781 netmask
= (struct iso_addr
*) (buf
+ 1);
785 printf("Unknown option in ESIS RD (0x%x)\n", buf
[-1]);
787 ESIS_NEXT_OPTION(buf
);
791 if (argo_debug
[D_ESISINPUT
]) {
792 printf("esis_rdinput: rd: ht %d, da %s\n", ht
,
795 printf("\t: net %s\n", clnp_iso_addrp(net
));
799 * If netl is zero, then redirect is to an ES. We need to add an entry
800 * to the snpa cache for (destination, better snpa).
801 * If netl is not zero, then the redirect is to an IS. In this
802 * case, add an snpa cache entry for (net, better snpa).
804 * If the redirect is to an IS, add a route entry towards that
807 if (net
== 0 || net
->isoa_len
== 0 || snpamask
) {
808 /* redirect to an ES */
809 snpac_add(shp
->snh_ifp
, da
,
810 bsnpa
->isoa_genaddr
, SNPA_ES
, ht
, 0);
812 snpac_add(shp
->snh_ifp
, net
,
813 bsnpa
->isoa_genaddr
, SNPA_IS
, ht
, 0);
814 snpac_addrt(shp
->snh_ifp
, da
, net
, netmask
);
816 bad
: ; /* Needed by ESIS_NEXT_OPTION */
820 * FUNCTION: esis_config
822 * PURPOSE: Report configuration
828 * NOTES: Called every esis_config_time seconds
836 callout_reset(&esis_config_ch
, hz
* esis_config_time
,
840 * Report configuration for each interface that - is UP - has
841 * BROADCAST capability - has an ISO address
844 * Todo: a better way would be to construct the esh or ish once and
845 * copy it out for all devices, possibly calling a method in the
846 * iso_ifaddr structure to encapsulate and transmit it. This could
847 * work to advantage for non-broadcast media
850 TAILQ_FOREACH(ifp
, &ifnet
, if_list
) {
851 if ((ifp
->if_flags
& IFF_UP
) &&
852 (ifp
->if_flags
& IFF_BROADCAST
)) {
853 /* search for an ISO address family */
856 IFADDR_FOREACH(ifa
, ifp
) {
857 if (ifa
->ifa_addr
->sa_family
== AF_ISO
) {
859 iso_systype
& SNPA_ES
? ESIS_ESH
: ESIS_ISH
,
861 (iso_systype
& SNPA_ES
? all_is_snpa
:
862 all_es_snpa
), 6, (struct iso_addr
*) 0);
871 * FUNCTION: esis_shoutput
873 * PURPOSE: Transmit an esh or ish pdu
888 struct iso_addr
*isoa
)
893 struct esis_fixed
*pdu
;
894 struct iso_ifaddr
*ia
;
896 struct sockaddr_iso siso
;
898 if (type
== ESIS_ESH
)
899 esis_stat
.es_eshsent
++;
900 else if (type
== ESIS_ISH
)
901 esis_stat
.es_ishsent
++;
903 printf("esis_shoutput: bad pdu type\n");
908 if (argo_debug
[D_ESISOUTPUT
]) {
910 printf("esis_shoutput: ifp %p (%s), %s, ht %d, to: [%d] ",
912 type
== ESIS_ESH
? "esh" : "ish",
914 for (i
= 0; i
< sn_len
; i
++)
915 printf("%x%c", *((const char *)sn_addr
+ i
),
916 i
< (sn_len
- 1) ? ':' : ' ');
921 if ((m0
= m
= m_gethdr(M_DONTWAIT
, MT_HEADER
)) == NULL
) {
922 esis_stat
.es_nomem
++;
925 memset(mtod(m
, void *), 0, MHLEN
);
927 pdu
= mtod(m
, struct esis_fixed
*);
928 naddrp
= cp
= (char *) (pdu
+ 1);
929 len
= sizeof(struct esis_fixed
);
932 * Build fixed part of header
934 pdu
->esis_proto_id
= ISO9542_ESIS
;
935 pdu
->esis_vers
= ESIS_VERSION
;
936 pdu
->esis_type
= type
;
937 HTOC(pdu
->esis_ht_msb
, pdu
->esis_ht_lsb
, ht
);
939 if (type
== ESIS_ESH
) {
946 * Here we are responding to a clnp packet sent to an NSAP
947 * that is ours which was sent to the MAC addr all_es's.
948 * It is possible that we did not specifically advertise this
949 * NSAP, even though it is ours, so we will respond
950 * directly to the sender that we are here. If we do have
951 * multiple NSEL's we'll tack them on so he can compress
954 (void) esis_insert_addr((void **)&cp
, &len
, isoa
, m
, 0);
957 TAILQ_FOREACH(ia
, &iso_ifaddr
, ia_list
) {
958 int nsellen
= (type
== ESIS_ISH
? ia
->ia_addr
.siso_tlen
: 0);
959 int n
= ia
->ia_addr
.siso_nlen
;
960 struct iso_ifaddr
*ia2
;
962 if (type
== ESIS_ISH
&& naddr
> 0)
964 TAILQ_FOREACH(ia2
, &iso_ifaddr
, ia_list
)
965 if (memcmp(ia
->ia_addr
.siso_data
,
966 ia2
->ia_addr
.siso_data
, n
) == 0)
969 continue; /* Means we have previously copied
971 if (isoa
&& memcmp(ia
->ia_addr
.siso_data
,
972 isoa
->isoa_genaddr
, n
) == 0) {
974 continue; /* Ditto */
977 if (argo_debug
[D_ESISOUTPUT
]) {
978 printf("esis_shoutput: adding NSAP %s\n",
979 clnp_iso_addrp(&ia
->ia_addr
.siso_addr
));
982 if (!esis_insert_addr((void **)&cp
, &len
,
983 &ia
->ia_addr
.siso_addr
, m
, nsellen
)) {
984 EXTEND_PACKET(m
, m0
, cp
);
985 (void) esis_insert_addr((void **)&cp
, &len
,
986 &ia
->ia_addr
.siso_addr
, m
,
992 if (type
== ESIS_ESH
)
995 /* add suggested es config timer option to ISH */
996 if (M_TRAILINGSPACE(m
) < 4) {
997 printf("esis_shoutput: extending packet\n");
998 EXTEND_PACKET(m
, m0
, cp
);
1000 *cp
++ = ESISOVAL_ESCT
;
1002 HTOC(*cp
, *(cp
+ 1), esis_esconfig_time
);
1006 if (argo_debug
[D_ESISOUTPUT
]) {
1007 printf("m0 %p, m %p, data %p, len %d, cp %p\n",
1008 m0
, m
, m
->m_data
, m
->m_len
, cp
);
1013 m0
->m_pkthdr
.len
= len
;
1014 pdu
->esis_hdr_len
= len
;
1015 iso_gen_csum(m0
, ESIS_CKSUM_OFF
, (int) pdu
->esis_hdr_len
);
1017 memset((void *) & siso
, 0, sizeof(siso
));
1018 siso
.siso_family
= AF_ISO
;
1019 siso
.siso_data
[0] = AFI_SNA
;
1020 siso
.siso_nlen
= sn_len
+ 1;
1021 memcpy(siso
.siso_data
+ 1, sn_addr
, (unsigned) sn_len
);
1022 (ifp
->if_output
) (ifp
, m0
, sisotosa(&siso
), 0);
1026 * FUNCTION: isis_input
1028 * PURPOSE: Process an incoming isis packet
1037 isis_input(struct mbuf
*m0
, ...)
1039 struct snpa_hdr
*shp
; /* subnetwork header */
1040 struct rawcb
*rp
, *first_rp
= 0;
1046 shp
= va_arg(ap
, struct snpa_hdr
*);
1051 if (argo_debug
[D_ISISINPUT
]) {
1054 printf("isis_input: pkt on ifp %p (%s): from:",
1055 ifp
, ifp
->if_xname
);
1056 for (i
= 0; i
< 6; i
++)
1057 printf("%x%c", shp
->snh_shost
[i
] & 0xff,
1058 (i
< 5) ? ':' : ' ');
1060 for (i
= 0; i
< 6; i
++)
1061 printf("%x%c", shp
->snh_dhost
[i
] & 0xff,
1062 (i
< 5) ? ':' : ' ');
1066 esis_dl
.sdl_alen
= ifp
->if_addrlen
;
1067 esis_dl
.sdl_index
= ifp
->if_index
;
1068 memcpy((void *) esis_dl
.sdl_data
, shp
->snh_shost
, esis_dl
.sdl_alen
);
1069 for (rp
= esis_pcb
.lh_first
; rp
!= 0; rp
= rp
->rcb_list
.le_next
) {
1070 if (first_rp
== 0) {
1074 /* can't block at interrupt level */
1075 if ((mm
= m_copy(m0
, 0, M_COPYALL
)) != NULL
) {
1076 if (sbappendaddr(&rp
->rcb_socket
->so_rcv
,
1077 (struct sockaddr
*) &esis_dl
, mm
,
1078 (struct mbuf
*) 0) != 0) {
1079 sorwakeup(rp
->rcb_socket
);
1082 if (argo_debug
[D_ISISINPUT
]) {
1084 "Error in sbappenaddr, mm = %p\n", mm
);
1091 if (first_rp
&& sbappendaddr(&first_rp
->rcb_socket
->so_rcv
,
1092 (struct sockaddr
*) &esis_dl
, m0
, (struct mbuf
*) 0) != 0) {
1093 sorwakeup(first_rp
->rcb_socket
);
1100 isis_output(struct mbuf
*m
, ...)
1102 struct sockaddr_dl
*sdl
;
1105 struct sockaddr_iso siso
;
1111 sdl
= va_arg(ap
, struct sockaddr_dl
*);
1114 /* we assume here we have a sockaddr_dl ... check it */
1115 if (sdl
->sdl_family
!= AF_LINK
) {
1119 if (sdl
->sdl_len
< 8 + sdl
->sdl_nlen
+ sdl
->sdl_alen
+ sdl
->sdl_slen
) {
1124 ifa
= ifa_ifwithnet((struct sockaddr
*) sdl
); /* get ifp from sdl */
1127 if (argo_debug
[D_ISISOUTPUT
]) {
1128 printf("isis_output: interface not found\n");
1135 sn_len
= sdl
->sdl_alen
;
1137 if (argo_debug
[D_ISISOUTPUT
]) {
1138 const u_char
*cp
= (const u_char
*)CLLADDR(sdl
),
1139 *cplim
= cp
+ sn_len
;
1140 printf("isis_output: ifp %p (%s), to: ",
1141 ifp
, ifp
->if_xname
);
1142 while (cp
< cplim
) {
1143 printf("%x", *cp
++);
1144 printf("%c", (cp
< cplim
) ? ':' : ' ');
1149 memset((void *) & siso
, 0, sizeof(siso
));
1150 siso
.siso_family
= AF_ISO
; /* This convention may be useful for
1155 siso
.siso_data
[0] = AFI_SNA
;
1156 siso
.siso_nlen
= sn_len
+ 1;
1157 memcpy(siso
.siso_data
+ 1, CLLADDR(sdl
), sn_len
);
1159 error
= (ifp
->if_output
) (ifp
, m
, sisotosa(&siso
), 0);
1162 if (argo_debug
[D_ISISOUTPUT
]) {
1163 printf("isis_output: error from if_output is %d\n",
1178 * FUNCTION: esis_ctlinput
1180 * PURPOSE: Handle the PRC_IFDOWN transition
1186 * NOTES: Calls snpac_flush for interface specified.
1187 * The loop through iso_ifaddr is stupid because
1188 * back in if_down, we knew the ifp...
1192 int req
, /* request: we handle only PRC_IFDOWN */
1193 const struct sockaddr
*siso
, /* address of ifp */
1196 struct iso_ifaddr
*ia
; /* scan through interface addresses */
1199 if (siso
->sa_family
!= AF_ISO
)
1201 if (req
== PRC_IFDOWN
)
1202 TAILQ_FOREACH(ia
, &iso_ifaddr
, ia_list
) {
1203 if (iso_addrmatch(IA_SIS(ia
),
1204 (const struct sockaddr_iso
*)siso
))
1205 snpac_flushifp(ia
->ia_ifp
);