xref: /csrg-svn/sys/netiso/esis.c (revision 43421)
136379Ssklower /***********************************************************
236379Ssklower 		Copyright IBM Corporation 1987
336379Ssklower 
436379Ssklower                       All Rights Reserved
536379Ssklower 
636379Ssklower Permission to use, copy, modify, and distribute this software and its
736379Ssklower documentation for any purpose and without fee is hereby granted,
836379Ssklower provided that the above copyright notice appear in all copies and that
936379Ssklower both that copyright notice and this permission notice appear in
1036379Ssklower supporting documentation, and that the name of IBM not be
1136379Ssklower used in advertising or publicity pertaining to distribution of the
1236379Ssklower software without specific, written prior permission.
1336379Ssklower 
1436379Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536379Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636379Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736379Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836379Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936379Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036379Ssklower SOFTWARE.
2136379Ssklower 
2236379Ssklower ******************************************************************/
2336379Ssklower 
2436379Ssklower /*
2536379Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636379Ssklower  */
27*43421Ssklower /*	@(#)esis.c	7.9 (Berkeley) 06/22/90 */
2836379Ssklower #ifndef lint
2936379Ssklower static char *rcsid = "$Header: esis.c,v 4.10 88/09/15 18:57:03 hagens Exp $";
3036379Ssklower #endif
3136379Ssklower 
3236379Ssklower #ifdef ISO
3336379Ssklower 
3437469Ssklower #include "types.h"
3537469Ssklower #include "param.h"
3637469Ssklower #include "mbuf.h"
3737469Ssklower #include "domain.h"
3837469Ssklower #include "protosw.h"
3937469Ssklower #include "user.h"
4037469Ssklower #include "socket.h"
4137469Ssklower #include "socketvar.h"
4237469Ssklower #include "errno.h"
4337469Ssklower #include "kernel.h"
4436379Ssklower 
4536379Ssklower #include "../net/if.h"
4643332Ssklower #include "../net/if_dl.h"
4736379Ssklower #include "../net/route.h"
48*43421Ssklower #include "../net/raw_cb.h"
4936379Ssklower 
5037469Ssklower #include "iso.h"
5137469Ssklower #include "iso_pcb.h"
5237469Ssklower #include "iso_var.h"
5337469Ssklower #include "iso_snpac.h"
5437469Ssklower #include "clnl.h"
5537469Ssklower #include "clnp.h"
5637469Ssklower #include "clnp_stat.h"
5738841Ssklower #include "esis.h"
5837469Ssklower #include "argo_debug.h"
5936379Ssklower 
6036379Ssklower /*
6136379Ssklower  *	Global variables to esis implementation
6236379Ssklower  *
6336379Ssklower  *	esis_holding_time - the holding time (sec) parameter for outgoing pdus
6436379Ssklower  *	esis_config_time  - the frequency (sec) that hellos are generated
65*43421Ssklower  *	esis_esconfig_time - suggested es configuration time placed in the
66*43421Ssklower  *						ish.
6736379Ssklower  *
6836379Ssklower  */
69*43421Ssklower struct rawcb	esis_pcb;
7036379Ssklower int				esis_sendspace = 2048;
7136379Ssklower int				esis_recvspace = 2048;
7236379Ssklower short			esis_holding_time = ESIS_HT;
7336379Ssklower short			esis_config_time = ESIS_CONFIG;
74*43421Ssklower short			esis_esconfig_time = ESIS_CONFIG;
7536379Ssklower extern int		iso_systype;
76*43421Ssklower struct sockaddr_dl	esis_dl = { sizeof(esis_dl), AF_LINK };
7743332Ssklower extern char		all_es_snpa[], all_is_snpa[];
7836379Ssklower 
7937469Ssklower #define EXTEND_PACKET(m, mhdr, cp)\
8036379Ssklower 	if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\
8136379Ssklower 		esis_stat.es_nomem++;\
8236379Ssklower 		m_freem(mhdr);\
8336379Ssklower 		return;\
8436379Ssklower 	} else {\
8536379Ssklower 		(m) = (m)->m_next;\
8636379Ssklower 		(cp) = mtod((m), caddr_t);\
8736379Ssklower 	}
8836379Ssklower /*
8936379Ssklower  * FUNCTION:		esis_init
9036379Ssklower  *
9136379Ssklower  * PURPOSE:			Initialize the kernel portion of esis protocol
9236379Ssklower  *
9336379Ssklower  * RETURNS:			nothing
9436379Ssklower  *
9536379Ssklower  * SIDE EFFECTS:
9636379Ssklower  *
9736379Ssklower  * NOTES:
9836379Ssklower  */
9936379Ssklower esis_init()
10036379Ssklower {
10136379Ssklower 	extern struct clnl_protosw clnl_protox[256];
10236379Ssklower 	int esis_input();
103*43421Ssklower 	int	esis_config();
10436379Ssklower 	int snpac_age();
10536379Ssklower #ifdef	ISO_X25ESIS
10636379Ssklower 	x25esis_input();
10736379Ssklower #endif	ISO_X25ESIS
10836379Ssklower 
109*43421Ssklower 	esis_pcb.rcb_next = esis_pcb.rcb_prev = &esis_pcb;
110*43421Ssklower 	llinfo_llc.lc_next = llinfo_llc.lc_prev = &llinfo_llc;
11136379Ssklower 
11236379Ssklower 	clnl_protox[ISO9542_ESIS].clnl_input = esis_input;
11336379Ssklower 	timeout(snpac_age, (caddr_t)0, hz);
11436379Ssklower 	timeout(esis_config, (caddr_t)0, hz);
11536379Ssklower 
11636379Ssklower #ifdef	ISO_X25ESIS
11736379Ssklower 	clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input;
11836379Ssklower #endif	ISO_X25ESIS
11936379Ssklower }
12036379Ssklower 
12136379Ssklower /*
12236379Ssklower  * FUNCTION:		esis_usrreq
12336379Ssklower  *
12436379Ssklower  * PURPOSE:			Handle user level esis requests
12536379Ssklower  *
12636379Ssklower  * RETURNS:			0 or appropriate errno
12736379Ssklower  *
12836379Ssklower  * SIDE EFFECTS:
12936379Ssklower  *
13036379Ssklower  */
13137469Ssklower /*ARGSUSED*/
13240775Ssklower esis_usrreq(so, req, m, nam, control)
13336379Ssklower struct socket	*so;		/* socket: used only to get to this code */
13436379Ssklower int				req;		/* request */
13536379Ssklower struct mbuf		*m;			/* data for request */
13636379Ssklower struct mbuf		*nam;		/* optional name */
13740775Ssklower struct mbuf		*control;	/* optional control */
13836379Ssklower {
139*43421Ssklower 	struct rawcb *rp = sotorawcb(so);
140*43421Ssklower 	int error = 0;
141*43421Ssklower 
142*43421Ssklower 	if (suser(u.u_cred, &u.u_acflag)) {
143*43421Ssklower 		error = EACCES;
144*43421Ssklower 		goto release;
145*43421Ssklower 	}
146*43421Ssklower 	if (rp == NULL && req != PRU_ATTACH) {
147*43421Ssklower 		error = EINVAL;
148*43421Ssklower 		goto release;
149*43421Ssklower 	}
150*43421Ssklower 
151*43421Ssklower 	switch (req) {
152*43421Ssklower 	case PRU_ATTACH:
153*43421Ssklower 		if (rp != NULL) {
154*43421Ssklower 			error = EINVAL;
155*43421Ssklower 			break;
156*43421Ssklower 		}
157*43421Ssklower 		MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
158*43421Ssklower 		if (so->so_pcb = (caddr_t)rp) {
159*43421Ssklower 			bzero(so->so_pcb, sizeof(*rp));
160*43421Ssklower 			insque(rp, &esis_pcb);
161*43421Ssklower 			error = soreserve(so, esis_sendspace, esis_recvspace);
162*43421Ssklower 		} else
163*43421Ssklower 			error = ENOBUFS;
164*43421Ssklower 		break;
165*43421Ssklower 
166*43421Ssklower 	case PRU_SEND:
167*43421Ssklower 		if (nam == NULL) {
168*43421Ssklower 			error = EINVAL;
169*43421Ssklower 			break;
170*43421Ssklower 		}
171*43421Ssklower 		/* error checking here */
172*43421Ssklower 		error = isis_output(mtod(nam,struct sockaddr_dl *), m);
173*43421Ssklower 		m = NULL;
174*43421Ssklower 		break;
175*43421Ssklower 
176*43421Ssklower 	case PRU_DETACH:
177*43421Ssklower 		raw_detach(rp);
178*43421Ssklower 		break;
179*43421Ssklower 
180*43421Ssklower 	case PRU_SHUTDOWN:
181*43421Ssklower 		socantsendmore(so);
182*43421Ssklower 		break;
183*43421Ssklower 
184*43421Ssklower 	case PRU_ABORT:
185*43421Ssklower 		soisdisconnected(so);
186*43421Ssklower 		raw_detach(rp);
187*43421Ssklower 		break;
188*43421Ssklower 
189*43421Ssklower 	case PRU_SENSE:
190*43421Ssklower 		return (0);
191*43421Ssklower 
192*43421Ssklower 	default:
193*43421Ssklower 		return (EOPNOTSUPP);
194*43421Ssklower 	}
195*43421Ssklower release:
19636379Ssklower 	if (m != NULL)
19736379Ssklower 		m_freem(m);
19836379Ssklower 
199*43421Ssklower 	return (error);
20036379Ssklower }
20136379Ssklower 
20236379Ssklower /*
20336379Ssklower  * FUNCTION:		esis_input
20436379Ssklower  *
20536379Ssklower  * PURPOSE:			Process an incoming esis packet
20636379Ssklower  *
20736379Ssklower  * RETURNS:			nothing
20836379Ssklower  *
20936379Ssklower  * SIDE EFFECTS:
21036379Ssklower  *
21136379Ssklower  * NOTES:
21236379Ssklower  */
21336379Ssklower esis_input(m0, shp)
21436379Ssklower struct mbuf		*m0;		/* ptr to first mbuf of pkt */
21536379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
21636379Ssklower {
217*43421Ssklower 	register struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
21837469Ssklower 	register int type;
21936379Ssklower 
22036379Ssklower 	/*
22136379Ssklower 	 *	check checksum if necessary
22236379Ssklower 	 */
22337469Ssklower 	if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) {
22436379Ssklower 		esis_stat.es_badcsum++;
22536379Ssklower 		goto bad;
22636379Ssklower 	}
22736379Ssklower 
22836379Ssklower 	/* check version */
22936379Ssklower 	if (pdu->esis_vers != ESIS_VERSION) {
23036379Ssklower 		esis_stat.es_badvers++;
23136379Ssklower 		goto bad;
23236379Ssklower 	}
23337469Ssklower 	type = pdu->esis_type & 0x1f;
23437469Ssklower 	switch (type) {
23536379Ssklower 		case ESIS_ESH:
23636379Ssklower 			esis_eshinput(m0, shp);
237*43421Ssklower 			break;
23836379Ssklower 
23936379Ssklower 		case ESIS_ISH:
24036379Ssklower 			esis_ishinput(m0, shp);
241*43421Ssklower 			break;
24236379Ssklower 
24336379Ssklower 		case ESIS_RD:
24436379Ssklower 			esis_rdinput(m0, shp);
245*43421Ssklower 			break;
24636379Ssklower 
247*43421Ssklower 		default:
24836379Ssklower 			esis_stat.es_badtype++;
24936379Ssklower 	}
25036379Ssklower 
25136379Ssklower bad:
252*43421Ssklower 	if (esis_pcb.rcb_next != &esis_pcb)
253*43421Ssklower 		isis_input(m0, shp);
254*43421Ssklower 	else
255*43421Ssklower 		m_freem(m0);
25636379Ssklower }
25736379Ssklower 
25836379Ssklower /*
25936379Ssklower  * FUNCTION:		esis_rdoutput
26036379Ssklower  *
26136379Ssklower  * PURPOSE:			Transmit a redirect pdu
26236379Ssklower  *
26336379Ssklower  * RETURNS:			nothing
26436379Ssklower  *
26536379Ssklower  * SIDE EFFECTS:
26636379Ssklower  *
26736379Ssklower  * NOTES:			Assumes there is enough space for fixed part of header,
26836379Ssklower  *					DA, BSNPA and NET in first mbuf.
26936379Ssklower  */
27043332Ssklower esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt)
27136379Ssklower struct snpa_hdr		*inbound_shp;	/* snpa hdr from incoming packet */
27236379Ssklower struct mbuf			*inbound_m;		/* incoming pkt itself */
27336379Ssklower struct clnp_optidx	*inbound_oidx;	/* clnp options assoc with incoming pkt */
27436379Ssklower struct iso_addr		*rd_dstnsap;	/* ultimate destination of pkt */
27543332Ssklower struct rtentry		*rt;			/* snpa cache info regarding next hop of
27636379Ssklower 										pkt */
27736379Ssklower {
27836379Ssklower 	struct mbuf			*m, *m0;
27936379Ssklower 	caddr_t				cp;
28036379Ssklower 	struct esis_fixed	*pdu;
28136379Ssklower 	int					len, total_len = 0;
28236379Ssklower 	struct sockaddr_iso	siso;
28336379Ssklower 	struct ifnet 		*ifp = inbound_shp->snh_ifp;
28443332Ssklower 	struct sockaddr_dl *sdl;
28543332Ssklower 	struct iso_addr *rd_gwnsap;
28636379Ssklower 
28743332Ssklower 	if (rt->rt_flags & RTF_GATEWAY) {
28843332Ssklower 		rd_gwnsap = &((struct sockaddr_iso *)rt->rt_gateway)->siso_addr;
28943332Ssklower 		rt = rtalloc1(rt->rt_gateway, 0);
29043332Ssklower 	} else
29143332Ssklower 		rd_gwnsap = &((struct sockaddr_iso *)rt_key(rt))->siso_addr;
29243332Ssklower 	if (rt == 0 || (sdl = (struct sockaddr_dl *)rt->rt_gateway) == 0 ||
29343332Ssklower 		sdl->sdl_family != AF_LINK) {
29443332Ssklower 		/* maybe we should have a function that you
29543332Ssklower 		   could put in the iso_ifaddr structure
29643332Ssklower 		   which could translate iso_addrs into snpa's
29743332Ssklower 		   where there is a known mapping for that address type */
29843332Ssklower 		esis_stat.es_badtype++;
29943332Ssklower 		return;
30043332Ssklower 	}
30136379Ssklower 	esis_stat.es_rdsent++;
30236379Ssklower 	IFDEBUG(D_ESISOUTPUT)
30336379Ssklower 		printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n",
30436379Ssklower 			ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m,
30536379Ssklower 			inbound_oidx);
30636379Ssklower 		printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap));
30743332Ssklower 		printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap));
30836379Ssklower 	ENDDEBUG
30936379Ssklower 
31037469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
31136379Ssklower 		esis_stat.es_nomem++;
31236379Ssklower 		return;
31336379Ssklower 	}
31437469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
31536379Ssklower 
31636379Ssklower 	pdu = mtod(m, struct esis_fixed *);
31737469Ssklower 	cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */
31836379Ssklower 	len = sizeof(struct esis_fixed);
31936379Ssklower 
32036379Ssklower 	/*
32136379Ssklower 	 *	Build fixed part of header
32236379Ssklower 	 */
32336379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
32436379Ssklower 	pdu->esis_vers = ESIS_VERSION;
32536379Ssklower 	pdu->esis_type = ESIS_RD;
32636379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time);
32736379Ssklower 
32836379Ssklower 	/* Insert destination address */
32943072Ssklower 	(void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0);
33036379Ssklower 
33136379Ssklower 	/* Insert the snpa of better next hop */
33243332Ssklower 	*cp++ = sdl->sdl_alen;
33343332Ssklower 	bcopy(LLADDR(sdl), cp, sdl->sdl_alen);
33443332Ssklower 	cp += sdl->sdl_alen;
33543332Ssklower 	len += (sdl->sdl_alen + 1);
33636379Ssklower 
33736379Ssklower 	/*
33836379Ssklower 	 *	If the next hop is not the destination, then it ought to be
33936379Ssklower 	 *	an IS and it should be inserted next. Else, set the
34036379Ssklower 	 *	NETL to 0
34136379Ssklower 	 */
34236379Ssklower 	/* PHASE2 use mask from ifp of outgoing interface */
34343332Ssklower 	if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) {
34443332Ssklower 		/* this should not happen:
34536379Ssklower 		if ((nhop_sc->sc_flags & SNPA_IS) == 0) {
34636379Ssklower 			printf("esis_rdoutput: next hop is not dst and not an IS\n");
34736379Ssklower 			m_freem(m0);
34836379Ssklower 			return;
34943332Ssklower 		} */
35043332Ssklower 		(void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0);
35136379Ssklower 	} else {
35236379Ssklower 		*cp++ = 0;	/* NETL */
35336379Ssklower 		len++;
35436379Ssklower 	}
35537469Ssklower 	m->m_len = len;
35636379Ssklower 
35736379Ssklower 	/*
35836379Ssklower 	 *	PHASE2
35936379Ssklower 	 *	If redirect is to an IS, add an address mask. The mask to be
36036379Ssklower 	 *	used should be the mask present in the routing entry used to
36136379Ssklower 	 *	forward the original data packet.
36236379Ssklower 	 */
36336379Ssklower 
36436379Ssklower 	/*
36536379Ssklower 	 *	Copy Qos, priority, or security options present in original npdu
36636379Ssklower 	 */
36736379Ssklower 	if (inbound_oidx) {
36843332Ssklower 		/* THIS CODE IS CURRENTLY (mostly) UNTESTED */
36936379Ssklower 		int optlen = 0;
37036379Ssklower 		if (inbound_oidx->cni_qos_formatp)
37136379Ssklower 			optlen += (inbound_oidx->cni_qos_len + 2);
37236379Ssklower 		if (inbound_oidx->cni_priorp)	/* priority option is 1 byte long */
37336379Ssklower 			optlen += 3;
37436379Ssklower 		if (inbound_oidx->cni_securep)
37536379Ssklower 			optlen += (inbound_oidx->cni_secure_len + 2);
37637469Ssklower 		if (M_TRAILINGSPACE(m) < optlen) {
37737469Ssklower 			EXTEND_PACKET(m, m0, cp);
37837469Ssklower 			m->m_len = 0;
37936379Ssklower 			/* assumes MLEN > optlen */
38036379Ssklower 		}
38136379Ssklower 		/* assume MLEN-len > optlen */
38236379Ssklower 		/*
38336379Ssklower 		 *	When copying options, copy from ptr - 2 in order to grab
38436379Ssklower 		 *	the option code and length
38536379Ssklower 		 */
38636379Ssklower 		if (inbound_oidx->cni_qos_formatp) {
38743332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_qos_formatp - 2,
38843332Ssklower 				cp, (unsigned)(inbound_oidx->cni_qos_len + 2));
38943332Ssklower 			cp += inbound_oidx->cni_qos_len + 2;
39036379Ssklower 		}
39136379Ssklower 		if (inbound_oidx->cni_priorp) {
39243332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_priorp - 2,
39343332Ssklower 					cp, 3);
39443332Ssklower 			cp += 3;
39536379Ssklower 		}
39636379Ssklower 		if (inbound_oidx->cni_securep) {
39743332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_securep - 2, cp,
39837469Ssklower 				(unsigned)(inbound_oidx->cni_secure_len + 2));
39943332Ssklower 			cp += inbound_oidx->cni_secure_len + 2;
40036379Ssklower 		}
40137469Ssklower 		m->m_len += optlen;
40243332Ssklower 		len += optlen;
40336379Ssklower 	}
40436379Ssklower 
40537469Ssklower 	pdu->esis_hdr_len = m0->m_pkthdr.len = len;
40636379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
40736379Ssklower 
40837469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
40936379Ssklower 	siso.siso_family = AF_ISO;
41037469Ssklower 	siso.siso_data[0] = AFI_SNA;
41137469Ssklower 	siso.siso_nlen = 6 + 1;	/* should be taken from snpa_hdr */
41236379Ssklower 										/* +1 is for AFI */
41337469Ssklower 	bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6);
41440775Ssklower 	(ifp->if_output)(ifp, m0, &siso, 0);
41536379Ssklower }
41636379Ssklower 
41736379Ssklower /*
41836379Ssklower  * FUNCTION:		esis_insert_addr
41936379Ssklower  *
42036379Ssklower  * PURPOSE:			Insert an iso_addr into a buffer
42136379Ssklower  *
42236379Ssklower  * RETURNS:			true if buffer was big enough, else false
42336379Ssklower  *
42436379Ssklower  * SIDE EFFECTS:	Increment buf & len according to size of iso_addr
42536379Ssklower  *
42636379Ssklower  * NOTES:			Plus 1 here is for length byte
42736379Ssklower  */
42843072Ssklower esis_insert_addr(buf, len, isoa, m, nsellen)
42943332Ssklower register caddr_t			*buf;		/* ptr to buffer to put address into */
43043332Ssklower int							*len;		/* ptr to length of buffer so far */
43143332Ssklower register struct iso_addr	*isoa;		/* ptr to address */
43243332Ssklower register struct mbuf		*m;			/* determine if there remains space */
43343332Ssklower int							nsellen;
43436379Ssklower {
43543332Ssklower 	register int newlen, result = 0;
43636379Ssklower 
43743332Ssklower 	isoa->isoa_len -= nsellen;
43843332Ssklower 	newlen = isoa->isoa_len + 1;
43943332Ssklower 	if (newlen <=  M_TRAILINGSPACE(m)) {
44043332Ssklower 		bcopy((caddr_t)isoa, *buf, newlen);
44143332Ssklower 		*len += newlen;
44243332Ssklower 		*buf += newlen;
44343332Ssklower 		m->m_len += newlen;
44443332Ssklower 		result = 1;
44543332Ssklower 	}
44643332Ssklower 	isoa->isoa_len += nsellen;
44743332Ssklower 	return (result);
44836379Ssklower }
44936379Ssklower 
45039950Ssklower #define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \
45139950Ssklower 	    if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
45239950Ssklower #define ESIS_NEXT_OPTION(b)	{ b += (2 + b[1]); \
45339950Ssklower 	    if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
45440775Ssklower int ESHonly = 1;
45536379Ssklower /*
45636379Ssklower 
45736379Ssklower /*
45836379Ssklower  * FUNCTION:		esis_eshinput
45936379Ssklower  *
46036379Ssklower  * PURPOSE:			Process an incoming ESH pdu
46136379Ssklower  *
46236379Ssklower  * RETURNS:			nothing
46336379Ssklower  *
46436379Ssklower  * SIDE EFFECTS:
46536379Ssklower  *
46636379Ssklower  * NOTES:
46736379Ssklower  */
46836379Ssklower esis_eshinput(m, shp)
46936379Ssklower struct mbuf		*m;	/* esh pdu */
47036379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
47136379Ssklower {
47243072Ssklower 	struct	esis_fixed	*pdu = mtod(m, struct esis_fixed *);
47336379Ssklower 	u_short				ht;		/* holding time */
47443072Ssklower 	struct	iso_addr	*nsap;
47539950Ssklower 	int					naddr;
47637469Ssklower 	u_char				*buf = (u_char *)(pdu + 1);
47739950Ssklower 	u_char				*buflim = pdu->esis_hdr_len + (u_char *)pdu;
47843332Ssklower 	int					new_entry = 0;
47936379Ssklower 
48036379Ssklower 	esis_stat.es_eshrcvd++;
48136379Ssklower 
48236379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
48336379Ssklower 
48439950Ssklower 	naddr = *buf++;
48539950Ssklower 	if (buf >= buflim)
48636379Ssklower 		goto bad;
48743332Ssklower 	if (naddr == 1) {
48839950Ssklower 		ESIS_EXTRACT_ADDR(nsap, buf);
48943332Ssklower 		new_entry = snpac_add(shp->snh_ifp,
49043332Ssklower 								 nsap, shp->snh_shost, SNPA_ES, ht, 0);
49143332Ssklower 	} else {
49243332Ssklower 		int nsellength = 0, nlen = 0;
49343332Ssklower 		{
49443332Ssklower 		/* See if we want to compress out multiple nsaps differing
49543332Ssklower 		   only by nsel */
49643332Ssklower 			register struct ifaddr *ifa = shp->snh_ifp->if_addrlist;
49743332Ssklower 			for (; ifa; ifa = ifa->ifa_next)
49843332Ssklower 				if (ifa->ifa_addr->sa_family == AF_ISO) {
49943332Ssklower 					nsellength = ((struct iso_ifaddr *)ifa)->ia_addr.siso_tlen;
50043332Ssklower 					break;
50143332Ssklower 			}
50243332Ssklower 		}
50339950Ssklower 		IFDEBUG(D_ESISINPUT)
50443332Ssklower 			printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n",
50543332Ssklower 					ht, naddr, nsellength);
50639950Ssklower 		ENDDEBUG
50743332Ssklower 		while (naddr-- > 0) {
50843332Ssklower 			struct iso_addr *nsap2; u_char *buf2;
50943332Ssklower 			ESIS_EXTRACT_ADDR(nsap, buf);
51043332Ssklower 			/* see if there is at least one more nsap in ESH differing
51143332Ssklower 			   only by nsel */
51243332Ssklower 			if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) {
51343332Ssklower 				ESIS_EXTRACT_ADDR(nsap2, buf2);
51443332Ssklower 				IFDEBUG(D_ESISINPUT)
51543332Ssklower 					printf("esis_eshinput: comparing %s ",
51643332Ssklower 						clnp_iso_addrp(nsap));
51743332Ssklower 					printf("and %s\n", clnp_iso_addrp(nsap2));
51843332Ssklower 				ENDDEBUG
51943332Ssklower 				if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr,
52043332Ssklower 						 nsap->isoa_len - nsellength) == 0) {
52143332Ssklower 					nlen = nsellength;
52243332Ssklower 					break;
52343332Ssklower 				}
52443332Ssklower 			}
52543332Ssklower 			new_entry |= snpac_add(shp->snh_ifp,
52643332Ssklower 									nsap, shp->snh_shost, SNPA_ES, ht, nlen);
52743332Ssklower 			nlen = 0;
52843332Ssklower 		}
52939950Ssklower 	}
53043332Ssklower 	IFDEBUG(D_ESISINPUT)
53143332Ssklower 		printf("esis_eshinput: nsap %s is %s\n",
53243332Ssklower 			clnp_iso_addrp(nsap), new_entry ? "new" : "old");
53343332Ssklower 	ENDDEBUG
53443332Ssklower 	if (new_entry && (iso_systype & SNPA_IS))
53543332Ssklower 		esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time,
53643332Ssklower 						shp->snh_shost, 6, (struct iso_addr *)0);
53737469Ssklower bad:
53839950Ssklower 	return;
53936379Ssklower }
54036379Ssklower 
54136379Ssklower /*
54236379Ssklower  * FUNCTION:		esis_ishinput
54336379Ssklower  *
54436379Ssklower  * PURPOSE:			process an incoming ISH pdu
54536379Ssklower  *
54636379Ssklower  * RETURNS:
54736379Ssklower  *
54836379Ssklower  * SIDE EFFECTS:
54936379Ssklower  *
55036379Ssklower  * NOTES:
55136379Ssklower  */
55236379Ssklower esis_ishinput(m, shp)
55336379Ssklower struct mbuf		*m;	/* esh pdu */
55436379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
55536379Ssklower {
55636379Ssklower 	struct esis_fixed	*pdu = mtod(m, struct esis_fixed *);
55739950Ssklower 	u_short				ht;					/* holding time */
55839950Ssklower 	struct iso_addr		*nsap; 				/* Network Entity Title */
55939950Ssklower 	register u_char		*buf = (u_char *) (pdu + 1);
56039950Ssklower 	register u_char		*buflim = pdu->esis_hdr_len + (u_char *)pdu;
56139950Ssklower 	int					new_entry;
56236379Ssklower 
56336379Ssklower 	esis_stat.es_ishrcvd++;
56436379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
56536379Ssklower 
56636379Ssklower 	IFDEBUG(D_ESISINPUT)
56736379Ssklower 		printf("esis_ishinput: ish: ht %d\n", ht);
56836379Ssklower 	ENDDEBUG
56939950Ssklower 	if (ESHonly)
57037469Ssklower 		goto bad;
57136379Ssklower 
57239950Ssklower 	ESIS_EXTRACT_ADDR(nsap, buf);
57339950Ssklower 
57439950Ssklower 	while (buf < buflim) {
57539950Ssklower 		switch (*buf) {
57637469Ssklower 		case ESISOVAL_ESCT:
57739950Ssklower 			if (buf[1] != 2)
57837469Ssklower 				goto bad;
57939950Ssklower 			CTOH(buf[2], buf[3], esis_config_time);
58039950Ssklower 			break;
58139950Ssklower 
58239950Ssklower 		default:
58339950Ssklower 			printf("Unknown ISH option: %x\n", *buf);
58437469Ssklower 		}
58539950Ssklower 		ESIS_NEXT_OPTION(buf);
58637469Ssklower 	}
58743332Ssklower 	new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0);
58837469Ssklower 	IFDEBUG(D_ESISINPUT)
58937469Ssklower 		printf("esis_ishinput: nsap %s is %s\n",
59037469Ssklower 			clnp_iso_addrp(nsap), new_entry ? "new" : "old");
59137469Ssklower 	ENDDEBUG
59237469Ssklower 
59337469Ssklower 	if (new_entry)
59437469Ssklower 		esis_shoutput(shp->snh_ifp,
59537469Ssklower 			iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
59643332Ssklower 			esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0);
59739950Ssklower bad:
59839950Ssklower 	return;
59936379Ssklower }
60036379Ssklower 
60136379Ssklower /*
60236379Ssklower  * FUNCTION:		esis_rdinput
60336379Ssklower  *
60436379Ssklower  * PURPOSE:			Process an incoming RD pdu
60536379Ssklower  *
60636379Ssklower  * RETURNS:
60736379Ssklower  *
60836379Ssklower  * SIDE EFFECTS:
60936379Ssklower  *
61036379Ssklower  * NOTES:
61136379Ssklower  */
61236379Ssklower esis_rdinput(m0, shp)
61336379Ssklower struct mbuf		*m0;	/* esh pdu */
61436379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
61536379Ssklower {
61636379Ssklower 	struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
61736379Ssklower 	u_short				ht;		/* holding time */
61839950Ssklower 	struct iso_addr		*da, *net = 0, *netmask = 0, *snpamask = 0;
61939950Ssklower 	register struct iso_addr *bsnpa;
62039950Ssklower 	register u_char		*buf = (u_char *)(pdu + 1);
62139950Ssklower 	register u_char		*buflim = pdu->esis_hdr_len + (u_char *)pdu;
62236379Ssklower 
62336379Ssklower 	esis_stat.es_rdrcvd++;
62436379Ssklower 
62536379Ssklower 	/* intermediate systems ignore redirects */
62636379Ssklower 	if (iso_systype & SNPA_IS)
627*43421Ssklower 		return;
62839950Ssklower 	if (ESHonly)
629*43421Ssklower 		return;
63036379Ssklower 
63136379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
63239950Ssklower 	if (buf >= buflim)
633*43421Ssklower 		return;
63436379Ssklower 
63536379Ssklower 	/* Extract DA */
63639950Ssklower 	ESIS_EXTRACT_ADDR(da, buf);
63737469Ssklower 
63836379Ssklower 	/* Extract better snpa */
63939950Ssklower 	ESIS_EXTRACT_ADDR(bsnpa, buf);
64039950Ssklower 
64137469Ssklower 	/* Extract NET if present */
64239950Ssklower 	if (buf < buflim) {
64343332Ssklower 		if (*buf == 0)
64443332Ssklower 			buf++; /* no NET present, skip NETL anyway */
64543332Ssklower 		else
64643332Ssklower 			ESIS_EXTRACT_ADDR(net, buf);
64736379Ssklower 	}
64836379Ssklower 
64937469Ssklower 	/* process options */
65039950Ssklower 	while (buf < buflim) {
65139950Ssklower 		switch (*buf) {
65237469Ssklower 		case ESISOVAL_SNPAMASK:
65337469Ssklower 			if (snpamask) /* duplicate */
654*43421Ssklower 				return;
65539950Ssklower 			snpamask = (struct iso_addr *)(buf + 1);
65637469Ssklower 			break;
65737469Ssklower 
65837469Ssklower 		case ESISOVAL_NETMASK:
65937469Ssklower 			if (netmask) /* duplicate */
660*43421Ssklower 				return;
66139950Ssklower 			netmask = (struct iso_addr *)(buf + 1);
66239950Ssklower 			break;
66339950Ssklower 
66439950Ssklower 		default:
66539950Ssklower 			printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]);
66637469Ssklower 		}
66739950Ssklower 		ESIS_NEXT_OPTION(buf);
66836379Ssklower 	}
66936379Ssklower 
67036379Ssklower 	IFDEBUG(D_ESISINPUT)
67137469Ssklower 		printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da));
67237469Ssklower 		if (net)
67337469Ssklower 			printf("\t: net %s\n", clnp_iso_addrp(net));
67436379Ssklower 	ENDDEBUG
67536379Ssklower 	/*
67636379Ssklower 	 *	If netl is zero, then redirect is to an ES. We need to add an entry
67736379Ssklower 	 *	to the snpa cache for (destination, better snpa).
67836379Ssklower 	 *	If netl is not zero, then the redirect is to an IS. In this
67936379Ssklower 	 *	case, add an snpa cache entry for (net, better snpa).
68036379Ssklower 	 *
68136379Ssklower 	 *	If the redirect is to an IS, add a route entry towards that
68236379Ssklower 	 *	IS.
68336379Ssklower 	 */
68439950Ssklower 	if (net == 0 || net->isoa_len == 0 || snpamask) {
68536379Ssklower 		/* redirect to an ES */
68639950Ssklower 		snpac_add(shp->snh_ifp, da,
68743332Ssklower 				bsnpa->isoa_genaddr, SNPA_ES, ht, 0);
68836379Ssklower 	} else {
68939950Ssklower 		snpac_add(shp->snh_ifp, net,
69043332Ssklower 				bsnpa->isoa_genaddr, SNPA_IS, ht, 0);
69139950Ssklower 		snpac_addrt(shp->snh_ifp, da, net, netmask);
69236379Ssklower 	}
693*43421Ssklower bad: ;    /* Needed by ESIS_NEXT_OPTION */
69436379Ssklower }
69536379Ssklower 
69636379Ssklower /*
69736379Ssklower  * FUNCTION:		esis_config
69836379Ssklower  *
69936379Ssklower  * PURPOSE:			Report configuration
70036379Ssklower  *
70136379Ssklower  * RETURNS:
70236379Ssklower  *
70336379Ssklower  * SIDE EFFECTS:
70436379Ssklower  *
70536379Ssklower  * NOTES:			Called every esis_config_time seconds
70636379Ssklower  */
70736379Ssklower esis_config()
70836379Ssklower {
70936379Ssklower 	register struct ifnet	*ifp;
71036379Ssklower 
71136379Ssklower 	timeout(esis_config, (caddr_t)0, hz * esis_config_time);
71236379Ssklower 
71336379Ssklower 	/*
71436379Ssklower 	 *	Report configuration for each interface that
71536379Ssklower 	 *	- is UP
71636379Ssklower 	 *	- is not loopback
71736379Ssklower 	 *	- has an ISO address
71836379Ssklower 	 */
71936379Ssklower 
72036379Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
72136379Ssklower 		if ((ifp->if_flags & IFF_UP) &&
72236379Ssklower 			((ifp->if_flags & IFF_LOOPBACK) == 0)) {
72336379Ssklower 			/* search for an ISO address family */
72436379Ssklower 			struct ifaddr	*ia;
72536379Ssklower 
72636379Ssklower 			for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {
72737469Ssklower 				if (ia->ifa_addr->sa_family == AF_ISO) {
72836379Ssklower 					esis_shoutput(ifp,
72936379Ssklower 						iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
73036379Ssklower 						esis_holding_time,
73143332Ssklower 						(caddr_t)(iso_systype & SNPA_ES ? all_is_snpa :
73243332Ssklower 						all_es_snpa), 6, (struct iso_addr *)0);
73336379Ssklower 					break;
73436379Ssklower 				}
73536379Ssklower 			}
73636379Ssklower 		}
73736379Ssklower 	}
73836379Ssklower }
73936379Ssklower 
74036379Ssklower /*
74136379Ssklower  * FUNCTION:		esis_shoutput
74236379Ssklower  *
74336379Ssklower  * PURPOSE:			Transmit an esh or ish pdu
74436379Ssklower  *
74536379Ssklower  * RETURNS:			nothing
74636379Ssklower  *
74736379Ssklower  * SIDE EFFECTS:
74836379Ssklower  *
74936379Ssklower  * NOTES:
75036379Ssklower  */
75143332Ssklower esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa)
75236379Ssklower struct ifnet	*ifp;
75336379Ssklower int				type;
75436379Ssklower short			ht;
75536379Ssklower caddr_t 		sn_addr;
75636379Ssklower int				sn_len;
75743332Ssklower struct	iso_addr *isoa;
75836379Ssklower {
75936379Ssklower 	struct mbuf			*m, *m0;
76036379Ssklower 	caddr_t				cp, naddrp;
76136379Ssklower 	int					naddr = 0;
76236379Ssklower 	struct esis_fixed	*pdu;
76343332Ssklower 	struct iso_ifaddr	*ia;
76437469Ssklower 	int					len;
76536379Ssklower 	struct sockaddr_iso	siso;
76636379Ssklower 
76736379Ssklower 	if (type == ESIS_ESH)
76836379Ssklower 		esis_stat.es_eshsent++;
76936379Ssklower 	else if (type == ESIS_ISH)
77036379Ssklower 		esis_stat.es_ishsent++;
77136379Ssklower 	else {
77236379Ssklower 		printf("esis_shoutput: bad pdu type\n");
77336379Ssklower 		return;
77436379Ssklower 	}
77536379Ssklower 
77636379Ssklower 	IFDEBUG(D_ESISOUTPUT)
77736379Ssklower 		int	i;
77836379Ssklower 		printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ",
77936379Ssklower 			ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish",
78036379Ssklower 			ht, sn_len);
78136379Ssklower 		for (i=0; i<sn_len; i++)
78236379Ssklower 			printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' ');
78336379Ssklower 		printf("\n");
78436379Ssklower 	ENDDEBUG
78536379Ssklower 
78637469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
78736379Ssklower 		esis_stat.es_nomem++;
78836379Ssklower 		return;
78936379Ssklower 	}
79037469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
79136379Ssklower 
79236379Ssklower 	pdu = mtod(m, struct esis_fixed *);
79337469Ssklower 	naddrp = cp = (caddr_t)(pdu + 1);
79436379Ssklower 	len = sizeof(struct esis_fixed);
79536379Ssklower 
79636379Ssklower 	/*
79736379Ssklower 	 *	Build fixed part of header
79836379Ssklower 	 */
79936379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
80036379Ssklower 	pdu->esis_vers = ESIS_VERSION;
80136379Ssklower 	pdu->esis_type = type;
80236379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
80336379Ssklower 
80436379Ssklower 	if (type == ESIS_ESH) {
80536379Ssklower 		cp++;
80636379Ssklower 		len++;
80736379Ssklower 	}
80836379Ssklower 
80937469Ssklower 	m->m_len = len;
81043332Ssklower 	if (isoa) {
81143332Ssklower 		/*
81243332Ssklower 		 * Here we are responding to a clnp packet sent to an NSAP
81343332Ssklower 		 * that is ours which was sent to the MAC addr all_es's.
81443332Ssklower 		 * It is possible that we did not specifically advertise this
81543332Ssklower 		 * NSAP, even though it is ours, so we will respond
81643332Ssklower 		 * directly to the sender that we are here.  If we do have
81743332Ssklower 		 * multiple NSEL's we'll tack them on so he can compress them out.
81843332Ssklower 		 */
81943332Ssklower 		(void) esis_insert_addr(&cp, &len, isoa, m, 0);
82043332Ssklower 		naddr = 1;
82143332Ssklower 	}
82243332Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
82343332Ssklower 		int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0);
82443332Ssklower 		int n = ia->ia_addr.siso_nlen;
82543332Ssklower 		register struct iso_ifaddr *ia2;
82643332Ssklower 
82743332Ssklower 		if (type == ESIS_ISH && naddr > 0)
82843332Ssklower 			break;
82943332Ssklower 		for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next)
83043332Ssklower 			if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0)
83143332Ssklower 					break;
83243332Ssklower 		if (ia2 != ia)
83343332Ssklower 			continue;	/* Means we have previously copied this nsap */
83443332Ssklower 		if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) {
83543332Ssklower 			isoa = 0;
83643332Ssklower 			continue;	/* Ditto */
83736379Ssklower 		}
83843332Ssklower 		IFDEBUG(D_ESISOUTPUT)
83943332Ssklower 			printf("esis_shoutput: adding NSAP %s\n",
84043332Ssklower 				clnp_iso_addrp(&ia->ia_addr.siso_addr));
84143332Ssklower 		ENDDEBUG
84243332Ssklower 		if (!esis_insert_addr(&cp, &len,
84343332Ssklower 							  &ia->ia_addr.siso_addr, m, nsellen)) {
84443332Ssklower 			EXTEND_PACKET(m, m0, cp);
84543332Ssklower 			(void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m,
84643332Ssklower 									nsellen);
84743332Ssklower 		}
84843332Ssklower 		naddr++;
84936379Ssklower 	}
85036379Ssklower 
85136379Ssklower 	if (type == ESIS_ESH)
85236379Ssklower 		*naddrp = naddr;
85336379Ssklower 
85437469Ssklower 	m0->m_pkthdr.len = len;
85537469Ssklower 	pdu->esis_hdr_len = len;
85636379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
85736379Ssklower 
85837469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
85936379Ssklower 	siso.siso_family = AF_ISO;
86037469Ssklower 	siso.siso_data[0] = AFI_SNA;
86137469Ssklower 	siso.siso_nlen = sn_len + 1;
86237469Ssklower 	bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len);
86340775Ssklower 	(ifp->if_output)(ifp, m0, &siso, 0);
86436379Ssklower }
86536379Ssklower 
86636379Ssklower /*
867*43421Ssklower  * FUNCTION:		isis_input
868*43421Ssklower  *
869*43421Ssklower  * PURPOSE:			Process an incoming isis packet
870*43421Ssklower  *
871*43421Ssklower  * RETURNS:			nothing
872*43421Ssklower  *
873*43421Ssklower  * SIDE EFFECTS:
874*43421Ssklower  *
875*43421Ssklower  * NOTES:
876*43421Ssklower  */
877*43421Ssklower isis_input(m0, shp)
878*43421Ssklower struct mbuf		*m0;		/* ptr to first mbuf of pkt */
879*43421Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
880*43421Ssklower {
881*43421Ssklower 	register int type;
882*43421Ssklower 	struct rawcb *rp;
883*43421Ssklower 	struct ifnet *ifp = shp->snh_ifp;
884*43421Ssklower 	struct sockbuf *sb = 0;
885*43421Ssklower 	char workbuf[16];
886*43421Ssklower 	struct mbuf *mm;
887*43421Ssklower 
888*43421Ssklower 	IFDEBUG(D_ISISINPUT)
889*43421Ssklower 		int i;
890*43421Ssklower 
891*43421Ssklower 		printf("isis_input: pkt on ifp x%x (%s%d): from:", ifp,
892*43421Ssklower 			ifp->if_name, ifp->if_unit);
893*43421Ssklower 		for (i=0; i<6; i++)
894*43421Ssklower 			printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' ');
895*43421Ssklower 		printf(" to:");
896*43421Ssklower 		for (i=0; i<6; i++)
897*43421Ssklower 			printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' ');
898*43421Ssklower 		printf("\n");
899*43421Ssklower 	ENDDEBUG
900*43421Ssklower 	esis_dl.sdl_alen = ifp->if_addrlen;
901*43421Ssklower 	esis_dl.sdl_index = ifp->if_index;
902*43421Ssklower 	bcopy(shp->snh_shost, (caddr_t)esis_dl.sdl_data, esis_dl.sdl_alen);
903*43421Ssklower 	for (rp = esis_pcb.rcb_next; rp != &esis_pcb; rp = rp->rcb_next) {
904*43421Ssklower 		if (sb == 0) {
905*43421Ssklower 			sb = &rp->rcb_socket->so_rcv;
906*43421Ssklower 			continue;
907*43421Ssklower 		}
908*43421Ssklower 		if (mm = m_copy(m0, 0, M_COPYALL)) { /*can't block at interrupt level */
909*43421Ssklower 			if (sbappendaddr(&rp->rcb_socket->so_rcv,
910*43421Ssklower 							  &esis_dl, mm, (struct mbuf *)0) != 0)
911*43421Ssklower 				sorwakeup(rp->rcb_socket);
912*43421Ssklower 			else {
913*43421Ssklower 				IFDEBUG(D_ISISINPUT)
914*43421Ssklower 					printf("Error in sbappenaddr, mm = 0x%x\n", mm);
915*43421Ssklower 				ENDDEBUG
916*43421Ssklower 				m_freem(mm);
917*43421Ssklower 			}
918*43421Ssklower 		}
919*43421Ssklower 	}
920*43421Ssklower 	if (sb) {
921*43421Ssklower 		if (sbappendaddr(&rp->rcb_socket->so_rcv,
922*43421Ssklower 							  &esis_dl, mm, (struct mbuf *)0) != 0)
923*43421Ssklower 			sorwakeup(rp->rcb_socket);
924*43421Ssklower 		else
925*43421Ssklower 			m_freem(m0);
926*43421Ssklower 	}
927*43421Ssklower }
928*43421Ssklower 
929*43421Ssklower isis_output(sdl, m)
930*43421Ssklower register struct sockaddr_dl	*sdl;
931*43421Ssklower struct mbuf *m;
932*43421Ssklower {
933*43421Ssklower 	register struct ifnet *ifp;
934*43421Ssklower 	struct ifaddr *ifa, *ifa_ifwithnet();
935*43421Ssklower 	struct sockaddr_iso siso;
936*43421Ssklower 	int error = 0;
937*43421Ssklower 	unsigned sn_len;
938*43421Ssklower 
939*43421Ssklower 	ifa = ifa_ifwithnet(sdl);	/* extract ifp from sockaddr_dl */
940*43421Ssklower 	if (ifa == 0) {
941*43421Ssklower 		IFDEBUG(D_ISISOUTPUT)
942*43421Ssklower 			printf("isis_output: interface not found\n");
943*43421Ssklower 		ENDDEBUG
944*43421Ssklower 		error = EINVAL;
945*43421Ssklower 		goto release;
946*43421Ssklower 	}
947*43421Ssklower 	ifp = ifa->ifa_ifp;
948*43421Ssklower 	sn_len = ifp->if_addrlen;
949*43421Ssklower 	IFDEBUG(D_ISISOUTPUT)
950*43421Ssklower 		u_char *cp = (u_char *)LLADDR(sdl), *cplim = cp + sn_len;
951*43421Ssklower 		printf("isis_output: ifp 0x%x (%s%d), to: ",
952*43421Ssklower 			ifp, ifp->if_name, ifp->if_unit);
953*43421Ssklower 		while (cp < cplim) {
954*43421Ssklower 			printf("%x", *cp++);
955*43421Ssklower 			printf("%c", (cp < cplim) ? ':' : ' ');
956*43421Ssklower 		}
957*43421Ssklower 		printf("\n");
958*43421Ssklower 	ENDDEBUG
959*43421Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
960*43421Ssklower 	siso.siso_family = AF_ISO; /* This convention may be useful for X.25 */
961*43421Ssklower 	siso.siso_data[0] = AFI_SNA;
962*43421Ssklower 	siso.siso_nlen = sn_len + 1;
963*43421Ssklower 	bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len);
964*43421Ssklower 	error = (ifp->if_output)(ifp, m, (struct sockaddr *)&siso, 0);
965*43421Ssklower 	if (error) {
966*43421Ssklower 		IFDEBUG(D_ISISOUTPUT)
967*43421Ssklower 			printf("isis_output: error from ether_output is %d\n", error);
968*43421Ssklower 		ENDDEBUG
969*43421Ssklower 	}
970*43421Ssklower 	return (error);
971*43421Ssklower 
972*43421Ssklower release:
973*43421Ssklower 	if (m != NULL)
974*43421Ssklower 		m_freem(m);
975*43421Ssklower 	return(error);
976*43421Ssklower }
977*43421Ssklower 
978*43421Ssklower 
979*43421Ssklower /*
98036379Ssklower  * FUNCTION:		esis_ctlinput
98136379Ssklower  *
98236379Ssklower  * PURPOSE:			Handle the PRC_IFDOWN transition
98336379Ssklower  *
98436379Ssklower  * RETURNS:			nothing
98536379Ssklower  *
98636379Ssklower  * SIDE EFFECTS:
98736379Ssklower  *
98836379Ssklower  * NOTES:			Calls snpac_flush for interface specified.
98936379Ssklower  *					The loop through iso_ifaddr is stupid because
99036379Ssklower  *					back in if_down, we knew the ifp...
99136379Ssklower  */
99236379Ssklower esis_ctlinput(req, siso)
99336379Ssklower int						req;		/* request: we handle only PRC_IFDOWN */
99436379Ssklower struct sockaddr_iso		*siso;		/* address of ifp */
99536379Ssklower {
99636379Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
99736379Ssklower 
99837469Ssklower 	if (req == PRC_IFDOWN)
99937469Ssklower 		for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
100037469Ssklower 			if (iso_addrmatch(IA_SIS(ia), siso))
100137469Ssklower 				snpac_flushifp(ia->ia_ifp);
100237469Ssklower 		}
100336379Ssklower }
100436379Ssklower 
100536379Ssklower #endif	ISO
1006