xref: /csrg-svn/sys/netiso/esis.c (revision 48963)
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*48963Ssklower /*	@(#)esis.c	7.17 (Berkeley) 05/02/91 */
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"
3643451Smckusick #include "systm.h"
3737469Ssklower #include "mbuf.h"
3837469Ssklower #include "domain.h"
3937469Ssklower #include "protosw.h"
4037469Ssklower #include "user.h"
4137469Ssklower #include "socket.h"
4237469Ssklower #include "socketvar.h"
4337469Ssklower #include "errno.h"
4437469Ssklower #include "kernel.h"
4536379Ssklower 
4636379Ssklower #include "../net/if.h"
4743332Ssklower #include "../net/if_dl.h"
4836379Ssklower #include "../net/route.h"
4943421Ssklower #include "../net/raw_cb.h"
5036379Ssklower 
5137469Ssklower #include "iso.h"
5237469Ssklower #include "iso_pcb.h"
5337469Ssklower #include "iso_var.h"
5437469Ssklower #include "iso_snpac.h"
5537469Ssklower #include "clnl.h"
5637469Ssklower #include "clnp.h"
5737469Ssklower #include "clnp_stat.h"
5838841Ssklower #include "esis.h"
5937469Ssklower #include "argo_debug.h"
6036379Ssklower 
6136379Ssklower /*
6236379Ssklower  *	Global variables to esis implementation
6336379Ssklower  *
6436379Ssklower  *	esis_holding_time - the holding time (sec) parameter for outgoing pdus
6536379Ssklower  *	esis_config_time  - the frequency (sec) that hellos are generated
6643421Ssklower  *	esis_esconfig_time - suggested es configuration time placed in the
6743421Ssklower  *						ish.
6836379Ssklower  *
6936379Ssklower  */
7043421Ssklower struct rawcb	esis_pcb;
7136379Ssklower int				esis_sendspace = 2048;
7236379Ssklower int				esis_recvspace = 2048;
7336379Ssklower short			esis_holding_time = ESIS_HT;
7436379Ssklower short			esis_config_time = ESIS_CONFIG;
7543421Ssklower short			esis_esconfig_time = ESIS_CONFIG;
7636379Ssklower extern int		iso_systype;
7743421Ssklower struct sockaddr_dl	esis_dl = { sizeof(esis_dl), AF_LINK };
7843332Ssklower extern char		all_es_snpa[], all_is_snpa[];
7936379Ssklower 
8037469Ssklower #define EXTEND_PACKET(m, mhdr, cp)\
8136379Ssklower 	if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\
8236379Ssklower 		esis_stat.es_nomem++;\
8336379Ssklower 		m_freem(mhdr);\
8436379Ssklower 		return;\
8536379Ssklower 	} else {\
8636379Ssklower 		(m) = (m)->m_next;\
8736379Ssklower 		(cp) = mtod((m), caddr_t);\
8836379Ssklower 	}
8936379Ssklower /*
9036379Ssklower  * FUNCTION:		esis_init
9136379Ssklower  *
9236379Ssklower  * PURPOSE:			Initialize the kernel portion of esis protocol
9336379Ssklower  *
9436379Ssklower  * RETURNS:			nothing
9536379Ssklower  *
9636379Ssklower  * SIDE EFFECTS:
9736379Ssklower  *
9836379Ssklower  * NOTES:
9936379Ssklower  */
10036379Ssklower esis_init()
10136379Ssklower {
10236379Ssklower 	extern struct clnl_protosw clnl_protox[256];
10343892Ssklower 	int	esis_input(), isis_input();
10443892Ssklower 	int	esis_config(), snpac_age();
10536379Ssklower #ifdef	ISO_X25ESIS
10643892Ssklower 	int	x25esis_input();
10736379Ssklower #endif	ISO_X25ESIS
10836379Ssklower 
10943421Ssklower 	esis_pcb.rcb_next = esis_pcb.rcb_prev = &esis_pcb;
11043421Ssklower 	llinfo_llc.lc_next = llinfo_llc.lc_prev = &llinfo_llc;
11136379Ssklower 
11236379Ssklower 	timeout(snpac_age, (caddr_t)0, hz);
11336379Ssklower 	timeout(esis_config, (caddr_t)0, hz);
11436379Ssklower 
11543892Ssklower 	clnl_protox[ISO9542_ESIS].clnl_input = esis_input;
11643892Ssklower 	clnl_protox[ISO10589_ISIS].clnl_input = isis_input;
11736379Ssklower #ifdef	ISO_X25ESIS
11836379Ssklower 	clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input;
11936379Ssklower #endif	ISO_X25ESIS
12036379Ssklower }
12136379Ssklower 
12236379Ssklower /*
12336379Ssklower  * FUNCTION:		esis_usrreq
12436379Ssklower  *
12536379Ssklower  * PURPOSE:			Handle user level esis requests
12636379Ssklower  *
12736379Ssklower  * RETURNS:			0 or appropriate errno
12836379Ssklower  *
12936379Ssklower  * SIDE EFFECTS:
13036379Ssklower  *
13136379Ssklower  */
13237469Ssklower /*ARGSUSED*/
13340775Ssklower esis_usrreq(so, req, m, nam, control)
13436379Ssklower struct socket	*so;		/* socket: used only to get to this code */
13536379Ssklower int				req;		/* request */
13636379Ssklower struct mbuf		*m;			/* data for request */
13736379Ssklower struct mbuf		*nam;		/* optional name */
13840775Ssklower struct mbuf		*control;	/* optional control */
13936379Ssklower {
14043421Ssklower 	struct rawcb *rp = sotorawcb(so);
14143421Ssklower 	int error = 0;
14243421Ssklower 
14343421Ssklower 	if (suser(u.u_cred, &u.u_acflag)) {
14443421Ssklower 		error = EACCES;
14543421Ssklower 		goto release;
14643421Ssklower 	}
14743421Ssklower 	if (rp == NULL && req != PRU_ATTACH) {
14843421Ssklower 		error = EINVAL;
14943421Ssklower 		goto release;
15043421Ssklower 	}
15143421Ssklower 
15243421Ssklower 	switch (req) {
15343421Ssklower 	case PRU_ATTACH:
15443421Ssklower 		if (rp != NULL) {
15543421Ssklower 			error = EINVAL;
15643421Ssklower 			break;
15743421Ssklower 		}
15843421Ssklower 		MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
15943421Ssklower 		if (so->so_pcb = (caddr_t)rp) {
16043421Ssklower 			bzero(so->so_pcb, sizeof(*rp));
16143421Ssklower 			insque(rp, &esis_pcb);
16244946Ssklower 			rp->rcb_socket = so;
16343421Ssklower 			error = soreserve(so, esis_sendspace, esis_recvspace);
16443421Ssklower 		} else
16543421Ssklower 			error = ENOBUFS;
16643421Ssklower 		break;
16743421Ssklower 
16843421Ssklower 	case PRU_SEND:
16943421Ssklower 		if (nam == NULL) {
17043421Ssklower 			error = EINVAL;
17143421Ssklower 			break;
17243421Ssklower 		}
17343421Ssklower 		/* error checking here */
17443421Ssklower 		error = isis_output(mtod(nam,struct sockaddr_dl *), m);
17543421Ssklower 		m = NULL;
17643421Ssklower 		break;
17743421Ssklower 
17843421Ssklower 	case PRU_DETACH:
17943421Ssklower 		raw_detach(rp);
18043421Ssklower 		break;
18143421Ssklower 
18243421Ssklower 	case PRU_SHUTDOWN:
18343421Ssklower 		socantsendmore(so);
18443421Ssklower 		break;
18543421Ssklower 
18643421Ssklower 	case PRU_ABORT:
18743421Ssklower 		soisdisconnected(so);
18843421Ssklower 		raw_detach(rp);
18943421Ssklower 		break;
19043421Ssklower 
19143421Ssklower 	case PRU_SENSE:
19243421Ssklower 		return (0);
19343421Ssklower 
19443421Ssklower 	default:
19543421Ssklower 		return (EOPNOTSUPP);
19643421Ssklower 	}
19743421Ssklower release:
19836379Ssklower 	if (m != NULL)
19936379Ssklower 		m_freem(m);
20036379Ssklower 
20143421Ssklower 	return (error);
20236379Ssklower }
20336379Ssklower 
20436379Ssklower /*
20536379Ssklower  * FUNCTION:		esis_input
20636379Ssklower  *
20736379Ssklower  * PURPOSE:			Process an incoming esis packet
20836379Ssklower  *
20936379Ssklower  * RETURNS:			nothing
21036379Ssklower  *
21136379Ssklower  * SIDE EFFECTS:
21236379Ssklower  *
21336379Ssklower  * NOTES:
21436379Ssklower  */
21536379Ssklower esis_input(m0, shp)
21636379Ssklower struct mbuf		*m0;		/* ptr to first mbuf of pkt */
21736379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
21836379Ssklower {
21943421Ssklower 	register struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
22037469Ssklower 	register int type;
22136379Ssklower 
22236379Ssklower 	/*
22336379Ssklower 	 *	check checksum if necessary
22436379Ssklower 	 */
22537469Ssklower 	if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) {
22636379Ssklower 		esis_stat.es_badcsum++;
22736379Ssklower 		goto bad;
22836379Ssklower 	}
22936379Ssklower 
23036379Ssklower 	/* check version */
23136379Ssklower 	if (pdu->esis_vers != ESIS_VERSION) {
23236379Ssklower 		esis_stat.es_badvers++;
23336379Ssklower 		goto bad;
23436379Ssklower 	}
23537469Ssklower 	type = pdu->esis_type & 0x1f;
23637469Ssklower 	switch (type) {
23736379Ssklower 		case ESIS_ESH:
23836379Ssklower 			esis_eshinput(m0, shp);
23943421Ssklower 			break;
24036379Ssklower 
24136379Ssklower 		case ESIS_ISH:
24236379Ssklower 			esis_ishinput(m0, shp);
24343421Ssklower 			break;
24436379Ssklower 
24536379Ssklower 		case ESIS_RD:
24636379Ssklower 			esis_rdinput(m0, shp);
24743421Ssklower 			break;
24836379Ssklower 
24943421Ssklower 		default:
25036379Ssklower 			esis_stat.es_badtype++;
25136379Ssklower 	}
25236379Ssklower 
25336379Ssklower bad:
25443421Ssklower 	if (esis_pcb.rcb_next != &esis_pcb)
25543421Ssklower 		isis_input(m0, shp);
25643421Ssklower 	else
25743421Ssklower 		m_freem(m0);
25836379Ssklower }
25936379Ssklower 
26036379Ssklower /*
26136379Ssklower  * FUNCTION:		esis_rdoutput
26236379Ssklower  *
26336379Ssklower  * PURPOSE:			Transmit a redirect pdu
26436379Ssklower  *
26536379Ssklower  * RETURNS:			nothing
26636379Ssklower  *
26736379Ssklower  * SIDE EFFECTS:
26836379Ssklower  *
26936379Ssklower  * NOTES:			Assumes there is enough space for fixed part of header,
27036379Ssklower  *					DA, BSNPA and NET in first mbuf.
27136379Ssklower  */
27243332Ssklower esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt)
27336379Ssklower struct snpa_hdr		*inbound_shp;	/* snpa hdr from incoming packet */
27436379Ssklower struct mbuf			*inbound_m;		/* incoming pkt itself */
27536379Ssklower struct clnp_optidx	*inbound_oidx;	/* clnp options assoc with incoming pkt */
27636379Ssklower struct iso_addr		*rd_dstnsap;	/* ultimate destination of pkt */
27743332Ssklower struct rtentry		*rt;			/* snpa cache info regarding next hop of
27836379Ssklower 										pkt */
27936379Ssklower {
28036379Ssklower 	struct mbuf			*m, *m0;
28136379Ssklower 	caddr_t				cp;
28236379Ssklower 	struct esis_fixed	*pdu;
28336379Ssklower 	int					len, total_len = 0;
28436379Ssklower 	struct sockaddr_iso	siso;
28536379Ssklower 	struct ifnet 		*ifp = inbound_shp->snh_ifp;
28643332Ssklower 	struct sockaddr_dl *sdl;
28743332Ssklower 	struct iso_addr *rd_gwnsap;
28836379Ssklower 
28943332Ssklower 	if (rt->rt_flags & RTF_GATEWAY) {
29043332Ssklower 		rd_gwnsap = &((struct sockaddr_iso *)rt->rt_gateway)->siso_addr;
29143332Ssklower 		rt = rtalloc1(rt->rt_gateway, 0);
29243332Ssklower 	} else
29343332Ssklower 		rd_gwnsap = &((struct sockaddr_iso *)rt_key(rt))->siso_addr;
29443332Ssklower 	if (rt == 0 || (sdl = (struct sockaddr_dl *)rt->rt_gateway) == 0 ||
29543332Ssklower 		sdl->sdl_family != AF_LINK) {
29643332Ssklower 		/* maybe we should have a function that you
29743332Ssklower 		   could put in the iso_ifaddr structure
29843332Ssklower 		   which could translate iso_addrs into snpa's
29943332Ssklower 		   where there is a known mapping for that address type */
30043332Ssklower 		esis_stat.es_badtype++;
30143332Ssklower 		return;
30243332Ssklower 	}
30336379Ssklower 	esis_stat.es_rdsent++;
30436379Ssklower 	IFDEBUG(D_ESISOUTPUT)
30536379Ssklower 		printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n",
30636379Ssklower 			ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m,
30736379Ssklower 			inbound_oidx);
30836379Ssklower 		printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap));
30943332Ssklower 		printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap));
31036379Ssklower 	ENDDEBUG
31136379Ssklower 
31237469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
31336379Ssklower 		esis_stat.es_nomem++;
31436379Ssklower 		return;
31536379Ssklower 	}
31637469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
31736379Ssklower 
31836379Ssklower 	pdu = mtod(m, struct esis_fixed *);
31937469Ssklower 	cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */
32036379Ssklower 	len = sizeof(struct esis_fixed);
32136379Ssklower 
32236379Ssklower 	/*
32336379Ssklower 	 *	Build fixed part of header
32436379Ssklower 	 */
32536379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
32636379Ssklower 	pdu->esis_vers = ESIS_VERSION;
32736379Ssklower 	pdu->esis_type = ESIS_RD;
32836379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time);
32936379Ssklower 
33036379Ssklower 	/* Insert destination address */
33143072Ssklower 	(void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0);
33236379Ssklower 
33336379Ssklower 	/* Insert the snpa of better next hop */
33443332Ssklower 	*cp++ = sdl->sdl_alen;
33543332Ssklower 	bcopy(LLADDR(sdl), cp, sdl->sdl_alen);
33643332Ssklower 	cp += sdl->sdl_alen;
33743332Ssklower 	len += (sdl->sdl_alen + 1);
33836379Ssklower 
33936379Ssklower 	/*
34036379Ssklower 	 *	If the next hop is not the destination, then it ought to be
34136379Ssklower 	 *	an IS and it should be inserted next. Else, set the
34236379Ssklower 	 *	NETL to 0
34336379Ssklower 	 */
34436379Ssklower 	/* PHASE2 use mask from ifp of outgoing interface */
34543332Ssklower 	if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) {
34643332Ssklower 		/* this should not happen:
34736379Ssklower 		if ((nhop_sc->sc_flags & SNPA_IS) == 0) {
34836379Ssklower 			printf("esis_rdoutput: next hop is not dst and not an IS\n");
34936379Ssklower 			m_freem(m0);
35036379Ssklower 			return;
35143332Ssklower 		} */
35243332Ssklower 		(void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0);
35336379Ssklower 	} else {
35436379Ssklower 		*cp++ = 0;	/* NETL */
35536379Ssklower 		len++;
35636379Ssklower 	}
35737469Ssklower 	m->m_len = len;
35836379Ssklower 
35936379Ssklower 	/*
36036379Ssklower 	 *	PHASE2
36136379Ssklower 	 *	If redirect is to an IS, add an address mask. The mask to be
36236379Ssklower 	 *	used should be the mask present in the routing entry used to
36336379Ssklower 	 *	forward the original data packet.
36436379Ssklower 	 */
36536379Ssklower 
36636379Ssklower 	/*
36736379Ssklower 	 *	Copy Qos, priority, or security options present in original npdu
36836379Ssklower 	 */
36936379Ssklower 	if (inbound_oidx) {
37043332Ssklower 		/* THIS CODE IS CURRENTLY (mostly) UNTESTED */
37136379Ssklower 		int optlen = 0;
37236379Ssklower 		if (inbound_oidx->cni_qos_formatp)
37336379Ssklower 			optlen += (inbound_oidx->cni_qos_len + 2);
37436379Ssklower 		if (inbound_oidx->cni_priorp)	/* priority option is 1 byte long */
37536379Ssklower 			optlen += 3;
37636379Ssklower 		if (inbound_oidx->cni_securep)
37736379Ssklower 			optlen += (inbound_oidx->cni_secure_len + 2);
37837469Ssklower 		if (M_TRAILINGSPACE(m) < optlen) {
37937469Ssklower 			EXTEND_PACKET(m, m0, cp);
38037469Ssklower 			m->m_len = 0;
38136379Ssklower 			/* assumes MLEN > optlen */
38236379Ssklower 		}
38336379Ssklower 		/* assume MLEN-len > optlen */
38436379Ssklower 		/*
38536379Ssklower 		 *	When copying options, copy from ptr - 2 in order to grab
38636379Ssklower 		 *	the option code and length
38736379Ssklower 		 */
38836379Ssklower 		if (inbound_oidx->cni_qos_formatp) {
38943332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_qos_formatp - 2,
39043332Ssklower 				cp, (unsigned)(inbound_oidx->cni_qos_len + 2));
39143332Ssklower 			cp += inbound_oidx->cni_qos_len + 2;
39236379Ssklower 		}
39336379Ssklower 		if (inbound_oidx->cni_priorp) {
39443332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_priorp - 2,
39543332Ssklower 					cp, 3);
39643332Ssklower 			cp += 3;
39736379Ssklower 		}
39836379Ssklower 		if (inbound_oidx->cni_securep) {
39943332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_securep - 2, cp,
40037469Ssklower 				(unsigned)(inbound_oidx->cni_secure_len + 2));
40143332Ssklower 			cp += inbound_oidx->cni_secure_len + 2;
40236379Ssklower 		}
40337469Ssklower 		m->m_len += optlen;
40443332Ssklower 		len += optlen;
40536379Ssklower 	}
40636379Ssklower 
40737469Ssklower 	pdu->esis_hdr_len = m0->m_pkthdr.len = len;
40836379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
40936379Ssklower 
41037469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
41136379Ssklower 	siso.siso_family = AF_ISO;
41237469Ssklower 	siso.siso_data[0] = AFI_SNA;
41337469Ssklower 	siso.siso_nlen = 6 + 1;	/* should be taken from snpa_hdr */
41436379Ssklower 										/* +1 is for AFI */
41537469Ssklower 	bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6);
41640775Ssklower 	(ifp->if_output)(ifp, m0, &siso, 0);
41736379Ssklower }
41836379Ssklower 
41936379Ssklower /*
42036379Ssklower  * FUNCTION:		esis_insert_addr
42136379Ssklower  *
42236379Ssklower  * PURPOSE:			Insert an iso_addr into a buffer
42336379Ssklower  *
42436379Ssklower  * RETURNS:			true if buffer was big enough, else false
42536379Ssklower  *
42636379Ssklower  * SIDE EFFECTS:	Increment buf & len according to size of iso_addr
42736379Ssklower  *
42836379Ssklower  * NOTES:			Plus 1 here is for length byte
42936379Ssklower  */
43043072Ssklower esis_insert_addr(buf, len, isoa, m, nsellen)
43143332Ssklower register caddr_t			*buf;		/* ptr to buffer to put address into */
43243332Ssklower int							*len;		/* ptr to length of buffer so far */
43343332Ssklower register struct iso_addr	*isoa;		/* ptr to address */
43443332Ssklower register struct mbuf		*m;			/* determine if there remains space */
43543332Ssklower int							nsellen;
43636379Ssklower {
43743332Ssklower 	register int newlen, result = 0;
43836379Ssklower 
43943332Ssklower 	isoa->isoa_len -= nsellen;
44043332Ssklower 	newlen = isoa->isoa_len + 1;
44143332Ssklower 	if (newlen <=  M_TRAILINGSPACE(m)) {
44243332Ssklower 		bcopy((caddr_t)isoa, *buf, newlen);
44343332Ssklower 		*len += newlen;
44443332Ssklower 		*buf += newlen;
44543332Ssklower 		m->m_len += newlen;
44643332Ssklower 		result = 1;
44743332Ssklower 	}
44843332Ssklower 	isoa->isoa_len += nsellen;
44943332Ssklower 	return (result);
45036379Ssklower }
45136379Ssklower 
45239950Ssklower #define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \
45339950Ssklower 	    if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
45439950Ssklower #define ESIS_NEXT_OPTION(b)	{ b += (2 + b[1]); \
45539950Ssklower 	    if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
45643430Ssklower int ESHonly = 0;
45736379Ssklower /*
45836379Ssklower 
45936379Ssklower /*
46036379Ssklower  * FUNCTION:		esis_eshinput
46136379Ssklower  *
46236379Ssklower  * PURPOSE:			Process an incoming ESH pdu
46336379Ssklower  *
46436379Ssklower  * RETURNS:			nothing
46536379Ssklower  *
46636379Ssklower  * SIDE EFFECTS:
46736379Ssklower  *
46836379Ssklower  * NOTES:
46936379Ssklower  */
47036379Ssklower esis_eshinput(m, shp)
47136379Ssklower struct mbuf		*m;	/* esh pdu */
47236379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
47336379Ssklower {
47443072Ssklower 	struct	esis_fixed	*pdu = mtod(m, struct esis_fixed *);
47536379Ssklower 	u_short				ht;		/* holding time */
47643072Ssklower 	struct	iso_addr	*nsap;
47739950Ssklower 	int					naddr;
47837469Ssklower 	u_char				*buf = (u_char *)(pdu + 1);
47939950Ssklower 	u_char				*buflim = pdu->esis_hdr_len + (u_char *)pdu;
48043332Ssklower 	int					new_entry = 0;
48136379Ssklower 
48236379Ssklower 	esis_stat.es_eshrcvd++;
48336379Ssklower 
48436379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
48536379Ssklower 
48639950Ssklower 	naddr = *buf++;
48739950Ssklower 	if (buf >= buflim)
48836379Ssklower 		goto bad;
48943332Ssklower 	if (naddr == 1) {
49039950Ssklower 		ESIS_EXTRACT_ADDR(nsap, buf);
49143332Ssklower 		new_entry = snpac_add(shp->snh_ifp,
49243332Ssklower 								 nsap, shp->snh_shost, SNPA_ES, ht, 0);
49343332Ssklower 	} else {
49443332Ssklower 		int nsellength = 0, nlen = 0;
49543332Ssklower 		{
49643332Ssklower 		/* See if we want to compress out multiple nsaps differing
49743332Ssklower 		   only by nsel */
49843332Ssklower 			register struct ifaddr *ifa = shp->snh_ifp->if_addrlist;
49943332Ssklower 			for (; ifa; ifa = ifa->ifa_next)
50043332Ssklower 				if (ifa->ifa_addr->sa_family == AF_ISO) {
50143332Ssklower 					nsellength = ((struct iso_ifaddr *)ifa)->ia_addr.siso_tlen;
50243332Ssklower 					break;
50343332Ssklower 			}
50443332Ssklower 		}
50539950Ssklower 		IFDEBUG(D_ESISINPUT)
50643332Ssklower 			printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n",
50743332Ssklower 					ht, naddr, nsellength);
50839950Ssklower 		ENDDEBUG
50943332Ssklower 		while (naddr-- > 0) {
51043332Ssklower 			struct iso_addr *nsap2; u_char *buf2;
51143332Ssklower 			ESIS_EXTRACT_ADDR(nsap, buf);
51243332Ssklower 			/* see if there is at least one more nsap in ESH differing
51343332Ssklower 			   only by nsel */
51443332Ssklower 			if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) {
51543332Ssklower 				ESIS_EXTRACT_ADDR(nsap2, buf2);
51643332Ssklower 				IFDEBUG(D_ESISINPUT)
51743332Ssklower 					printf("esis_eshinput: comparing %s ",
51843332Ssklower 						clnp_iso_addrp(nsap));
51943332Ssklower 					printf("and %s\n", clnp_iso_addrp(nsap2));
52043332Ssklower 				ENDDEBUG
52143332Ssklower 				if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr,
52243332Ssklower 						 nsap->isoa_len - nsellength) == 0) {
52343332Ssklower 					nlen = nsellength;
52443332Ssklower 					break;
52543332Ssklower 				}
52643332Ssklower 			}
52743332Ssklower 			new_entry |= snpac_add(shp->snh_ifp,
52843332Ssklower 									nsap, shp->snh_shost, SNPA_ES, ht, nlen);
52943332Ssklower 			nlen = 0;
53043332Ssklower 		}
53139950Ssklower 	}
53243332Ssklower 	IFDEBUG(D_ESISINPUT)
53343332Ssklower 		printf("esis_eshinput: nsap %s is %s\n",
53443332Ssklower 			clnp_iso_addrp(nsap), new_entry ? "new" : "old");
53543332Ssklower 	ENDDEBUG
53643332Ssklower 	if (new_entry && (iso_systype & SNPA_IS))
53743332Ssklower 		esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time,
53843332Ssklower 						shp->snh_shost, 6, (struct iso_addr *)0);
53937469Ssklower bad:
54039950Ssklower 	return;
54136379Ssklower }
54236379Ssklower 
54336379Ssklower /*
54436379Ssklower  * FUNCTION:		esis_ishinput
54536379Ssklower  *
54636379Ssklower  * PURPOSE:			process an incoming ISH pdu
54736379Ssklower  *
54836379Ssklower  * RETURNS:
54936379Ssklower  *
55036379Ssklower  * SIDE EFFECTS:
55136379Ssklower  *
55236379Ssklower  * NOTES:
55336379Ssklower  */
55436379Ssklower esis_ishinput(m, shp)
55536379Ssklower struct mbuf		*m;	/* esh pdu */
55636379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
55736379Ssklower {
55836379Ssklower 	struct esis_fixed	*pdu = mtod(m, struct esis_fixed *);
55943430Ssklower 	u_short				ht, newct;			/* holding time */
56039950Ssklower 	struct iso_addr		*nsap; 				/* Network Entity Title */
56139950Ssklower 	register u_char		*buf = (u_char *) (pdu + 1);
56239950Ssklower 	register u_char		*buflim = pdu->esis_hdr_len + (u_char *)pdu;
56339950Ssklower 	int					new_entry;
56436379Ssklower 
56536379Ssklower 	esis_stat.es_ishrcvd++;
56636379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
56736379Ssklower 
56836379Ssklower 	IFDEBUG(D_ESISINPUT)
56936379Ssklower 		printf("esis_ishinput: ish: ht %d\n", ht);
57036379Ssklower 	ENDDEBUG
57139950Ssklower 	if (ESHonly)
57237469Ssklower 		goto bad;
57336379Ssklower 
57439950Ssklower 	ESIS_EXTRACT_ADDR(nsap, buf);
57539950Ssklower 
57639950Ssklower 	while (buf < buflim) {
57739950Ssklower 		switch (*buf) {
57837469Ssklower 		case ESISOVAL_ESCT:
57944946Ssklower 			if (iso_systype & SNPA_IS)
58044946Ssklower 				break;
58139950Ssklower 			if (buf[1] != 2)
58237469Ssklower 				goto bad;
58343430Ssklower 			CTOH(buf[2], buf[3], newct);
58443430Ssklower 			if (esis_config_time != newct) {
58543430Ssklower 				untimeout(esis_config,0);
58643430Ssklower 				esis_config_time = newct;
58743430Ssklower 				esis_config();
58843430Ssklower 			}
58939950Ssklower 			break;
59039950Ssklower 
59139950Ssklower 		default:
59239950Ssklower 			printf("Unknown ISH option: %x\n", *buf);
59337469Ssklower 		}
59439950Ssklower 		ESIS_NEXT_OPTION(buf);
59537469Ssklower 	}
59643332Ssklower 	new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0);
59737469Ssklower 	IFDEBUG(D_ESISINPUT)
59837469Ssklower 		printf("esis_ishinput: nsap %s is %s\n",
59937469Ssklower 			clnp_iso_addrp(nsap), new_entry ? "new" : "old");
60037469Ssklower 	ENDDEBUG
60137469Ssklower 
60237469Ssklower 	if (new_entry)
60337469Ssklower 		esis_shoutput(shp->snh_ifp,
60437469Ssklower 			iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
60543332Ssklower 			esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0);
60639950Ssklower bad:
60739950Ssklower 	return;
60836379Ssklower }
60936379Ssklower 
61036379Ssklower /*
61136379Ssklower  * FUNCTION:		esis_rdinput
61236379Ssklower  *
61336379Ssklower  * PURPOSE:			Process an incoming RD pdu
61436379Ssklower  *
61536379Ssklower  * RETURNS:
61636379Ssklower  *
61736379Ssklower  * SIDE EFFECTS:
61836379Ssklower  *
61936379Ssklower  * NOTES:
62036379Ssklower  */
62136379Ssklower esis_rdinput(m0, shp)
62236379Ssklower struct mbuf		*m0;	/* esh pdu */
62336379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
62436379Ssklower {
62536379Ssklower 	struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
62636379Ssklower 	u_short				ht;		/* holding time */
62739950Ssklower 	struct iso_addr		*da, *net = 0, *netmask = 0, *snpamask = 0;
62839950Ssklower 	register struct iso_addr *bsnpa;
62939950Ssklower 	register u_char		*buf = (u_char *)(pdu + 1);
63039950Ssklower 	register u_char		*buflim = pdu->esis_hdr_len + (u_char *)pdu;
63136379Ssklower 
63236379Ssklower 	esis_stat.es_rdrcvd++;
63336379Ssklower 
63436379Ssklower 	/* intermediate systems ignore redirects */
63536379Ssklower 	if (iso_systype & SNPA_IS)
63643421Ssklower 		return;
63739950Ssklower 	if (ESHonly)
63843421Ssklower 		return;
63936379Ssklower 
64036379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
64139950Ssklower 	if (buf >= buflim)
64243421Ssklower 		return;
64336379Ssklower 
64436379Ssklower 	/* Extract DA */
64539950Ssklower 	ESIS_EXTRACT_ADDR(da, buf);
64637469Ssklower 
64736379Ssklower 	/* Extract better snpa */
64839950Ssklower 	ESIS_EXTRACT_ADDR(bsnpa, buf);
64939950Ssklower 
65037469Ssklower 	/* Extract NET if present */
65139950Ssklower 	if (buf < buflim) {
65243332Ssklower 		if (*buf == 0)
65343332Ssklower 			buf++; /* no NET present, skip NETL anyway */
65443332Ssklower 		else
65543332Ssklower 			ESIS_EXTRACT_ADDR(net, buf);
65636379Ssklower 	}
65736379Ssklower 
65837469Ssklower 	/* process options */
65939950Ssklower 	while (buf < buflim) {
66039950Ssklower 		switch (*buf) {
66137469Ssklower 		case ESISOVAL_SNPAMASK:
66237469Ssklower 			if (snpamask) /* duplicate */
66343421Ssklower 				return;
66439950Ssklower 			snpamask = (struct iso_addr *)(buf + 1);
66537469Ssklower 			break;
66637469Ssklower 
66737469Ssklower 		case ESISOVAL_NETMASK:
66837469Ssklower 			if (netmask) /* duplicate */
66943421Ssklower 				return;
67039950Ssklower 			netmask = (struct iso_addr *)(buf + 1);
67139950Ssklower 			break;
67239950Ssklower 
67339950Ssklower 		default:
67439950Ssklower 			printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]);
67537469Ssklower 		}
67639950Ssklower 		ESIS_NEXT_OPTION(buf);
67736379Ssklower 	}
67836379Ssklower 
67936379Ssklower 	IFDEBUG(D_ESISINPUT)
68037469Ssklower 		printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da));
68137469Ssklower 		if (net)
68237469Ssklower 			printf("\t: net %s\n", clnp_iso_addrp(net));
68336379Ssklower 	ENDDEBUG
68436379Ssklower 	/*
68536379Ssklower 	 *	If netl is zero, then redirect is to an ES. We need to add an entry
68636379Ssklower 	 *	to the snpa cache for (destination, better snpa).
68736379Ssklower 	 *	If netl is not zero, then the redirect is to an IS. In this
68836379Ssklower 	 *	case, add an snpa cache entry for (net, better snpa).
68936379Ssklower 	 *
69036379Ssklower 	 *	If the redirect is to an IS, add a route entry towards that
69136379Ssklower 	 *	IS.
69236379Ssklower 	 */
69339950Ssklower 	if (net == 0 || net->isoa_len == 0 || snpamask) {
69436379Ssklower 		/* redirect to an ES */
69539950Ssklower 		snpac_add(shp->snh_ifp, da,
69643332Ssklower 				bsnpa->isoa_genaddr, SNPA_ES, ht, 0);
69736379Ssklower 	} else {
69839950Ssklower 		snpac_add(shp->snh_ifp, net,
69943332Ssklower 				bsnpa->isoa_genaddr, SNPA_IS, ht, 0);
70039950Ssklower 		snpac_addrt(shp->snh_ifp, da, net, netmask);
70136379Ssklower 	}
70243421Ssklower bad: ;    /* Needed by ESIS_NEXT_OPTION */
70336379Ssklower }
70436379Ssklower 
70536379Ssklower /*
70636379Ssklower  * FUNCTION:		esis_config
70736379Ssklower  *
70836379Ssklower  * PURPOSE:			Report configuration
70936379Ssklower  *
71036379Ssklower  * RETURNS:
71136379Ssklower  *
71236379Ssklower  * SIDE EFFECTS:
71336379Ssklower  *
71436379Ssklower  * NOTES:			Called every esis_config_time seconds
71536379Ssklower  */
71636379Ssklower esis_config()
71736379Ssklower {
71836379Ssklower 	register struct ifnet	*ifp;
71936379Ssklower 
72036379Ssklower 	timeout(esis_config, (caddr_t)0, hz * esis_config_time);
72136379Ssklower 
72236379Ssklower 	/*
72336379Ssklower 	 *	Report configuration for each interface that
72436379Ssklower 	 *	- is UP
725*48963Ssklower 	 *	- has BROADCAST capability
72636379Ssklower 	 *	- has an ISO address
72736379Ssklower 	 */
728*48963Ssklower 	/* Todo: a better way would be to construct the esh or ish
729*48963Ssklower 	 * once and copy it out for all devices, possibly calling
730*48963Ssklower 	 * a method in the iso_ifaddr structure to encapsulate and
731*48963Ssklower 	 * transmit it.  This could work to advantage for non-broadcast media
732*48963Ssklower 	 */
73336379Ssklower 
73436379Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
73536379Ssklower 		if ((ifp->if_flags & IFF_UP) &&
736*48963Ssklower 		    (ifp->if_flags & IFF_BROADCAST)) {
73736379Ssklower 			/* search for an ISO address family */
73836379Ssklower 			struct ifaddr	*ia;
73936379Ssklower 
74036379Ssklower 			for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {
74137469Ssklower 				if (ia->ifa_addr->sa_family == AF_ISO) {
74236379Ssklower 					esis_shoutput(ifp,
74336379Ssklower 						iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
74436379Ssklower 						esis_holding_time,
74543332Ssklower 						(caddr_t)(iso_systype & SNPA_ES ? all_is_snpa :
74643332Ssklower 						all_es_snpa), 6, (struct iso_addr *)0);
74736379Ssklower 					break;
74836379Ssklower 				}
74936379Ssklower 			}
75036379Ssklower 		}
75136379Ssklower 	}
75236379Ssklower }
75336379Ssklower 
75436379Ssklower /*
75536379Ssklower  * FUNCTION:		esis_shoutput
75636379Ssklower  *
75736379Ssklower  * PURPOSE:			Transmit an esh or ish pdu
75836379Ssklower  *
75936379Ssklower  * RETURNS:			nothing
76036379Ssklower  *
76136379Ssklower  * SIDE EFFECTS:
76236379Ssklower  *
76336379Ssklower  * NOTES:
76436379Ssklower  */
76543332Ssklower esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa)
76636379Ssklower struct ifnet	*ifp;
76736379Ssklower int				type;
76836379Ssklower short			ht;
76936379Ssklower caddr_t 		sn_addr;
77036379Ssklower int				sn_len;
77143332Ssklower struct	iso_addr *isoa;
77236379Ssklower {
77336379Ssklower 	struct mbuf			*m, *m0;
77436379Ssklower 	caddr_t				cp, naddrp;
77536379Ssklower 	int					naddr = 0;
77636379Ssklower 	struct esis_fixed	*pdu;
77743332Ssklower 	struct iso_ifaddr	*ia;
77837469Ssklower 	int					len;
77936379Ssklower 	struct sockaddr_iso	siso;
78036379Ssklower 
78136379Ssklower 	if (type == ESIS_ESH)
78236379Ssklower 		esis_stat.es_eshsent++;
78336379Ssklower 	else if (type == ESIS_ISH)
78436379Ssklower 		esis_stat.es_ishsent++;
78536379Ssklower 	else {
78636379Ssklower 		printf("esis_shoutput: bad pdu type\n");
78736379Ssklower 		return;
78836379Ssklower 	}
78936379Ssklower 
79036379Ssklower 	IFDEBUG(D_ESISOUTPUT)
79136379Ssklower 		int	i;
79236379Ssklower 		printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ",
79336379Ssklower 			ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish",
79436379Ssklower 			ht, sn_len);
79536379Ssklower 		for (i=0; i<sn_len; i++)
79636379Ssklower 			printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' ');
79736379Ssklower 		printf("\n");
79836379Ssklower 	ENDDEBUG
79936379Ssklower 
80037469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
80136379Ssklower 		esis_stat.es_nomem++;
80236379Ssklower 		return;
80336379Ssklower 	}
80437469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
80536379Ssklower 
80636379Ssklower 	pdu = mtod(m, struct esis_fixed *);
80737469Ssklower 	naddrp = cp = (caddr_t)(pdu + 1);
80836379Ssklower 	len = sizeof(struct esis_fixed);
80936379Ssklower 
81036379Ssklower 	/*
81136379Ssklower 	 *	Build fixed part of header
81236379Ssklower 	 */
81336379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
81436379Ssklower 	pdu->esis_vers = ESIS_VERSION;
81536379Ssklower 	pdu->esis_type = type;
81636379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
81736379Ssklower 
81836379Ssklower 	if (type == ESIS_ESH) {
81936379Ssklower 		cp++;
82036379Ssklower 		len++;
82136379Ssklower 	}
82236379Ssklower 
82337469Ssklower 	m->m_len = len;
82443332Ssklower 	if (isoa) {
82543332Ssklower 		/*
82643332Ssklower 		 * Here we are responding to a clnp packet sent to an NSAP
82743332Ssklower 		 * that is ours which was sent to the MAC addr all_es's.
82843332Ssklower 		 * It is possible that we did not specifically advertise this
82943332Ssklower 		 * NSAP, even though it is ours, so we will respond
83043332Ssklower 		 * directly to the sender that we are here.  If we do have
83143332Ssklower 		 * multiple NSEL's we'll tack them on so he can compress them out.
83243332Ssklower 		 */
83343332Ssklower 		(void) esis_insert_addr(&cp, &len, isoa, m, 0);
83443332Ssklower 		naddr = 1;
83543332Ssklower 	}
83643332Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
83743332Ssklower 		int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0);
83843332Ssklower 		int n = ia->ia_addr.siso_nlen;
83943332Ssklower 		register struct iso_ifaddr *ia2;
84043332Ssklower 
84143332Ssklower 		if (type == ESIS_ISH && naddr > 0)
84243332Ssklower 			break;
84343332Ssklower 		for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next)
84443332Ssklower 			if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0)
84543332Ssklower 					break;
84643332Ssklower 		if (ia2 != ia)
84743332Ssklower 			continue;	/* Means we have previously copied this nsap */
84843332Ssklower 		if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) {
84943332Ssklower 			isoa = 0;
85043332Ssklower 			continue;	/* Ditto */
85136379Ssklower 		}
85243332Ssklower 		IFDEBUG(D_ESISOUTPUT)
85343332Ssklower 			printf("esis_shoutput: adding NSAP %s\n",
85443332Ssklower 				clnp_iso_addrp(&ia->ia_addr.siso_addr));
85543332Ssklower 		ENDDEBUG
85643332Ssklower 		if (!esis_insert_addr(&cp, &len,
85743332Ssklower 							  &ia->ia_addr.siso_addr, m, nsellen)) {
85843332Ssklower 			EXTEND_PACKET(m, m0, cp);
85943332Ssklower 			(void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m,
86043332Ssklower 									nsellen);
86143332Ssklower 		}
86243332Ssklower 		naddr++;
86336379Ssklower 	}
86436379Ssklower 
86536379Ssklower 	if (type == ESIS_ESH)
86636379Ssklower 		*naddrp = naddr;
86744254Ssklower 	else {
86844254Ssklower 		/* add suggested es config timer option to ISH */
86944254Ssklower 		if (M_TRAILINGSPACE(m) < 4) {
87044254Ssklower 			printf("esis_shoutput: extending packet\n");
87144254Ssklower 			EXTEND_PACKET(m, m0, cp);
87244254Ssklower 		}
87344254Ssklower 		*cp++ = ESISOVAL_ESCT;
87444254Ssklower 		*cp++ = 2;
87544254Ssklower 		HTOC(*cp, *(cp+1), esis_esconfig_time);
87644254Ssklower 		len += 4;
87744254Ssklower 		m->m_len += 4;
87844254Ssklower 		IFDEBUG(D_ESISOUTPUT)
87944254Ssklower 			printf("m0 0x%x, m 0x%x, data 0x%x, len %d, cp 0x%x\n",
88044254Ssklower 			m0, m, m->m_data, m->m_len, cp);
88144254Ssklower 		ENDDEBUG
88244254Ssklower 	}
88336379Ssklower 
88437469Ssklower 	m0->m_pkthdr.len = len;
88537469Ssklower 	pdu->esis_hdr_len = len;
88636379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
88736379Ssklower 
88837469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
88936379Ssklower 	siso.siso_family = AF_ISO;
89037469Ssklower 	siso.siso_data[0] = AFI_SNA;
89137469Ssklower 	siso.siso_nlen = sn_len + 1;
89237469Ssklower 	bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len);
89340775Ssklower 	(ifp->if_output)(ifp, m0, &siso, 0);
89436379Ssklower }
89536379Ssklower 
89636379Ssklower /*
89743421Ssklower  * FUNCTION:		isis_input
89843421Ssklower  *
89943421Ssklower  * PURPOSE:			Process an incoming isis packet
90043421Ssklower  *
90143421Ssklower  * RETURNS:			nothing
90243421Ssklower  *
90343421Ssklower  * SIDE EFFECTS:
90443421Ssklower  *
90543421Ssklower  * NOTES:
90643421Ssklower  */
90743421Ssklower isis_input(m0, shp)
90843421Ssklower struct mbuf		*m0;		/* ptr to first mbuf of pkt */
90943421Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
91043421Ssklower {
91143421Ssklower 	register int type;
91243961Ssklower 	register struct rawcb *rp, *first_rp = 0;
91343421Ssklower 	struct ifnet *ifp = shp->snh_ifp;
91443421Ssklower 	char workbuf[16];
91543421Ssklower 	struct mbuf *mm;
91643421Ssklower 
91743421Ssklower 	IFDEBUG(D_ISISINPUT)
91843421Ssklower 		int i;
91943421Ssklower 
92043421Ssklower 		printf("isis_input: pkt on ifp x%x (%s%d): from:", ifp,
92143421Ssklower 			ifp->if_name, ifp->if_unit);
92243421Ssklower 		for (i=0; i<6; i++)
92343421Ssklower 			printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' ');
92443421Ssklower 		printf(" to:");
92543421Ssklower 		for (i=0; i<6; i++)
92643421Ssklower 			printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' ');
92743421Ssklower 		printf("\n");
92843421Ssklower 	ENDDEBUG
92943421Ssklower 	esis_dl.sdl_alen = ifp->if_addrlen;
93043421Ssklower 	esis_dl.sdl_index = ifp->if_index;
93143421Ssklower 	bcopy(shp->snh_shost, (caddr_t)esis_dl.sdl_data, esis_dl.sdl_alen);
93243421Ssklower 	for (rp = esis_pcb.rcb_next; rp != &esis_pcb; rp = rp->rcb_next) {
93343961Ssklower 		if (first_rp == 0) {
93443961Ssklower 			first_rp = rp;
93543421Ssklower 			continue;
93643421Ssklower 		}
93743421Ssklower 		if (mm = m_copy(m0, 0, M_COPYALL)) { /*can't block at interrupt level */
93843421Ssklower 			if (sbappendaddr(&rp->rcb_socket->so_rcv,
93943421Ssklower 							  &esis_dl, mm, (struct mbuf *)0) != 0)
94043421Ssklower 				sorwakeup(rp->rcb_socket);
94143421Ssklower 			else {
94243421Ssklower 				IFDEBUG(D_ISISINPUT)
94343421Ssklower 					printf("Error in sbappenaddr, mm = 0x%x\n", mm);
94443421Ssklower 				ENDDEBUG
94543421Ssklower 				m_freem(mm);
94643421Ssklower 			}
94743421Ssklower 		}
94843421Ssklower 	}
94943961Ssklower 	if (first_rp && sbappendaddr(&first_rp->rcb_socket->so_rcv,
95044946Ssklower 							  &esis_dl, m0, (struct mbuf *)0) != 0) {
95143961Ssklower 		sorwakeup(first_rp->rcb_socket);
95243961Ssklower 		return;
95343421Ssklower 	}
95443961Ssklower 	m_freem(m0);
95543421Ssklower }
95643421Ssklower 
95743421Ssklower isis_output(sdl, m)
95843421Ssklower register struct sockaddr_dl	*sdl;
95943421Ssklower struct mbuf *m;
96043421Ssklower {
96143421Ssklower 	register struct ifnet *ifp;
96243421Ssklower 	struct ifaddr *ifa, *ifa_ifwithnet();
96343421Ssklower 	struct sockaddr_iso siso;
96443421Ssklower 	int error = 0;
96543421Ssklower 	unsigned sn_len;
96643421Ssklower 
96743421Ssklower 	ifa = ifa_ifwithnet(sdl);	/* extract ifp from sockaddr_dl */
96843421Ssklower 	if (ifa == 0) {
96943421Ssklower 		IFDEBUG(D_ISISOUTPUT)
97043421Ssklower 			printf("isis_output: interface not found\n");
97143421Ssklower 		ENDDEBUG
97243421Ssklower 		error = EINVAL;
97343421Ssklower 		goto release;
97443421Ssklower 	}
97543421Ssklower 	ifp = ifa->ifa_ifp;
97645896Ssklower 	sn_len = sdl->sdl_alen;
97743421Ssklower 	IFDEBUG(D_ISISOUTPUT)
97843421Ssklower 		u_char *cp = (u_char *)LLADDR(sdl), *cplim = cp + sn_len;
97943421Ssklower 		printf("isis_output: ifp 0x%x (%s%d), to: ",
98043421Ssklower 			ifp, ifp->if_name, ifp->if_unit);
98143421Ssklower 		while (cp < cplim) {
98243421Ssklower 			printf("%x", *cp++);
98343421Ssklower 			printf("%c", (cp < cplim) ? ':' : ' ');
98443421Ssklower 		}
98543421Ssklower 		printf("\n");
98643421Ssklower 	ENDDEBUG
98743421Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
98843421Ssklower 	siso.siso_family = AF_ISO; /* This convention may be useful for X.25 */
98943421Ssklower 	siso.siso_data[0] = AFI_SNA;
99043421Ssklower 	siso.siso_nlen = sn_len + 1;
99143421Ssklower 	bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len);
99243421Ssklower 	error = (ifp->if_output)(ifp, m, (struct sockaddr *)&siso, 0);
99343421Ssklower 	if (error) {
99443421Ssklower 		IFDEBUG(D_ISISOUTPUT)
99543421Ssklower 			printf("isis_output: error from ether_output is %d\n", error);
99643421Ssklower 		ENDDEBUG
99743421Ssklower 	}
99843421Ssklower 	return (error);
99943421Ssklower 
100043421Ssklower release:
100143421Ssklower 	if (m != NULL)
100243421Ssklower 		m_freem(m);
100343421Ssklower 	return(error);
100443421Ssklower }
100543421Ssklower 
100643421Ssklower 
100743421Ssklower /*
100836379Ssklower  * FUNCTION:		esis_ctlinput
100936379Ssklower  *
101036379Ssklower  * PURPOSE:			Handle the PRC_IFDOWN transition
101136379Ssklower  *
101236379Ssklower  * RETURNS:			nothing
101336379Ssklower  *
101436379Ssklower  * SIDE EFFECTS:
101536379Ssklower  *
101636379Ssklower  * NOTES:			Calls snpac_flush for interface specified.
101736379Ssklower  *					The loop through iso_ifaddr is stupid because
101836379Ssklower  *					back in if_down, we knew the ifp...
101936379Ssklower  */
102036379Ssklower esis_ctlinput(req, siso)
102136379Ssklower int						req;		/* request: we handle only PRC_IFDOWN */
102236379Ssklower struct sockaddr_iso		*siso;		/* address of ifp */
102336379Ssklower {
102436379Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
102536379Ssklower 
102637469Ssklower 	if (req == PRC_IFDOWN)
102737469Ssklower 		for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
102837469Ssklower 			if (iso_addrmatch(IA_SIS(ia), siso))
102937469Ssklower 				snpac_flushifp(ia->ia_ifp);
103037469Ssklower 		}
103136379Ssklower }
103236379Ssklower 
103336379Ssklower #endif	ISO
1034