xref: /csrg-svn/sys/netiso/esis.c (revision 43332)
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*43332Ssklower /*	@(#)esis.c	7.8 (Berkeley) 06/20/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"
46*43332Ssklower #include "../net/if_dl.h"
4736379Ssklower #include "../net/route.h"
4836379Ssklower 
4937469Ssklower #include "iso.h"
5037469Ssklower #include "iso_pcb.h"
5137469Ssklower #include "iso_var.h"
5237469Ssklower #include "iso_snpac.h"
5337469Ssklower #include "clnl.h"
5437469Ssklower #include "clnp.h"
5537469Ssklower #include "clnp_stat.h"
5638841Ssklower #include "esis.h"
5737469Ssklower #include "argo_debug.h"
5836379Ssklower 
5936379Ssklower /*
6036379Ssklower  *	Global variables to esis implementation
6136379Ssklower  *
6236379Ssklower  *	esis_holding_time - the holding time (sec) parameter for outgoing pdus
6336379Ssklower  *	esis_config_time  - the frequency (sec) that hellos are generated
6436379Ssklower  *
6536379Ssklower  */
6636379Ssklower struct isopcb	esis_pcb;
6736379Ssklower int				esis_sendspace = 2048;
6836379Ssklower int				esis_recvspace = 2048;
6936379Ssklower short			esis_holding_time = ESIS_HT;
7036379Ssklower short			esis_config_time = ESIS_CONFIG;
7136379Ssklower extern int		iso_systype;
72*43332Ssklower extern char		all_es_snpa[], all_is_snpa[];
7336379Ssklower 
7437469Ssklower #define EXTEND_PACKET(m, mhdr, cp)\
7536379Ssklower 	if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\
7636379Ssklower 		esis_stat.es_nomem++;\
7736379Ssklower 		m_freem(mhdr);\
7836379Ssklower 		return;\
7936379Ssklower 	} else {\
8036379Ssklower 		(m) = (m)->m_next;\
8136379Ssklower 		(cp) = mtod((m), caddr_t);\
8236379Ssklower 	}
8336379Ssklower /*
8436379Ssklower  * FUNCTION:		esis_init
8536379Ssklower  *
8636379Ssklower  * PURPOSE:			Initialize the kernel portion of esis protocol
8736379Ssklower  *
8836379Ssklower  * RETURNS:			nothing
8936379Ssklower  *
9036379Ssklower  * SIDE EFFECTS:
9136379Ssklower  *
9236379Ssklower  * NOTES:
9336379Ssklower  */
9436379Ssklower esis_init()
9536379Ssklower {
9636379Ssklower 	extern struct clnl_protosw clnl_protox[256];
9736379Ssklower 	int esis_input();
9836379Ssklower 	int snpac_age();
9936379Ssklower 	int	esis_config();
10036379Ssklower #ifdef	ISO_X25ESIS
10136379Ssklower 	x25esis_input();
10236379Ssklower #endif	ISO_X25ESIS
10336379Ssklower 
10436379Ssklower 	esis_pcb.isop_next = esis_pcb.isop_prev = &esis_pcb;
10536379Ssklower 
10636379Ssklower 	clnl_protox[ISO9542_ESIS].clnl_input = esis_input;
107*43332Ssklower 	llinfo_llc.lc_next = llinfo_llc.lc_prev = &llinfo_llc;
10836379Ssklower 	timeout(snpac_age, (caddr_t)0, hz);
10936379Ssklower 	timeout(esis_config, (caddr_t)0, hz);
11036379Ssklower 
11136379Ssklower #ifdef	ISO_X25ESIS
11236379Ssklower 	clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input;
11336379Ssklower #endif	ISO_X25ESIS
11436379Ssklower }
11536379Ssklower 
11636379Ssklower /*
11736379Ssklower  * FUNCTION:		esis_usrreq
11836379Ssklower  *
11936379Ssklower  * PURPOSE:			Handle user level esis requests
12036379Ssklower  *
12136379Ssklower  * RETURNS:			0 or appropriate errno
12236379Ssklower  *
12336379Ssklower  * SIDE EFFECTS:
12436379Ssklower  *
12536379Ssklower  * NOTES:			This is here only so esis gets initialized.
12636379Ssklower  */
12737469Ssklower /*ARGSUSED*/
12840775Ssklower esis_usrreq(so, req, m, nam, control)
12936379Ssklower struct socket	*so;		/* socket: used only to get to this code */
13036379Ssklower int				req;		/* request */
13136379Ssklower struct mbuf		*m;			/* data for request */
13236379Ssklower struct mbuf		*nam;		/* optional name */
13340775Ssklower struct mbuf		*control;	/* optional control */
13436379Ssklower {
13536379Ssklower 	if (m != NULL)
13636379Ssklower 		m_freem(m);
13736379Ssklower 
13836379Ssklower 	return(EOPNOTSUPP);
13936379Ssklower }
14036379Ssklower 
14136379Ssklower /*
14236379Ssklower  * FUNCTION:		esis_input
14336379Ssklower  *
14436379Ssklower  * PURPOSE:			Process an incoming esis packet
14536379Ssklower  *
14636379Ssklower  * RETURNS:			nothing
14736379Ssklower  *
14836379Ssklower  * SIDE EFFECTS:
14936379Ssklower  *
15036379Ssklower  * NOTES:
15136379Ssklower  */
15236379Ssklower esis_input(m0, shp)
15336379Ssklower struct mbuf		*m0;		/* ptr to first mbuf of pkt */
15436379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
15536379Ssklower {
15636379Ssklower 	struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
15737469Ssklower 	register int type;
15836379Ssklower 
15936379Ssklower 	IFDEBUG(D_ESISINPUT)
16036379Ssklower 		int i;
16136379Ssklower 
16236379Ssklower 		printf("esis_input: pdu on ifp x%x (%s%d): from:", shp->snh_ifp,
16336379Ssklower 			shp->snh_ifp->if_name, shp->snh_ifp->if_unit);
16436379Ssklower 		for (i=0; i<6; i++)
16536379Ssklower 			printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' ');
16636379Ssklower 		printf(" to:");
16736379Ssklower 		for (i=0; i<6; i++)
16836379Ssklower 			printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' ');
16936379Ssklower 		printf("\n");
17036379Ssklower 	ENDDEBUG
17136379Ssklower 
17236379Ssklower 	/*
17336379Ssklower 	 *	check checksum if necessary
17436379Ssklower 	 */
17537469Ssklower 	if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) {
17636379Ssklower 		esis_stat.es_badcsum++;
17736379Ssklower 		goto bad;
17836379Ssklower 	}
17936379Ssklower 
18036379Ssklower 	/* check version */
18136379Ssklower 	if (pdu->esis_vers != ESIS_VERSION) {
18236379Ssklower 		esis_stat.es_badvers++;
18336379Ssklower 		goto bad;
18436379Ssklower 	}
18536379Ssklower 
18637469Ssklower 	type = pdu->esis_type & 0x1f;
18737469Ssklower 	switch (type) {
18836379Ssklower 		case ESIS_ESH:
18936379Ssklower 			esis_eshinput(m0, shp);
19036379Ssklower 			return;
19136379Ssklower 
19236379Ssklower 		case ESIS_ISH:
19336379Ssklower 			esis_ishinput(m0, shp);
19436379Ssklower 			return;
19536379Ssklower 
19636379Ssklower 		case ESIS_RD:
19736379Ssklower 			esis_rdinput(m0, shp);
19836379Ssklower 			return;
19936379Ssklower 
20036379Ssklower 		default: {
20136379Ssklower 			esis_stat.es_badtype++;
20236379Ssklower 			goto bad;
20336379Ssklower 		}
20436379Ssklower 	}
20536379Ssklower 
20636379Ssklower bad:
20736379Ssklower 	m_freem(m0);
20836379Ssklower }
20936379Ssklower 
21036379Ssklower /*
21136379Ssklower  * FUNCTION:		esis_rdoutput
21236379Ssklower  *
21336379Ssklower  * PURPOSE:			Transmit a redirect pdu
21436379Ssklower  *
21536379Ssklower  * RETURNS:			nothing
21636379Ssklower  *
21736379Ssklower  * SIDE EFFECTS:
21836379Ssklower  *
21936379Ssklower  * NOTES:			Assumes there is enough space for fixed part of header,
22036379Ssklower  *					DA, BSNPA and NET in first mbuf.
22136379Ssklower  */
222*43332Ssklower esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt)
22336379Ssklower struct snpa_hdr		*inbound_shp;	/* snpa hdr from incoming packet */
22436379Ssklower struct mbuf			*inbound_m;		/* incoming pkt itself */
22536379Ssklower struct clnp_optidx	*inbound_oidx;	/* clnp options assoc with incoming pkt */
22636379Ssklower struct iso_addr		*rd_dstnsap;	/* ultimate destination of pkt */
227*43332Ssklower struct rtentry		*rt;			/* snpa cache info regarding next hop of
22836379Ssklower 										pkt */
22936379Ssklower {
23036379Ssklower 	struct mbuf			*m, *m0;
23136379Ssklower 	caddr_t				cp;
23236379Ssklower 	struct esis_fixed	*pdu;
23336379Ssklower 	int					len, total_len = 0;
23436379Ssklower 	struct sockaddr_iso	siso;
23536379Ssklower 	struct ifnet 		*ifp = inbound_shp->snh_ifp;
236*43332Ssklower 	struct sockaddr_dl *sdl;
237*43332Ssklower 	struct iso_addr *rd_gwnsap;
23836379Ssklower 
239*43332Ssklower 	if (rt->rt_flags & RTF_GATEWAY) {
240*43332Ssklower 		rd_gwnsap = &((struct sockaddr_iso *)rt->rt_gateway)->siso_addr;
241*43332Ssklower 		rt = rtalloc1(rt->rt_gateway, 0);
242*43332Ssklower 	} else
243*43332Ssklower 		rd_gwnsap = &((struct sockaddr_iso *)rt_key(rt))->siso_addr;
244*43332Ssklower 	if (rt == 0 || (sdl = (struct sockaddr_dl *)rt->rt_gateway) == 0 ||
245*43332Ssklower 		sdl->sdl_family != AF_LINK) {
246*43332Ssklower 		/* maybe we should have a function that you
247*43332Ssklower 		   could put in the iso_ifaddr structure
248*43332Ssklower 		   which could translate iso_addrs into snpa's
249*43332Ssklower 		   where there is a known mapping for that address type */
250*43332Ssklower 		esis_stat.es_badtype++;
251*43332Ssklower 		return;
252*43332Ssklower 	}
25336379Ssklower 	esis_stat.es_rdsent++;
25436379Ssklower 	IFDEBUG(D_ESISOUTPUT)
25536379Ssklower 		printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n",
25636379Ssklower 			ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m,
25736379Ssklower 			inbound_oidx);
25836379Ssklower 		printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap));
259*43332Ssklower 		printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap));
26036379Ssklower 	ENDDEBUG
26136379Ssklower 
26237469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
26336379Ssklower 		esis_stat.es_nomem++;
26436379Ssklower 		return;
26536379Ssklower 	}
26637469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
26736379Ssklower 
26836379Ssklower 	pdu = mtod(m, struct esis_fixed *);
26937469Ssklower 	cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */
27036379Ssklower 	len = sizeof(struct esis_fixed);
27136379Ssklower 
27236379Ssklower 	/*
27336379Ssklower 	 *	Build fixed part of header
27436379Ssklower 	 */
27536379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
27636379Ssklower 	pdu->esis_vers = ESIS_VERSION;
27736379Ssklower 	pdu->esis_type = ESIS_RD;
27836379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time);
27936379Ssklower 
28036379Ssklower 	/* Insert destination address */
28143072Ssklower 	(void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0);
28236379Ssklower 
28336379Ssklower 	/* Insert the snpa of better next hop */
284*43332Ssklower 	*cp++ = sdl->sdl_alen;
285*43332Ssklower 	bcopy(LLADDR(sdl), cp, sdl->sdl_alen);
286*43332Ssklower 	cp += sdl->sdl_alen;
287*43332Ssklower 	len += (sdl->sdl_alen + 1);
28836379Ssklower 
28936379Ssklower 	/*
29036379Ssklower 	 *	If the next hop is not the destination, then it ought to be
29136379Ssklower 	 *	an IS and it should be inserted next. Else, set the
29236379Ssklower 	 *	NETL to 0
29336379Ssklower 	 */
29436379Ssklower 	/* PHASE2 use mask from ifp of outgoing interface */
295*43332Ssklower 	if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) {
296*43332Ssklower 		/* this should not happen:
29736379Ssklower 		if ((nhop_sc->sc_flags & SNPA_IS) == 0) {
29836379Ssklower 			printf("esis_rdoutput: next hop is not dst and not an IS\n");
29936379Ssklower 			m_freem(m0);
30036379Ssklower 			return;
301*43332Ssklower 		} */
302*43332Ssklower 		(void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0);
30336379Ssklower 	} else {
30436379Ssklower 		*cp++ = 0;	/* NETL */
30536379Ssklower 		len++;
30636379Ssklower 	}
30737469Ssklower 	m->m_len = len;
30836379Ssklower 
30936379Ssklower 	/*
31036379Ssklower 	 *	PHASE2
31136379Ssklower 	 *	If redirect is to an IS, add an address mask. The mask to be
31236379Ssklower 	 *	used should be the mask present in the routing entry used to
31336379Ssklower 	 *	forward the original data packet.
31436379Ssklower 	 */
31536379Ssklower 
31636379Ssklower 	/*
31736379Ssklower 	 *	Copy Qos, priority, or security options present in original npdu
31836379Ssklower 	 */
31936379Ssklower 	if (inbound_oidx) {
320*43332Ssklower 		/* THIS CODE IS CURRENTLY (mostly) UNTESTED */
32136379Ssklower 		int optlen = 0;
32236379Ssklower 		if (inbound_oidx->cni_qos_formatp)
32336379Ssklower 			optlen += (inbound_oidx->cni_qos_len + 2);
32436379Ssklower 		if (inbound_oidx->cni_priorp)	/* priority option is 1 byte long */
32536379Ssklower 			optlen += 3;
32636379Ssklower 		if (inbound_oidx->cni_securep)
32736379Ssklower 			optlen += (inbound_oidx->cni_secure_len + 2);
32837469Ssklower 		if (M_TRAILINGSPACE(m) < optlen) {
32937469Ssklower 			EXTEND_PACKET(m, m0, cp);
33037469Ssklower 			m->m_len = 0;
33136379Ssklower 			/* assumes MLEN > optlen */
33236379Ssklower 		}
33336379Ssklower 		/* assume MLEN-len > optlen */
33436379Ssklower 		/*
33536379Ssklower 		 *	When copying options, copy from ptr - 2 in order to grab
33636379Ssklower 		 *	the option code and length
33736379Ssklower 		 */
33836379Ssklower 		if (inbound_oidx->cni_qos_formatp) {
339*43332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_qos_formatp - 2,
340*43332Ssklower 				cp, (unsigned)(inbound_oidx->cni_qos_len + 2));
341*43332Ssklower 			cp += inbound_oidx->cni_qos_len + 2;
34236379Ssklower 		}
34336379Ssklower 		if (inbound_oidx->cni_priorp) {
344*43332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_priorp - 2,
345*43332Ssklower 					cp, 3);
346*43332Ssklower 			cp += 3;
34736379Ssklower 		}
34836379Ssklower 		if (inbound_oidx->cni_securep) {
349*43332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_securep - 2, cp,
35037469Ssklower 				(unsigned)(inbound_oidx->cni_secure_len + 2));
351*43332Ssklower 			cp += inbound_oidx->cni_secure_len + 2;
35236379Ssklower 		}
35337469Ssklower 		m->m_len += optlen;
354*43332Ssklower 		len += optlen;
35536379Ssklower 	}
35636379Ssklower 
35737469Ssklower 	pdu->esis_hdr_len = m0->m_pkthdr.len = len;
35836379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
35936379Ssklower 
36037469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
36137469Ssklower 	siso.siso_len = 12;
36236379Ssklower 	siso.siso_family = AF_ISO;
36337469Ssklower 	siso.siso_data[0] = AFI_SNA;
36437469Ssklower 	siso.siso_nlen = 6 + 1;	/* should be taken from snpa_hdr */
36536379Ssklower 										/* +1 is for AFI */
36637469Ssklower 	bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6);
36740775Ssklower 	(ifp->if_output)(ifp, m0, &siso, 0);
36836379Ssklower }
36936379Ssklower 
37036379Ssklower /*
37136379Ssklower  * FUNCTION:		esis_insert_addr
37236379Ssklower  *
37336379Ssklower  * PURPOSE:			Insert an iso_addr into a buffer
37436379Ssklower  *
37536379Ssklower  * RETURNS:			true if buffer was big enough, else false
37636379Ssklower  *
37736379Ssklower  * SIDE EFFECTS:	Increment buf & len according to size of iso_addr
37836379Ssklower  *
37936379Ssklower  * NOTES:			Plus 1 here is for length byte
38036379Ssklower  */
38143072Ssklower esis_insert_addr(buf, len, isoa, m, nsellen)
382*43332Ssklower register caddr_t			*buf;		/* ptr to buffer to put address into */
383*43332Ssklower int							*len;		/* ptr to length of buffer so far */
384*43332Ssklower register struct iso_addr	*isoa;		/* ptr to address */
385*43332Ssklower register struct mbuf		*m;			/* determine if there remains space */
386*43332Ssklower int							nsellen;
38736379Ssklower {
388*43332Ssklower 	register int newlen, result = 0;
38936379Ssklower 
390*43332Ssklower 	isoa->isoa_len -= nsellen;
391*43332Ssklower 	newlen = isoa->isoa_len + 1;
392*43332Ssklower 	if (newlen <=  M_TRAILINGSPACE(m)) {
393*43332Ssklower 		bcopy((caddr_t)isoa, *buf, newlen);
394*43332Ssklower 		*len += newlen;
395*43332Ssklower 		*buf += newlen;
396*43332Ssklower 		m->m_len += newlen;
397*43332Ssklower 		result = 1;
398*43332Ssklower 	}
399*43332Ssklower 	isoa->isoa_len += nsellen;
400*43332Ssklower 	return (result);
40136379Ssklower }
40236379Ssklower 
40339950Ssklower #define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \
40439950Ssklower 	    if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
40539950Ssklower #define ESIS_NEXT_OPTION(b)	{ b += (2 + b[1]); \
40639950Ssklower 	    if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
40740775Ssklower int ESHonly = 1;
40836379Ssklower /*
40936379Ssklower 
41036379Ssklower /*
41136379Ssklower  * FUNCTION:		esis_eshinput
41236379Ssklower  *
41336379Ssklower  * PURPOSE:			Process an incoming ESH pdu
41436379Ssklower  *
41536379Ssklower  * RETURNS:			nothing
41636379Ssklower  *
41736379Ssklower  * SIDE EFFECTS:
41836379Ssklower  *
41936379Ssklower  * NOTES:
42036379Ssklower  */
42136379Ssklower esis_eshinput(m, shp)
42236379Ssklower struct mbuf		*m;	/* esh pdu */
42336379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
42436379Ssklower {
42543072Ssklower 	struct	esis_fixed	*pdu = mtod(m, struct esis_fixed *);
42636379Ssklower 	u_short				ht;		/* holding time */
42743072Ssklower 	struct	iso_addr	*nsap;
42839950Ssklower 	int					naddr;
42937469Ssklower 	u_char				*buf = (u_char *)(pdu + 1);
43039950Ssklower 	u_char				*buflim = pdu->esis_hdr_len + (u_char *)pdu;
431*43332Ssklower 	int					new_entry = 0;
43236379Ssklower 
43336379Ssklower 	esis_stat.es_eshrcvd++;
43436379Ssklower 
43536379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
43636379Ssklower 
43739950Ssklower 	naddr = *buf++;
43839950Ssklower 	if (buf >= buflim)
43936379Ssklower 		goto bad;
440*43332Ssklower 	if (naddr == 1) {
44139950Ssklower 		ESIS_EXTRACT_ADDR(nsap, buf);
442*43332Ssklower 		new_entry = snpac_add(shp->snh_ifp,
443*43332Ssklower 								 nsap, shp->snh_shost, SNPA_ES, ht, 0);
444*43332Ssklower 	} else {
445*43332Ssklower 		int nsellength = 0, nlen = 0;
446*43332Ssklower 		{
447*43332Ssklower 		/* See if we want to compress out multiple nsaps differing
448*43332Ssklower 		   only by nsel */
449*43332Ssklower 			register struct ifaddr *ifa = shp->snh_ifp->if_addrlist;
450*43332Ssklower 			for (; ifa; ifa = ifa->ifa_next)
451*43332Ssklower 				if (ifa->ifa_addr->sa_family == AF_ISO) {
452*43332Ssklower 					nsellength = ((struct iso_ifaddr *)ifa)->ia_addr.siso_tlen;
453*43332Ssklower 					break;
454*43332Ssklower 			}
455*43332Ssklower 		}
45639950Ssklower 		IFDEBUG(D_ESISINPUT)
457*43332Ssklower 			printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n",
458*43332Ssklower 					ht, naddr, nsellength);
45939950Ssklower 		ENDDEBUG
460*43332Ssklower 		while (naddr-- > 0) {
461*43332Ssklower 			struct iso_addr *nsap2; u_char *buf2;
462*43332Ssklower 			ESIS_EXTRACT_ADDR(nsap, buf);
463*43332Ssklower 			/* see if there is at least one more nsap in ESH differing
464*43332Ssklower 			   only by nsel */
465*43332Ssklower 			if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) {
466*43332Ssklower 				ESIS_EXTRACT_ADDR(nsap2, buf2);
467*43332Ssklower 				IFDEBUG(D_ESISINPUT)
468*43332Ssklower 					printf("esis_eshinput: comparing %s ",
469*43332Ssklower 						clnp_iso_addrp(nsap));
470*43332Ssklower 					printf("and %s\n", clnp_iso_addrp(nsap2));
471*43332Ssklower 				ENDDEBUG
472*43332Ssklower 				if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr,
473*43332Ssklower 						 nsap->isoa_len - nsellength) == 0) {
474*43332Ssklower 					nlen = nsellength;
475*43332Ssklower 					break;
476*43332Ssklower 				}
477*43332Ssklower 			}
478*43332Ssklower 			new_entry |= snpac_add(shp->snh_ifp,
479*43332Ssklower 									nsap, shp->snh_shost, SNPA_ES, ht, nlen);
480*43332Ssklower 			nlen = 0;
481*43332Ssklower 		}
48239950Ssklower 	}
483*43332Ssklower 	IFDEBUG(D_ESISINPUT)
484*43332Ssklower 		printf("esis_eshinput: nsap %s is %s\n",
485*43332Ssklower 			clnp_iso_addrp(nsap), new_entry ? "new" : "old");
486*43332Ssklower 	ENDDEBUG
487*43332Ssklower 	if (new_entry && (iso_systype & SNPA_IS))
488*43332Ssklower 		esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time,
489*43332Ssklower 						shp->snh_shost, 6, (struct iso_addr *)0);
49037469Ssklower bad:
49136379Ssklower 	m_freem(m);
49239950Ssklower 	return;
49336379Ssklower }
49436379Ssklower 
49536379Ssklower /*
49636379Ssklower  * FUNCTION:		esis_ishinput
49736379Ssklower  *
49836379Ssklower  * PURPOSE:			process an incoming ISH pdu
49936379Ssklower  *
50036379Ssklower  * RETURNS:
50136379Ssklower  *
50236379Ssklower  * SIDE EFFECTS:
50336379Ssklower  *
50436379Ssklower  * NOTES:
50536379Ssklower  */
50636379Ssklower esis_ishinput(m, shp)
50736379Ssklower struct mbuf		*m;	/* esh pdu */
50836379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
50936379Ssklower {
51036379Ssklower 	struct esis_fixed	*pdu = mtod(m, struct esis_fixed *);
51139950Ssklower 	u_short				ht;					/* holding time */
51239950Ssklower 	struct iso_addr		*nsap; 				/* Network Entity Title */
51339950Ssklower 	register u_char		*buf = (u_char *) (pdu + 1);
51439950Ssklower 	register u_char		*buflim = pdu->esis_hdr_len + (u_char *)pdu;
51539950Ssklower 	int					new_entry;
51636379Ssklower 
51736379Ssklower 	esis_stat.es_ishrcvd++;
51836379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
51936379Ssklower 
52036379Ssklower 	IFDEBUG(D_ESISINPUT)
52136379Ssklower 		printf("esis_ishinput: ish: ht %d\n", ht);
52236379Ssklower 	ENDDEBUG
52339950Ssklower 	if (ESHonly)
52437469Ssklower 		goto bad;
52536379Ssklower 
52639950Ssklower 	ESIS_EXTRACT_ADDR(nsap, buf);
52739950Ssklower 
52839950Ssklower 	while (buf < buflim) {
52939950Ssklower 		switch (*buf) {
53037469Ssklower 		case ESISOVAL_ESCT:
53139950Ssklower 			if (buf[1] != 2)
53237469Ssklower 				goto bad;
53339950Ssklower 			CTOH(buf[2], buf[3], esis_config_time);
53439950Ssklower 			break;
53539950Ssklower 
53639950Ssklower 		default:
53739950Ssklower 			printf("Unknown ISH option: %x\n", *buf);
53837469Ssklower 		}
53939950Ssklower 		ESIS_NEXT_OPTION(buf);
54037469Ssklower 	}
541*43332Ssklower 	new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0);
54237469Ssklower 	IFDEBUG(D_ESISINPUT)
54337469Ssklower 		printf("esis_ishinput: nsap %s is %s\n",
54437469Ssklower 			clnp_iso_addrp(nsap), new_entry ? "new" : "old");
54537469Ssklower 	ENDDEBUG
54637469Ssklower 
54737469Ssklower 	if (new_entry)
54837469Ssklower 		esis_shoutput(shp->snh_ifp,
54937469Ssklower 			iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
550*43332Ssklower 			esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0);
55139950Ssklower bad:
55236379Ssklower 	m_freem(m);
55339950Ssklower 	return;
55436379Ssklower }
55536379Ssklower 
55636379Ssklower /*
55736379Ssklower  * FUNCTION:		esis_rdinput
55836379Ssklower  *
55936379Ssklower  * PURPOSE:			Process an incoming RD pdu
56036379Ssklower  *
56136379Ssklower  * RETURNS:
56236379Ssklower  *
56336379Ssklower  * SIDE EFFECTS:
56436379Ssklower  *
56536379Ssklower  * NOTES:
56636379Ssklower  */
56736379Ssklower esis_rdinput(m0, shp)
56836379Ssklower struct mbuf		*m0;	/* esh pdu */
56936379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
57036379Ssklower {
57136379Ssklower 	struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
57236379Ssklower 	u_short				ht;		/* holding time */
57339950Ssklower 	struct iso_addr		*da, *net = 0, *netmask = 0, *snpamask = 0;
57439950Ssklower 	register struct iso_addr *bsnpa;
57539950Ssklower 	register u_char		*buf = (u_char *)(pdu + 1);
57639950Ssklower 	register u_char		*buflim = pdu->esis_hdr_len + (u_char *)pdu;
57736379Ssklower 
57836379Ssklower 	esis_stat.es_rdrcvd++;
57936379Ssklower 
58036379Ssklower 	/* intermediate systems ignore redirects */
58136379Ssklower 	if (iso_systype & SNPA_IS)
58236379Ssklower 		goto bad;
58339950Ssklower 	if (ESHonly)
58439950Ssklower 		goto bad;
58536379Ssklower 
58636379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
58739950Ssklower 	if (buf >= buflim)
58837469Ssklower 		goto bad;
58936379Ssklower 
59036379Ssklower 	/* Extract DA */
59139950Ssklower 	ESIS_EXTRACT_ADDR(da, buf);
59237469Ssklower 
59336379Ssklower 	/* Extract better snpa */
59439950Ssklower 	ESIS_EXTRACT_ADDR(bsnpa, buf);
59539950Ssklower 
59637469Ssklower 	/* Extract NET if present */
59739950Ssklower 	if (buf < buflim) {
598*43332Ssklower 		if (*buf == 0)
599*43332Ssklower 			buf++; /* no NET present, skip NETL anyway */
600*43332Ssklower 		else
601*43332Ssklower 			ESIS_EXTRACT_ADDR(net, buf);
60236379Ssklower 	}
60336379Ssklower 
60437469Ssklower 	/* process options */
60539950Ssklower 	while (buf < buflim) {
60639950Ssklower 		switch (*buf) {
60737469Ssklower 		case ESISOVAL_SNPAMASK:
60837469Ssklower 			if (snpamask) /* duplicate */
60937469Ssklower 				goto bad;
61039950Ssklower 			snpamask = (struct iso_addr *)(buf + 1);
61137469Ssklower 			break;
61237469Ssklower 
61337469Ssklower 		case ESISOVAL_NETMASK:
61437469Ssklower 			if (netmask) /* duplicate */
61537469Ssklower 				goto bad;
61639950Ssklower 			netmask = (struct iso_addr *)(buf + 1);
61739950Ssklower 			break;
61839950Ssklower 
61939950Ssklower 		default:
62039950Ssklower 			printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]);
62137469Ssklower 		}
62239950Ssklower 		ESIS_NEXT_OPTION(buf);
62336379Ssklower 	}
62436379Ssklower 
62536379Ssklower 	IFDEBUG(D_ESISINPUT)
62637469Ssklower 		printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da));
62737469Ssklower 		if (net)
62837469Ssklower 			printf("\t: net %s\n", clnp_iso_addrp(net));
62936379Ssklower 	ENDDEBUG
63036379Ssklower 	/*
63136379Ssklower 	 *	If netl is zero, then redirect is to an ES. We need to add an entry
63236379Ssklower 	 *	to the snpa cache for (destination, better snpa).
63336379Ssklower 	 *	If netl is not zero, then the redirect is to an IS. In this
63436379Ssklower 	 *	case, add an snpa cache entry for (net, better snpa).
63536379Ssklower 	 *
63636379Ssklower 	 *	If the redirect is to an IS, add a route entry towards that
63736379Ssklower 	 *	IS.
63836379Ssklower 	 */
63939950Ssklower 	if (net == 0 || net->isoa_len == 0 || snpamask) {
64036379Ssklower 		/* redirect to an ES */
64139950Ssklower 		snpac_add(shp->snh_ifp, da,
642*43332Ssklower 				bsnpa->isoa_genaddr, SNPA_ES, ht, 0);
64336379Ssklower 	} else {
64439950Ssklower 		snpac_add(shp->snh_ifp, net,
645*43332Ssklower 				bsnpa->isoa_genaddr, SNPA_IS, ht, 0);
64639950Ssklower 		snpac_addrt(shp->snh_ifp, da, net, netmask);
64736379Ssklower 	}
64836379Ssklower bad:
64936379Ssklower 	m_freem(m0);
65036379Ssklower }
65136379Ssklower 
65236379Ssklower /*
65336379Ssklower  * FUNCTION:		esis_config
65436379Ssklower  *
65536379Ssklower  * PURPOSE:			Report configuration
65636379Ssklower  *
65736379Ssklower  * RETURNS:
65836379Ssklower  *
65936379Ssklower  * SIDE EFFECTS:
66036379Ssklower  *
66136379Ssklower  * NOTES:			Called every esis_config_time seconds
66236379Ssklower  */
66336379Ssklower esis_config()
66436379Ssklower {
66536379Ssklower 	register struct ifnet	*ifp;
66636379Ssklower 
66736379Ssklower 	timeout(esis_config, (caddr_t)0, hz * esis_config_time);
66836379Ssklower 
66936379Ssklower 	/*
67036379Ssklower 	 *	Report configuration for each interface that
67136379Ssklower 	 *	- is UP
67236379Ssklower 	 *	- is not loopback
67336379Ssklower 	 *	- has broadcast capabilities
67436379Ssklower 	 *	- has an ISO address
67536379Ssklower 	 */
67636379Ssklower 
67736379Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
67836379Ssklower 		if ((ifp->if_flags & IFF_UP) &&
67936379Ssklower 			(ifp->if_flags & IFF_BROADCAST) &&
68036379Ssklower 			((ifp->if_flags & IFF_LOOPBACK) == 0)) {
68136379Ssklower 			/* search for an ISO address family */
68236379Ssklower 			struct ifaddr	*ia;
68336379Ssklower 
68436379Ssklower 			for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {
68537469Ssklower 				if (ia->ifa_addr->sa_family == AF_ISO) {
68636379Ssklower 					esis_shoutput(ifp,
68736379Ssklower 						iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
68836379Ssklower 						esis_holding_time,
689*43332Ssklower 						(caddr_t)(iso_systype & SNPA_ES ? all_is_snpa :
690*43332Ssklower 						all_es_snpa), 6, (struct iso_addr *)0);
69136379Ssklower 					break;
69236379Ssklower 				}
69336379Ssklower 			}
69436379Ssklower 		}
69536379Ssklower 	}
69636379Ssklower }
69736379Ssklower 
69836379Ssklower /*
69936379Ssklower  * FUNCTION:		esis_shoutput
70036379Ssklower  *
70136379Ssklower  * PURPOSE:			Transmit an esh or ish pdu
70236379Ssklower  *
70336379Ssklower  * RETURNS:			nothing
70436379Ssklower  *
70536379Ssklower  * SIDE EFFECTS:
70636379Ssklower  *
70736379Ssklower  * NOTES:
70836379Ssklower  */
709*43332Ssklower esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa)
71036379Ssklower struct ifnet	*ifp;
71136379Ssklower int				type;
71236379Ssklower short			ht;
71336379Ssklower caddr_t 		sn_addr;
71436379Ssklower int				sn_len;
715*43332Ssklower struct	iso_addr *isoa;
71636379Ssklower {
71736379Ssklower 	struct mbuf			*m, *m0;
71836379Ssklower 	caddr_t				cp, naddrp;
71936379Ssklower 	int					naddr = 0;
72036379Ssklower 	struct esis_fixed	*pdu;
721*43332Ssklower 	struct iso_ifaddr	*ia;
72237469Ssklower 	int					len;
72336379Ssklower 	struct sockaddr_iso	siso;
72436379Ssklower 
72536379Ssklower 	if (type == ESIS_ESH)
72636379Ssklower 		esis_stat.es_eshsent++;
72736379Ssklower 	else if (type == ESIS_ISH)
72836379Ssklower 		esis_stat.es_ishsent++;
72936379Ssklower 	else {
73036379Ssklower 		printf("esis_shoutput: bad pdu type\n");
73136379Ssklower 		return;
73236379Ssklower 	}
73336379Ssklower 
73436379Ssklower 	IFDEBUG(D_ESISOUTPUT)
73536379Ssklower 		int	i;
73636379Ssklower 		printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ",
73736379Ssklower 			ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish",
73836379Ssklower 			ht, sn_len);
73936379Ssklower 		for (i=0; i<sn_len; i++)
74036379Ssklower 			printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' ');
74136379Ssklower 		printf("\n");
74236379Ssklower 	ENDDEBUG
74336379Ssklower 
74437469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
74536379Ssklower 		esis_stat.es_nomem++;
74636379Ssklower 		return;
74736379Ssklower 	}
74837469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
74936379Ssklower 
75036379Ssklower 	pdu = mtod(m, struct esis_fixed *);
75137469Ssklower 	naddrp = cp = (caddr_t)(pdu + 1);
75236379Ssklower 	len = sizeof(struct esis_fixed);
75336379Ssklower 
75436379Ssklower 	/*
75536379Ssklower 	 *	Build fixed part of header
75636379Ssklower 	 */
75736379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
75836379Ssklower 	pdu->esis_vers = ESIS_VERSION;
75936379Ssklower 	pdu->esis_type = type;
76036379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
76136379Ssklower 
76236379Ssklower 	if (type == ESIS_ESH) {
76336379Ssklower 		cp++;
76436379Ssklower 		len++;
76536379Ssklower 	}
76636379Ssklower 
76737469Ssklower 	m->m_len = len;
768*43332Ssklower 	if (isoa) {
769*43332Ssklower 		/*
770*43332Ssklower 		 * Here we are responding to a clnp packet sent to an NSAP
771*43332Ssklower 		 * that is ours which was sent to the MAC addr all_es's.
772*43332Ssklower 		 * It is possible that we did not specifically advertise this
773*43332Ssklower 		 * NSAP, even though it is ours, so we will respond
774*43332Ssklower 		 * directly to the sender that we are here.  If we do have
775*43332Ssklower 		 * multiple NSEL's we'll tack them on so he can compress them out.
776*43332Ssklower 		 */
777*43332Ssklower 		(void) esis_insert_addr(&cp, &len, isoa, m, 0);
778*43332Ssklower 		naddr = 1;
779*43332Ssklower 	}
780*43332Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
781*43332Ssklower 		int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0);
782*43332Ssklower 		int n = ia->ia_addr.siso_nlen;
783*43332Ssklower 		register struct iso_ifaddr *ia2;
784*43332Ssklower 
785*43332Ssklower 		if (type == ESIS_ISH && naddr > 0)
786*43332Ssklower 			break;
787*43332Ssklower 		for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next)
788*43332Ssklower 			if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0)
789*43332Ssklower 					break;
790*43332Ssklower 		if (ia2 != ia)
791*43332Ssklower 			continue;	/* Means we have previously copied this nsap */
792*43332Ssklower 		if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) {
793*43332Ssklower 			isoa = 0;
794*43332Ssklower 			continue;	/* Ditto */
79536379Ssklower 		}
796*43332Ssklower 		IFDEBUG(D_ESISOUTPUT)
797*43332Ssklower 			printf("esis_shoutput: adding NSAP %s\n",
798*43332Ssklower 				clnp_iso_addrp(&ia->ia_addr.siso_addr));
799*43332Ssklower 		ENDDEBUG
800*43332Ssklower 		if (!esis_insert_addr(&cp, &len,
801*43332Ssklower 							  &ia->ia_addr.siso_addr, m, nsellen)) {
802*43332Ssklower 			EXTEND_PACKET(m, m0, cp);
803*43332Ssklower 			(void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m,
804*43332Ssklower 									nsellen);
805*43332Ssklower 		}
806*43332Ssklower 		naddr++;
80736379Ssklower 	}
80836379Ssklower 
80936379Ssklower 	if (type == ESIS_ESH)
81036379Ssklower 		*naddrp = naddr;
81136379Ssklower 
81237469Ssklower 	m0->m_pkthdr.len = len;
81337469Ssklower 	pdu->esis_hdr_len = len;
81436379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
81536379Ssklower 
81637469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
81736379Ssklower 	siso.siso_family = AF_ISO;
81837469Ssklower 	siso.siso_data[0] = AFI_SNA;
81937469Ssklower 	siso.siso_nlen = sn_len + 1;
82037469Ssklower 	siso.siso_len  = sn_len + 6;
82137469Ssklower 	bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len);
82240775Ssklower 	(ifp->if_output)(ifp, m0, &siso, 0);
82336379Ssklower }
82436379Ssklower 
82536379Ssklower /*
82636379Ssklower  * FUNCTION:		esis_ctlinput
82736379Ssklower  *
82836379Ssklower  * PURPOSE:			Handle the PRC_IFDOWN transition
82936379Ssklower  *
83036379Ssklower  * RETURNS:			nothing
83136379Ssklower  *
83236379Ssklower  * SIDE EFFECTS:
83336379Ssklower  *
83436379Ssklower  * NOTES:			Calls snpac_flush for interface specified.
83536379Ssklower  *					The loop through iso_ifaddr is stupid because
83636379Ssklower  *					back in if_down, we knew the ifp...
83736379Ssklower  */
83836379Ssklower esis_ctlinput(req, siso)
83936379Ssklower int						req;		/* request: we handle only PRC_IFDOWN */
84036379Ssklower struct sockaddr_iso		*siso;		/* address of ifp */
84136379Ssklower {
84236379Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
84336379Ssklower 
84437469Ssklower 	if (req == PRC_IFDOWN)
84537469Ssklower 		for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
84637469Ssklower 			if (iso_addrmatch(IA_SIS(ia), siso))
84737469Ssklower 				snpac_flushifp(ia->ia_ifp);
84837469Ssklower 		}
84936379Ssklower }
85036379Ssklower 
85136379Ssklower #endif	ISO
852