xref: /csrg-svn/sys/netiso/esis.c (revision 44254)
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*44254Ssklower /*	@(#)esis.c	7.14 (Berkeley) 06/25/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"
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);
16243421Ssklower 			error = soreserve(so, esis_sendspace, esis_recvspace);
16343421Ssklower 		} else
16443421Ssklower 			error = ENOBUFS;
16543421Ssklower 		break;
16643421Ssklower 
16743421Ssklower 	case PRU_SEND:
16843421Ssklower 		if (nam == NULL) {
16943421Ssklower 			error = EINVAL;
17043421Ssklower 			break;
17143421Ssklower 		}
17243421Ssklower 		/* error checking here */
17343421Ssklower 		error = isis_output(mtod(nam,struct sockaddr_dl *), m);
17443421Ssklower 		m = NULL;
17543421Ssklower 		break;
17643421Ssklower 
17743421Ssklower 	case PRU_DETACH:
17843421Ssklower 		raw_detach(rp);
17943421Ssklower 		break;
18043421Ssklower 
18143421Ssklower 	case PRU_SHUTDOWN:
18243421Ssklower 		socantsendmore(so);
18343421Ssklower 		break;
18443421Ssklower 
18543421Ssklower 	case PRU_ABORT:
18643421Ssklower 		soisdisconnected(so);
18743421Ssklower 		raw_detach(rp);
18843421Ssklower 		break;
18943421Ssklower 
19043421Ssklower 	case PRU_SENSE:
19143421Ssklower 		return (0);
19243421Ssklower 
19343421Ssklower 	default:
19443421Ssklower 		return (EOPNOTSUPP);
19543421Ssklower 	}
19643421Ssklower release:
19736379Ssklower 	if (m != NULL)
19836379Ssklower 		m_freem(m);
19936379Ssklower 
20043421Ssklower 	return (error);
20136379Ssklower }
20236379Ssklower 
20336379Ssklower /*
20436379Ssklower  * FUNCTION:		esis_input
20536379Ssklower  *
20636379Ssklower  * PURPOSE:			Process an incoming esis packet
20736379Ssklower  *
20836379Ssklower  * RETURNS:			nothing
20936379Ssklower  *
21036379Ssklower  * SIDE EFFECTS:
21136379Ssklower  *
21236379Ssklower  * NOTES:
21336379Ssklower  */
21436379Ssklower esis_input(m0, shp)
21536379Ssklower struct mbuf		*m0;		/* ptr to first mbuf of pkt */
21636379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
21736379Ssklower {
21843421Ssklower 	register struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
21937469Ssklower 	register int type;
22036379Ssklower 
22136379Ssklower 	/*
22236379Ssklower 	 *	check checksum if necessary
22336379Ssklower 	 */
22437469Ssklower 	if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) {
22536379Ssklower 		esis_stat.es_badcsum++;
22636379Ssklower 		goto bad;
22736379Ssklower 	}
22836379Ssklower 
22936379Ssklower 	/* check version */
23036379Ssklower 	if (pdu->esis_vers != ESIS_VERSION) {
23136379Ssklower 		esis_stat.es_badvers++;
23236379Ssklower 		goto bad;
23336379Ssklower 	}
23437469Ssklower 	type = pdu->esis_type & 0x1f;
23537469Ssklower 	switch (type) {
23636379Ssklower 		case ESIS_ESH:
23736379Ssklower 			esis_eshinput(m0, shp);
23843421Ssklower 			break;
23936379Ssklower 
24036379Ssklower 		case ESIS_ISH:
24136379Ssklower 			esis_ishinput(m0, shp);
24243421Ssklower 			break;
24336379Ssklower 
24436379Ssklower 		case ESIS_RD:
24536379Ssklower 			esis_rdinput(m0, shp);
24643421Ssklower 			break;
24736379Ssklower 
24843421Ssklower 		default:
24936379Ssklower 			esis_stat.es_badtype++;
25036379Ssklower 	}
25136379Ssklower 
25236379Ssklower bad:
25343421Ssklower 	if (esis_pcb.rcb_next != &esis_pcb)
25443421Ssklower 		isis_input(m0, shp);
25543421Ssklower 	else
25643421Ssklower 		m_freem(m0);
25736379Ssklower }
25836379Ssklower 
25936379Ssklower /*
26036379Ssklower  * FUNCTION:		esis_rdoutput
26136379Ssklower  *
26236379Ssklower  * PURPOSE:			Transmit a redirect pdu
26336379Ssklower  *
26436379Ssklower  * RETURNS:			nothing
26536379Ssklower  *
26636379Ssklower  * SIDE EFFECTS:
26736379Ssklower  *
26836379Ssklower  * NOTES:			Assumes there is enough space for fixed part of header,
26936379Ssklower  *					DA, BSNPA and NET in first mbuf.
27036379Ssklower  */
27143332Ssklower esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt)
27236379Ssklower struct snpa_hdr		*inbound_shp;	/* snpa hdr from incoming packet */
27336379Ssklower struct mbuf			*inbound_m;		/* incoming pkt itself */
27436379Ssklower struct clnp_optidx	*inbound_oidx;	/* clnp options assoc with incoming pkt */
27536379Ssklower struct iso_addr		*rd_dstnsap;	/* ultimate destination of pkt */
27643332Ssklower struct rtentry		*rt;			/* snpa cache info regarding next hop of
27736379Ssklower 										pkt */
27836379Ssklower {
27936379Ssklower 	struct mbuf			*m, *m0;
28036379Ssklower 	caddr_t				cp;
28136379Ssklower 	struct esis_fixed	*pdu;
28236379Ssklower 	int					len, total_len = 0;
28336379Ssklower 	struct sockaddr_iso	siso;
28436379Ssklower 	struct ifnet 		*ifp = inbound_shp->snh_ifp;
28543332Ssklower 	struct sockaddr_dl *sdl;
28643332Ssklower 	struct iso_addr *rd_gwnsap;
28736379Ssklower 
28843332Ssklower 	if (rt->rt_flags & RTF_GATEWAY) {
28943332Ssklower 		rd_gwnsap = &((struct sockaddr_iso *)rt->rt_gateway)->siso_addr;
29043332Ssklower 		rt = rtalloc1(rt->rt_gateway, 0);
29143332Ssklower 	} else
29243332Ssklower 		rd_gwnsap = &((struct sockaddr_iso *)rt_key(rt))->siso_addr;
29343332Ssklower 	if (rt == 0 || (sdl = (struct sockaddr_dl *)rt->rt_gateway) == 0 ||
29443332Ssklower 		sdl->sdl_family != AF_LINK) {
29543332Ssklower 		/* maybe we should have a function that you
29643332Ssklower 		   could put in the iso_ifaddr structure
29743332Ssklower 		   which could translate iso_addrs into snpa's
29843332Ssklower 		   where there is a known mapping for that address type */
29943332Ssklower 		esis_stat.es_badtype++;
30043332Ssklower 		return;
30143332Ssklower 	}
30236379Ssklower 	esis_stat.es_rdsent++;
30336379Ssklower 	IFDEBUG(D_ESISOUTPUT)
30436379Ssklower 		printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n",
30536379Ssklower 			ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m,
30636379Ssklower 			inbound_oidx);
30736379Ssklower 		printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap));
30843332Ssklower 		printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap));
30936379Ssklower 	ENDDEBUG
31036379Ssklower 
31137469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
31236379Ssklower 		esis_stat.es_nomem++;
31336379Ssklower 		return;
31436379Ssklower 	}
31537469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
31636379Ssklower 
31736379Ssklower 	pdu = mtod(m, struct esis_fixed *);
31837469Ssklower 	cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */
31936379Ssklower 	len = sizeof(struct esis_fixed);
32036379Ssklower 
32136379Ssklower 	/*
32236379Ssklower 	 *	Build fixed part of header
32336379Ssklower 	 */
32436379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
32536379Ssklower 	pdu->esis_vers = ESIS_VERSION;
32636379Ssklower 	pdu->esis_type = ESIS_RD;
32736379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time);
32836379Ssklower 
32936379Ssklower 	/* Insert destination address */
33043072Ssklower 	(void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0);
33136379Ssklower 
33236379Ssklower 	/* Insert the snpa of better next hop */
33343332Ssklower 	*cp++ = sdl->sdl_alen;
33443332Ssklower 	bcopy(LLADDR(sdl), cp, sdl->sdl_alen);
33543332Ssklower 	cp += sdl->sdl_alen;
33643332Ssklower 	len += (sdl->sdl_alen + 1);
33736379Ssklower 
33836379Ssklower 	/*
33936379Ssklower 	 *	If the next hop is not the destination, then it ought to be
34036379Ssklower 	 *	an IS and it should be inserted next. Else, set the
34136379Ssklower 	 *	NETL to 0
34236379Ssklower 	 */
34336379Ssklower 	/* PHASE2 use mask from ifp of outgoing interface */
34443332Ssklower 	if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) {
34543332Ssklower 		/* this should not happen:
34636379Ssklower 		if ((nhop_sc->sc_flags & SNPA_IS) == 0) {
34736379Ssklower 			printf("esis_rdoutput: next hop is not dst and not an IS\n");
34836379Ssklower 			m_freem(m0);
34936379Ssklower 			return;
35043332Ssklower 		} */
35143332Ssklower 		(void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0);
35236379Ssklower 	} else {
35336379Ssklower 		*cp++ = 0;	/* NETL */
35436379Ssklower 		len++;
35536379Ssklower 	}
35637469Ssklower 	m->m_len = len;
35736379Ssklower 
35836379Ssklower 	/*
35936379Ssklower 	 *	PHASE2
36036379Ssklower 	 *	If redirect is to an IS, add an address mask. The mask to be
36136379Ssklower 	 *	used should be the mask present in the routing entry used to
36236379Ssklower 	 *	forward the original data packet.
36336379Ssklower 	 */
36436379Ssklower 
36536379Ssklower 	/*
36636379Ssklower 	 *	Copy Qos, priority, or security options present in original npdu
36736379Ssklower 	 */
36836379Ssklower 	if (inbound_oidx) {
36943332Ssklower 		/* THIS CODE IS CURRENTLY (mostly) UNTESTED */
37036379Ssklower 		int optlen = 0;
37136379Ssklower 		if (inbound_oidx->cni_qos_formatp)
37236379Ssklower 			optlen += (inbound_oidx->cni_qos_len + 2);
37336379Ssklower 		if (inbound_oidx->cni_priorp)	/* priority option is 1 byte long */
37436379Ssklower 			optlen += 3;
37536379Ssklower 		if (inbound_oidx->cni_securep)
37636379Ssklower 			optlen += (inbound_oidx->cni_secure_len + 2);
37737469Ssklower 		if (M_TRAILINGSPACE(m) < optlen) {
37837469Ssklower 			EXTEND_PACKET(m, m0, cp);
37937469Ssklower 			m->m_len = 0;
38036379Ssklower 			/* assumes MLEN > optlen */
38136379Ssklower 		}
38236379Ssklower 		/* assume MLEN-len > optlen */
38336379Ssklower 		/*
38436379Ssklower 		 *	When copying options, copy from ptr - 2 in order to grab
38536379Ssklower 		 *	the option code and length
38636379Ssklower 		 */
38736379Ssklower 		if (inbound_oidx->cni_qos_formatp) {
38843332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_qos_formatp - 2,
38943332Ssklower 				cp, (unsigned)(inbound_oidx->cni_qos_len + 2));
39043332Ssklower 			cp += inbound_oidx->cni_qos_len + 2;
39136379Ssklower 		}
39236379Ssklower 		if (inbound_oidx->cni_priorp) {
39343332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_priorp - 2,
39443332Ssklower 					cp, 3);
39543332Ssklower 			cp += 3;
39636379Ssklower 		}
39736379Ssklower 		if (inbound_oidx->cni_securep) {
39843332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_securep - 2, cp,
39937469Ssklower 				(unsigned)(inbound_oidx->cni_secure_len + 2));
40043332Ssklower 			cp += inbound_oidx->cni_secure_len + 2;
40136379Ssklower 		}
40237469Ssklower 		m->m_len += optlen;
40343332Ssklower 		len += optlen;
40436379Ssklower 	}
40536379Ssklower 
40637469Ssklower 	pdu->esis_hdr_len = m0->m_pkthdr.len = len;
40736379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
40836379Ssklower 
40937469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
41036379Ssklower 	siso.siso_family = AF_ISO;
41137469Ssklower 	siso.siso_data[0] = AFI_SNA;
41237469Ssklower 	siso.siso_nlen = 6 + 1;	/* should be taken from snpa_hdr */
41336379Ssklower 										/* +1 is for AFI */
41437469Ssklower 	bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6);
41540775Ssklower 	(ifp->if_output)(ifp, m0, &siso, 0);
41636379Ssklower }
41736379Ssklower 
41836379Ssklower /*
41936379Ssklower  * FUNCTION:		esis_insert_addr
42036379Ssklower  *
42136379Ssklower  * PURPOSE:			Insert an iso_addr into a buffer
42236379Ssklower  *
42336379Ssklower  * RETURNS:			true if buffer was big enough, else false
42436379Ssklower  *
42536379Ssklower  * SIDE EFFECTS:	Increment buf & len according to size of iso_addr
42636379Ssklower  *
42736379Ssklower  * NOTES:			Plus 1 here is for length byte
42836379Ssklower  */
42943072Ssklower esis_insert_addr(buf, len, isoa, m, nsellen)
43043332Ssklower register caddr_t			*buf;		/* ptr to buffer to put address into */
43143332Ssklower int							*len;		/* ptr to length of buffer so far */
43243332Ssklower register struct iso_addr	*isoa;		/* ptr to address */
43343332Ssklower register struct mbuf		*m;			/* determine if there remains space */
43443332Ssklower int							nsellen;
43536379Ssklower {
43643332Ssklower 	register int newlen, result = 0;
43736379Ssklower 
43843332Ssklower 	isoa->isoa_len -= nsellen;
43943332Ssklower 	newlen = isoa->isoa_len + 1;
44043332Ssklower 	if (newlen <=  M_TRAILINGSPACE(m)) {
44143332Ssklower 		bcopy((caddr_t)isoa, *buf, newlen);
44243332Ssklower 		*len += newlen;
44343332Ssklower 		*buf += newlen;
44443332Ssklower 		m->m_len += newlen;
44543332Ssklower 		result = 1;
44643332Ssklower 	}
44743332Ssklower 	isoa->isoa_len += nsellen;
44843332Ssklower 	return (result);
44936379Ssklower }
45036379Ssklower 
45139950Ssklower #define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \
45239950Ssklower 	    if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
45339950Ssklower #define ESIS_NEXT_OPTION(b)	{ b += (2 + b[1]); \
45439950Ssklower 	    if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
45543430Ssklower int ESHonly = 0;
45636379Ssklower /*
45736379Ssklower 
45836379Ssklower /*
45936379Ssklower  * FUNCTION:		esis_eshinput
46036379Ssklower  *
46136379Ssklower  * PURPOSE:			Process an incoming ESH pdu
46236379Ssklower  *
46336379Ssklower  * RETURNS:			nothing
46436379Ssklower  *
46536379Ssklower  * SIDE EFFECTS:
46636379Ssklower  *
46736379Ssklower  * NOTES:
46836379Ssklower  */
46936379Ssklower esis_eshinput(m, shp)
47036379Ssklower struct mbuf		*m;	/* esh pdu */
47136379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
47236379Ssklower {
47343072Ssklower 	struct	esis_fixed	*pdu = mtod(m, struct esis_fixed *);
47436379Ssklower 	u_short				ht;		/* holding time */
47543072Ssklower 	struct	iso_addr	*nsap;
47639950Ssklower 	int					naddr;
47737469Ssklower 	u_char				*buf = (u_char *)(pdu + 1);
47839950Ssklower 	u_char				*buflim = pdu->esis_hdr_len + (u_char *)pdu;
47943332Ssklower 	int					new_entry = 0;
48036379Ssklower 
48136379Ssklower 	esis_stat.es_eshrcvd++;
48236379Ssklower 
48336379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
48436379Ssklower 
48539950Ssklower 	naddr = *buf++;
48639950Ssklower 	if (buf >= buflim)
48736379Ssklower 		goto bad;
48843332Ssklower 	if (naddr == 1) {
48939950Ssklower 		ESIS_EXTRACT_ADDR(nsap, buf);
49043332Ssklower 		new_entry = snpac_add(shp->snh_ifp,
49143332Ssklower 								 nsap, shp->snh_shost, SNPA_ES, ht, 0);
49243332Ssklower 	} else {
49343332Ssklower 		int nsellength = 0, nlen = 0;
49443332Ssklower 		{
49543332Ssklower 		/* See if we want to compress out multiple nsaps differing
49643332Ssklower 		   only by nsel */
49743332Ssklower 			register struct ifaddr *ifa = shp->snh_ifp->if_addrlist;
49843332Ssklower 			for (; ifa; ifa = ifa->ifa_next)
49943332Ssklower 				if (ifa->ifa_addr->sa_family == AF_ISO) {
50043332Ssklower 					nsellength = ((struct iso_ifaddr *)ifa)->ia_addr.siso_tlen;
50143332Ssklower 					break;
50243332Ssklower 			}
50343332Ssklower 		}
50439950Ssklower 		IFDEBUG(D_ESISINPUT)
50543332Ssklower 			printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n",
50643332Ssklower 					ht, naddr, nsellength);
50739950Ssklower 		ENDDEBUG
50843332Ssklower 		while (naddr-- > 0) {
50943332Ssklower 			struct iso_addr *nsap2; u_char *buf2;
51043332Ssklower 			ESIS_EXTRACT_ADDR(nsap, buf);
51143332Ssklower 			/* see if there is at least one more nsap in ESH differing
51243332Ssklower 			   only by nsel */
51343332Ssklower 			if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) {
51443332Ssklower 				ESIS_EXTRACT_ADDR(nsap2, buf2);
51543332Ssklower 				IFDEBUG(D_ESISINPUT)
51643332Ssklower 					printf("esis_eshinput: comparing %s ",
51743332Ssklower 						clnp_iso_addrp(nsap));
51843332Ssklower 					printf("and %s\n", clnp_iso_addrp(nsap2));
51943332Ssklower 				ENDDEBUG
52043332Ssklower 				if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr,
52143332Ssklower 						 nsap->isoa_len - nsellength) == 0) {
52243332Ssklower 					nlen = nsellength;
52343332Ssklower 					break;
52443332Ssklower 				}
52543332Ssklower 			}
52643332Ssklower 			new_entry |= snpac_add(shp->snh_ifp,
52743332Ssklower 									nsap, shp->snh_shost, SNPA_ES, ht, nlen);
52843332Ssklower 			nlen = 0;
52943332Ssklower 		}
53039950Ssklower 	}
53143332Ssklower 	IFDEBUG(D_ESISINPUT)
53243332Ssklower 		printf("esis_eshinput: nsap %s is %s\n",
53343332Ssklower 			clnp_iso_addrp(nsap), new_entry ? "new" : "old");
53443332Ssklower 	ENDDEBUG
53543332Ssklower 	if (new_entry && (iso_systype & SNPA_IS))
53643332Ssklower 		esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time,
53743332Ssklower 						shp->snh_shost, 6, (struct iso_addr *)0);
53837469Ssklower bad:
53939950Ssklower 	return;
54036379Ssklower }
54136379Ssklower 
54236379Ssklower /*
54336379Ssklower  * FUNCTION:		esis_ishinput
54436379Ssklower  *
54536379Ssklower  * PURPOSE:			process an incoming ISH pdu
54636379Ssklower  *
54736379Ssklower  * RETURNS:
54836379Ssklower  *
54936379Ssklower  * SIDE EFFECTS:
55036379Ssklower  *
55136379Ssklower  * NOTES:
55236379Ssklower  */
55336379Ssklower esis_ishinput(m, shp)
55436379Ssklower struct mbuf		*m;	/* esh pdu */
55536379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
55636379Ssklower {
55736379Ssklower 	struct esis_fixed	*pdu = mtod(m, struct esis_fixed *);
55843430Ssklower 	u_short				ht, newct;			/* holding time */
55939950Ssklower 	struct iso_addr		*nsap; 				/* Network Entity Title */
56039950Ssklower 	register u_char		*buf = (u_char *) (pdu + 1);
56139950Ssklower 	register u_char		*buflim = pdu->esis_hdr_len + (u_char *)pdu;
56239950Ssklower 	int					new_entry;
56336379Ssklower 
56436379Ssklower 	esis_stat.es_ishrcvd++;
56536379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
56636379Ssklower 
56736379Ssklower 	IFDEBUG(D_ESISINPUT)
56836379Ssklower 		printf("esis_ishinput: ish: ht %d\n", ht);
56936379Ssklower 	ENDDEBUG
57039950Ssklower 	if (ESHonly)
57137469Ssklower 		goto bad;
57236379Ssklower 
57339950Ssklower 	ESIS_EXTRACT_ADDR(nsap, buf);
57439950Ssklower 
57539950Ssklower 	while (buf < buflim) {
57639950Ssklower 		switch (*buf) {
57737469Ssklower 		case ESISOVAL_ESCT:
57839950Ssklower 			if (buf[1] != 2)
57937469Ssklower 				goto bad;
58043430Ssklower 			CTOH(buf[2], buf[3], newct);
58143430Ssklower 			if (esis_config_time != newct) {
58243430Ssklower 				untimeout(esis_config,0);
58343430Ssklower 				esis_config_time = newct;
58443430Ssklower 				esis_config();
58543430Ssklower 			}
58639950Ssklower 			break;
58739950Ssklower 
58839950Ssklower 		default:
58939950Ssklower 			printf("Unknown ISH option: %x\n", *buf);
59037469Ssklower 		}
59139950Ssklower 		ESIS_NEXT_OPTION(buf);
59237469Ssklower 	}
59343332Ssklower 	new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0);
59437469Ssklower 	IFDEBUG(D_ESISINPUT)
59537469Ssklower 		printf("esis_ishinput: nsap %s is %s\n",
59637469Ssklower 			clnp_iso_addrp(nsap), new_entry ? "new" : "old");
59737469Ssklower 	ENDDEBUG
59837469Ssklower 
59937469Ssklower 	if (new_entry)
60037469Ssklower 		esis_shoutput(shp->snh_ifp,
60137469Ssklower 			iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
60243332Ssklower 			esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0);
60339950Ssklower bad:
60439950Ssklower 	return;
60536379Ssklower }
60636379Ssklower 
60736379Ssklower /*
60836379Ssklower  * FUNCTION:		esis_rdinput
60936379Ssklower  *
61036379Ssklower  * PURPOSE:			Process an incoming RD pdu
61136379Ssklower  *
61236379Ssklower  * RETURNS:
61336379Ssklower  *
61436379Ssklower  * SIDE EFFECTS:
61536379Ssklower  *
61636379Ssklower  * NOTES:
61736379Ssklower  */
61836379Ssklower esis_rdinput(m0, shp)
61936379Ssklower struct mbuf		*m0;	/* esh pdu */
62036379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
62136379Ssklower {
62236379Ssklower 	struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
62336379Ssklower 	u_short				ht;		/* holding time */
62439950Ssklower 	struct iso_addr		*da, *net = 0, *netmask = 0, *snpamask = 0;
62539950Ssklower 	register struct iso_addr *bsnpa;
62639950Ssklower 	register u_char		*buf = (u_char *)(pdu + 1);
62739950Ssklower 	register u_char		*buflim = pdu->esis_hdr_len + (u_char *)pdu;
62836379Ssklower 
62936379Ssklower 	esis_stat.es_rdrcvd++;
63036379Ssklower 
63136379Ssklower 	/* intermediate systems ignore redirects */
63236379Ssklower 	if (iso_systype & SNPA_IS)
63343421Ssklower 		return;
63439950Ssklower 	if (ESHonly)
63543421Ssklower 		return;
63636379Ssklower 
63736379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
63839950Ssklower 	if (buf >= buflim)
63943421Ssklower 		return;
64036379Ssklower 
64136379Ssklower 	/* Extract DA */
64239950Ssklower 	ESIS_EXTRACT_ADDR(da, buf);
64337469Ssklower 
64436379Ssklower 	/* Extract better snpa */
64539950Ssklower 	ESIS_EXTRACT_ADDR(bsnpa, buf);
64639950Ssklower 
64737469Ssklower 	/* Extract NET if present */
64839950Ssklower 	if (buf < buflim) {
64943332Ssklower 		if (*buf == 0)
65043332Ssklower 			buf++; /* no NET present, skip NETL anyway */
65143332Ssklower 		else
65243332Ssklower 			ESIS_EXTRACT_ADDR(net, buf);
65336379Ssklower 	}
65436379Ssklower 
65537469Ssklower 	/* process options */
65639950Ssklower 	while (buf < buflim) {
65739950Ssklower 		switch (*buf) {
65837469Ssklower 		case ESISOVAL_SNPAMASK:
65937469Ssklower 			if (snpamask) /* duplicate */
66043421Ssklower 				return;
66139950Ssklower 			snpamask = (struct iso_addr *)(buf + 1);
66237469Ssklower 			break;
66337469Ssklower 
66437469Ssklower 		case ESISOVAL_NETMASK:
66537469Ssklower 			if (netmask) /* duplicate */
66643421Ssklower 				return;
66739950Ssklower 			netmask = (struct iso_addr *)(buf + 1);
66839950Ssklower 			break;
66939950Ssklower 
67039950Ssklower 		default:
67139950Ssklower 			printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]);
67237469Ssklower 		}
67339950Ssklower 		ESIS_NEXT_OPTION(buf);
67436379Ssklower 	}
67536379Ssklower 
67636379Ssklower 	IFDEBUG(D_ESISINPUT)
67737469Ssklower 		printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da));
67837469Ssklower 		if (net)
67937469Ssklower 			printf("\t: net %s\n", clnp_iso_addrp(net));
68036379Ssklower 	ENDDEBUG
68136379Ssklower 	/*
68236379Ssklower 	 *	If netl is zero, then redirect is to an ES. We need to add an entry
68336379Ssklower 	 *	to the snpa cache for (destination, better snpa).
68436379Ssklower 	 *	If netl is not zero, then the redirect is to an IS. In this
68536379Ssklower 	 *	case, add an snpa cache entry for (net, better snpa).
68636379Ssklower 	 *
68736379Ssklower 	 *	If the redirect is to an IS, add a route entry towards that
68836379Ssklower 	 *	IS.
68936379Ssklower 	 */
69039950Ssklower 	if (net == 0 || net->isoa_len == 0 || snpamask) {
69136379Ssklower 		/* redirect to an ES */
69239950Ssklower 		snpac_add(shp->snh_ifp, da,
69343332Ssklower 				bsnpa->isoa_genaddr, SNPA_ES, ht, 0);
69436379Ssklower 	} else {
69539950Ssklower 		snpac_add(shp->snh_ifp, net,
69643332Ssklower 				bsnpa->isoa_genaddr, SNPA_IS, ht, 0);
69739950Ssklower 		snpac_addrt(shp->snh_ifp, da, net, netmask);
69836379Ssklower 	}
69943421Ssklower bad: ;    /* Needed by ESIS_NEXT_OPTION */
70036379Ssklower }
70136379Ssklower 
70236379Ssklower /*
70336379Ssklower  * FUNCTION:		esis_config
70436379Ssklower  *
70536379Ssklower  * PURPOSE:			Report configuration
70636379Ssklower  *
70736379Ssklower  * RETURNS:
70836379Ssklower  *
70936379Ssklower  * SIDE EFFECTS:
71036379Ssklower  *
71136379Ssklower  * NOTES:			Called every esis_config_time seconds
71236379Ssklower  */
71336379Ssklower esis_config()
71436379Ssklower {
71536379Ssklower 	register struct ifnet	*ifp;
71636379Ssklower 
71736379Ssklower 	timeout(esis_config, (caddr_t)0, hz * esis_config_time);
71836379Ssklower 
71936379Ssklower 	/*
72036379Ssklower 	 *	Report configuration for each interface that
72136379Ssklower 	 *	- is UP
72236379Ssklower 	 *	- is not loopback
72336379Ssklower 	 *	- has an ISO address
72436379Ssklower 	 */
72536379Ssklower 
72636379Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
72736379Ssklower 		if ((ifp->if_flags & IFF_UP) &&
72836379Ssklower 			((ifp->if_flags & IFF_LOOPBACK) == 0)) {
72936379Ssklower 			/* search for an ISO address family */
73036379Ssklower 			struct ifaddr	*ia;
73136379Ssklower 
73236379Ssklower 			for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {
73337469Ssklower 				if (ia->ifa_addr->sa_family == AF_ISO) {
73436379Ssklower 					esis_shoutput(ifp,
73536379Ssklower 						iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
73636379Ssklower 						esis_holding_time,
73743332Ssklower 						(caddr_t)(iso_systype & SNPA_ES ? all_is_snpa :
73843332Ssklower 						all_es_snpa), 6, (struct iso_addr *)0);
73936379Ssklower 					break;
74036379Ssklower 				}
74136379Ssklower 			}
74236379Ssklower 		}
74336379Ssklower 	}
74436379Ssklower }
74536379Ssklower 
74636379Ssklower /*
74736379Ssklower  * FUNCTION:		esis_shoutput
74836379Ssklower  *
74936379Ssklower  * PURPOSE:			Transmit an esh or ish pdu
75036379Ssklower  *
75136379Ssklower  * RETURNS:			nothing
75236379Ssklower  *
75336379Ssklower  * SIDE EFFECTS:
75436379Ssklower  *
75536379Ssklower  * NOTES:
75636379Ssklower  */
75743332Ssklower esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa)
75836379Ssklower struct ifnet	*ifp;
75936379Ssklower int				type;
76036379Ssklower short			ht;
76136379Ssklower caddr_t 		sn_addr;
76236379Ssklower int				sn_len;
76343332Ssklower struct	iso_addr *isoa;
76436379Ssklower {
76536379Ssklower 	struct mbuf			*m, *m0;
76636379Ssklower 	caddr_t				cp, naddrp;
76736379Ssklower 	int					naddr = 0;
76836379Ssklower 	struct esis_fixed	*pdu;
76943332Ssklower 	struct iso_ifaddr	*ia;
77037469Ssklower 	int					len;
77136379Ssklower 	struct sockaddr_iso	siso;
77236379Ssklower 
77336379Ssklower 	if (type == ESIS_ESH)
77436379Ssklower 		esis_stat.es_eshsent++;
77536379Ssklower 	else if (type == ESIS_ISH)
77636379Ssklower 		esis_stat.es_ishsent++;
77736379Ssklower 	else {
77836379Ssklower 		printf("esis_shoutput: bad pdu type\n");
77936379Ssklower 		return;
78036379Ssklower 	}
78136379Ssklower 
78236379Ssklower 	IFDEBUG(D_ESISOUTPUT)
78336379Ssklower 		int	i;
78436379Ssklower 		printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ",
78536379Ssklower 			ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish",
78636379Ssklower 			ht, sn_len);
78736379Ssklower 		for (i=0; i<sn_len; i++)
78836379Ssklower 			printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' ');
78936379Ssklower 		printf("\n");
79036379Ssklower 	ENDDEBUG
79136379Ssklower 
79237469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
79336379Ssklower 		esis_stat.es_nomem++;
79436379Ssklower 		return;
79536379Ssklower 	}
79637469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
79736379Ssklower 
79836379Ssklower 	pdu = mtod(m, struct esis_fixed *);
79937469Ssklower 	naddrp = cp = (caddr_t)(pdu + 1);
80036379Ssklower 	len = sizeof(struct esis_fixed);
80136379Ssklower 
80236379Ssklower 	/*
80336379Ssklower 	 *	Build fixed part of header
80436379Ssklower 	 */
80536379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
80636379Ssklower 	pdu->esis_vers = ESIS_VERSION;
80736379Ssklower 	pdu->esis_type = type;
80836379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
80936379Ssklower 
81036379Ssklower 	if (type == ESIS_ESH) {
81136379Ssklower 		cp++;
81236379Ssklower 		len++;
81336379Ssklower 	}
81436379Ssklower 
81537469Ssklower 	m->m_len = len;
81643332Ssklower 	if (isoa) {
81743332Ssklower 		/*
81843332Ssklower 		 * Here we are responding to a clnp packet sent to an NSAP
81943332Ssklower 		 * that is ours which was sent to the MAC addr all_es's.
82043332Ssklower 		 * It is possible that we did not specifically advertise this
82143332Ssklower 		 * NSAP, even though it is ours, so we will respond
82243332Ssklower 		 * directly to the sender that we are here.  If we do have
82343332Ssklower 		 * multiple NSEL's we'll tack them on so he can compress them out.
82443332Ssklower 		 */
82543332Ssklower 		(void) esis_insert_addr(&cp, &len, isoa, m, 0);
82643332Ssklower 		naddr = 1;
82743332Ssklower 	}
82843332Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
82943332Ssklower 		int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0);
83043332Ssklower 		int n = ia->ia_addr.siso_nlen;
83143332Ssklower 		register struct iso_ifaddr *ia2;
83243332Ssklower 
83343332Ssklower 		if (type == ESIS_ISH && naddr > 0)
83443332Ssklower 			break;
83543332Ssklower 		for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next)
83643332Ssklower 			if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0)
83743332Ssklower 					break;
83843332Ssklower 		if (ia2 != ia)
83943332Ssklower 			continue;	/* Means we have previously copied this nsap */
84043332Ssklower 		if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) {
84143332Ssklower 			isoa = 0;
84243332Ssklower 			continue;	/* Ditto */
84336379Ssklower 		}
84443332Ssklower 		IFDEBUG(D_ESISOUTPUT)
84543332Ssklower 			printf("esis_shoutput: adding NSAP %s\n",
84643332Ssklower 				clnp_iso_addrp(&ia->ia_addr.siso_addr));
84743332Ssklower 		ENDDEBUG
84843332Ssklower 		if (!esis_insert_addr(&cp, &len,
84943332Ssklower 							  &ia->ia_addr.siso_addr, m, nsellen)) {
85043332Ssklower 			EXTEND_PACKET(m, m0, cp);
85143332Ssklower 			(void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m,
85243332Ssklower 									nsellen);
85343332Ssklower 		}
85443332Ssklower 		naddr++;
85536379Ssklower 	}
85636379Ssklower 
85736379Ssklower 	if (type == ESIS_ESH)
85836379Ssklower 		*naddrp = naddr;
859*44254Ssklower 	else {
860*44254Ssklower 		/* add suggested es config timer option to ISH */
861*44254Ssklower 		if (M_TRAILINGSPACE(m) < 4) {
862*44254Ssklower 			printf("esis_shoutput: extending packet\n");
863*44254Ssklower 			EXTEND_PACKET(m, m0, cp);
864*44254Ssklower 		}
865*44254Ssklower 		*cp++ = ESISOVAL_ESCT;
866*44254Ssklower 		*cp++ = 2;
867*44254Ssklower 		HTOC(*cp, *(cp+1), esis_esconfig_time);
868*44254Ssklower 		len += 4;
869*44254Ssklower 		m->m_len += 4;
870*44254Ssklower 		IFDEBUG(D_ESISOUTPUT)
871*44254Ssklower 			printf("m0 0x%x, m 0x%x, data 0x%x, len %d, cp 0x%x\n",
872*44254Ssklower 			m0, m, m->m_data, m->m_len, cp);
873*44254Ssklower 		ENDDEBUG
874*44254Ssklower 	}
87536379Ssklower 
87637469Ssklower 	m0->m_pkthdr.len = len;
87737469Ssklower 	pdu->esis_hdr_len = len;
87836379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
87936379Ssklower 
88037469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
88136379Ssklower 	siso.siso_family = AF_ISO;
88237469Ssklower 	siso.siso_data[0] = AFI_SNA;
88337469Ssklower 	siso.siso_nlen = sn_len + 1;
88437469Ssklower 	bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len);
88540775Ssklower 	(ifp->if_output)(ifp, m0, &siso, 0);
88636379Ssklower }
88736379Ssklower 
88836379Ssklower /*
88943421Ssklower  * FUNCTION:		isis_input
89043421Ssklower  *
89143421Ssklower  * PURPOSE:			Process an incoming isis packet
89243421Ssklower  *
89343421Ssklower  * RETURNS:			nothing
89443421Ssklower  *
89543421Ssklower  * SIDE EFFECTS:
89643421Ssklower  *
89743421Ssklower  * NOTES:
89843421Ssklower  */
89943421Ssklower isis_input(m0, shp)
90043421Ssklower struct mbuf		*m0;		/* ptr to first mbuf of pkt */
90143421Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
90243421Ssklower {
90343421Ssklower 	register int type;
90443961Ssklower 	register struct rawcb *rp, *first_rp = 0;
90543421Ssklower 	struct ifnet *ifp = shp->snh_ifp;
90643421Ssklower 	char workbuf[16];
90743421Ssklower 	struct mbuf *mm;
90843421Ssklower 
90943421Ssklower 	IFDEBUG(D_ISISINPUT)
91043421Ssklower 		int i;
91143421Ssklower 
91243421Ssklower 		printf("isis_input: pkt on ifp x%x (%s%d): from:", ifp,
91343421Ssklower 			ifp->if_name, ifp->if_unit);
91443421Ssklower 		for (i=0; i<6; i++)
91543421Ssklower 			printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' ');
91643421Ssklower 		printf(" to:");
91743421Ssklower 		for (i=0; i<6; i++)
91843421Ssklower 			printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' ');
91943421Ssklower 		printf("\n");
92043421Ssklower 	ENDDEBUG
92143421Ssklower 	esis_dl.sdl_alen = ifp->if_addrlen;
92243421Ssklower 	esis_dl.sdl_index = ifp->if_index;
92343421Ssklower 	bcopy(shp->snh_shost, (caddr_t)esis_dl.sdl_data, esis_dl.sdl_alen);
92443421Ssklower 	for (rp = esis_pcb.rcb_next; rp != &esis_pcb; rp = rp->rcb_next) {
92543961Ssklower 		if (first_rp == 0) {
92643961Ssklower 			first_rp = rp;
92743421Ssklower 			continue;
92843421Ssklower 		}
92943421Ssklower 		if (mm = m_copy(m0, 0, M_COPYALL)) { /*can't block at interrupt level */
93043421Ssklower 			if (sbappendaddr(&rp->rcb_socket->so_rcv,
93143421Ssklower 							  &esis_dl, mm, (struct mbuf *)0) != 0)
93243421Ssklower 				sorwakeup(rp->rcb_socket);
93343421Ssklower 			else {
93443421Ssklower 				IFDEBUG(D_ISISINPUT)
93543421Ssklower 					printf("Error in sbappenaddr, mm = 0x%x\n", mm);
93643421Ssklower 				ENDDEBUG
93743421Ssklower 				m_freem(mm);
93843421Ssklower 			}
93943421Ssklower 		}
94043421Ssklower 	}
94143961Ssklower 	if (first_rp && sbappendaddr(&first_rp->rcb_socket->so_rcv,
94243961Ssklower 							  &esis_dl, mm, (struct mbuf *)0) != 0) {
94343961Ssklower 		sorwakeup(first_rp->rcb_socket);
94443961Ssklower 		return;
94543421Ssklower 	}
94643961Ssklower 	m_freem(m0);
94743421Ssklower }
94843421Ssklower 
94943421Ssklower isis_output(sdl, m)
95043421Ssklower register struct sockaddr_dl	*sdl;
95143421Ssklower struct mbuf *m;
95243421Ssklower {
95343421Ssklower 	register struct ifnet *ifp;
95443421Ssklower 	struct ifaddr *ifa, *ifa_ifwithnet();
95543421Ssklower 	struct sockaddr_iso siso;
95643421Ssklower 	int error = 0;
95743421Ssklower 	unsigned sn_len;
95843421Ssklower 
95943421Ssklower 	ifa = ifa_ifwithnet(sdl);	/* extract ifp from sockaddr_dl */
96043421Ssklower 	if (ifa == 0) {
96143421Ssklower 		IFDEBUG(D_ISISOUTPUT)
96243421Ssklower 			printf("isis_output: interface not found\n");
96343421Ssklower 		ENDDEBUG
96443421Ssklower 		error = EINVAL;
96543421Ssklower 		goto release;
96643421Ssklower 	}
96743421Ssklower 	ifp = ifa->ifa_ifp;
96843421Ssklower 	sn_len = ifp->if_addrlen;
96943421Ssklower 	IFDEBUG(D_ISISOUTPUT)
97043421Ssklower 		u_char *cp = (u_char *)LLADDR(sdl), *cplim = cp + sn_len;
97143421Ssklower 		printf("isis_output: ifp 0x%x (%s%d), to: ",
97243421Ssklower 			ifp, ifp->if_name, ifp->if_unit);
97343421Ssklower 		while (cp < cplim) {
97443421Ssklower 			printf("%x", *cp++);
97543421Ssklower 			printf("%c", (cp < cplim) ? ':' : ' ');
97643421Ssklower 		}
97743421Ssklower 		printf("\n");
97843421Ssklower 	ENDDEBUG
97943421Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
98043421Ssklower 	siso.siso_family = AF_ISO; /* This convention may be useful for X.25 */
98143421Ssklower 	siso.siso_data[0] = AFI_SNA;
98243421Ssklower 	siso.siso_nlen = sn_len + 1;
98343421Ssklower 	bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len);
98443421Ssklower 	error = (ifp->if_output)(ifp, m, (struct sockaddr *)&siso, 0);
98543421Ssklower 	if (error) {
98643421Ssklower 		IFDEBUG(D_ISISOUTPUT)
98743421Ssklower 			printf("isis_output: error from ether_output is %d\n", error);
98843421Ssklower 		ENDDEBUG
98943421Ssklower 	}
99043421Ssklower 	return (error);
99143421Ssklower 
99243421Ssklower release:
99343421Ssklower 	if (m != NULL)
99443421Ssklower 		m_freem(m);
99543421Ssklower 	return(error);
99643421Ssklower }
99743421Ssklower 
99843421Ssklower 
99943421Ssklower /*
100036379Ssklower  * FUNCTION:		esis_ctlinput
100136379Ssklower  *
100236379Ssklower  * PURPOSE:			Handle the PRC_IFDOWN transition
100336379Ssklower  *
100436379Ssklower  * RETURNS:			nothing
100536379Ssklower  *
100636379Ssklower  * SIDE EFFECTS:
100736379Ssklower  *
100836379Ssklower  * NOTES:			Calls snpac_flush for interface specified.
100936379Ssklower  *					The loop through iso_ifaddr is stupid because
101036379Ssklower  *					back in if_down, we knew the ifp...
101136379Ssklower  */
101236379Ssklower esis_ctlinput(req, siso)
101336379Ssklower int						req;		/* request: we handle only PRC_IFDOWN */
101436379Ssklower struct sockaddr_iso		*siso;		/* address of ifp */
101536379Ssklower {
101636379Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
101736379Ssklower 
101837469Ssklower 	if (req == PRC_IFDOWN)
101937469Ssklower 		for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
102037469Ssklower 			if (iso_addrmatch(IA_SIS(ia), siso))
102137469Ssklower 				snpac_flushifp(ia->ia_ifp);
102237469Ssklower 		}
102336379Ssklower }
102436379Ssklower 
102536379Ssklower #endif	ISO
1026