xref: /csrg-svn/sys/netiso/esis.c (revision 37469)
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  */
2736379Ssklower #ifndef lint
2836379Ssklower static char *rcsid = "$Header: esis.c,v 4.10 88/09/15 18:57:03 hagens Exp $";
2936379Ssklower #endif
3036379Ssklower 
3136379Ssklower #ifdef ISO
3236379Ssklower 
33*37469Ssklower #include "types.h"
34*37469Ssklower #include "param.h"
35*37469Ssklower #include "mbuf.h"
36*37469Ssklower #include "domain.h"
37*37469Ssklower #include "protosw.h"
38*37469Ssklower #include "dir.h"
39*37469Ssklower #include "user.h"
40*37469Ssklower #include "socket.h"
41*37469Ssklower #include "socketvar.h"
42*37469Ssklower #include "errno.h"
43*37469Ssklower #include "kernel.h"
4436379Ssklower 
4536379Ssklower #include "../net/if.h"
4636379Ssklower #include "../net/route.h"
4736379Ssklower 
48*37469Ssklower #include "iso.h"
49*37469Ssklower #include "iso_pcb.h"
50*37469Ssklower #include "iso_var.h"
51*37469Ssklower #include "iso_snpac.h"
52*37469Ssklower #include "clnl.h"
53*37469Ssklower #include "clnp.h"
54*37469Ssklower #include "clnp_stat.h"
55*37469Ssklower #include "argo_debug.h"
56*37469Ssklower #include "esis.h"
5736379Ssklower 
5836379Ssklower /*
5936379Ssklower  *	Global variables to esis implementation
6036379Ssklower  *
6136379Ssklower  *	esis_holding_time - the holding time (sec) parameter for outgoing pdus
6236379Ssklower  *	esis_config_time  - the frequency (sec) that hellos are generated
6336379Ssklower  *
6436379Ssklower  */
6536379Ssklower struct isopcb	esis_pcb;
6636379Ssklower int				esis_sendspace = 2048;
6736379Ssklower int				esis_recvspace = 2048;
6836379Ssklower short			esis_holding_time = ESIS_HT;
6936379Ssklower short			esis_config_time = ESIS_CONFIG;
7036379Ssklower extern int		iso_systype;
7136379Ssklower extern struct snpa_cache	all_es, all_is;
7236379Ssklower 
73*37469Ssklower #define EXTEND_PACKET(m, mhdr, cp)\
7436379Ssklower 	if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\
7536379Ssklower 		esis_stat.es_nomem++;\
7636379Ssklower 		m_freem(mhdr);\
7736379Ssklower 		return;\
7836379Ssklower 	} else {\
7936379Ssklower 		(m) = (m)->m_next;\
8036379Ssklower 		(cp) = mtod((m), caddr_t);\
8136379Ssklower 	}
8236379Ssklower /*
8336379Ssklower  * FUNCTION:		esis_init
8436379Ssklower  *
8536379Ssklower  * PURPOSE:			Initialize the kernel portion of esis protocol
8636379Ssklower  *
8736379Ssklower  * RETURNS:			nothing
8836379Ssklower  *
8936379Ssklower  * SIDE EFFECTS:
9036379Ssklower  *
9136379Ssklower  * NOTES:
9236379Ssklower  */
9336379Ssklower esis_init()
9436379Ssklower {
9536379Ssklower 	extern struct clnl_protosw clnl_protox[256];
9636379Ssklower 	int esis_input();
9736379Ssklower 	int snpac_age();
9836379Ssklower 	int	esis_config();
9936379Ssklower #ifdef	ISO_X25ESIS
10036379Ssklower 	x25esis_input();
10136379Ssklower #endif	ISO_X25ESIS
10236379Ssklower 
10336379Ssklower 	esis_pcb.isop_next = esis_pcb.isop_prev = &esis_pcb;
10436379Ssklower 
10536379Ssklower 	clnl_protox[ISO9542_ESIS].clnl_input = esis_input;
10636379Ssklower 	timeout(snpac_age, (caddr_t)0, hz);
10736379Ssklower 	timeout(esis_config, (caddr_t)0, hz);
10836379Ssklower 
10936379Ssklower #ifdef	ISO_X25ESIS
11036379Ssklower 	clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input;
11136379Ssklower #endif	ISO_X25ESIS
11236379Ssklower }
11336379Ssklower 
11436379Ssklower /*
11536379Ssklower  * FUNCTION:		esis_usrreq
11636379Ssklower  *
11736379Ssklower  * PURPOSE:			Handle user level esis requests
11836379Ssklower  *
11936379Ssklower  * RETURNS:			0 or appropriate errno
12036379Ssklower  *
12136379Ssklower  * SIDE EFFECTS:
12236379Ssklower  *
12336379Ssklower  * NOTES:			This is here only so esis gets initialized.
12436379Ssklower  */
125*37469Ssklower /*ARGSUSED*/
12636379Ssklower esis_usrreq(so, req, m, nam, rights)
12736379Ssklower struct socket	*so;		/* socket: used only to get to this code */
12836379Ssklower int				req;		/* request */
12936379Ssklower struct mbuf		*m;			/* data for request */
13036379Ssklower struct mbuf		*nam;		/* optional name */
13136379Ssklower struct mbuf		*rights;	/* optional rights */
13236379Ssklower {
13336379Ssklower 	if (m != NULL)
13436379Ssklower 		m_freem(m);
13536379Ssklower 
13636379Ssklower 	return(EOPNOTSUPP);
13736379Ssklower }
13836379Ssklower 
13936379Ssklower /*
14036379Ssklower  * FUNCTION:		esis_input
14136379Ssklower  *
14236379Ssklower  * PURPOSE:			Process an incoming esis packet
14336379Ssklower  *
14436379Ssklower  * RETURNS:			nothing
14536379Ssklower  *
14636379Ssklower  * SIDE EFFECTS:
14736379Ssklower  *
14836379Ssklower  * NOTES:
14936379Ssklower  */
15036379Ssklower esis_input(m0, shp)
15136379Ssklower struct mbuf		*m0;		/* ptr to first mbuf of pkt */
15236379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
15336379Ssklower {
15436379Ssklower 	struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
155*37469Ssklower 	register int type;
15636379Ssklower 
15736379Ssklower 	IFDEBUG(D_ESISINPUT)
15836379Ssklower 		int i;
15936379Ssklower 
16036379Ssklower 		printf("esis_input: pdu on ifp x%x (%s%d): from:", shp->snh_ifp,
16136379Ssklower 			shp->snh_ifp->if_name, shp->snh_ifp->if_unit);
16236379Ssklower 		for (i=0; i<6; i++)
16336379Ssklower 			printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' ');
16436379Ssklower 		printf(" to:");
16536379Ssklower 		for (i=0; i<6; i++)
16636379Ssklower 			printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' ');
16736379Ssklower 		printf("\n");
16836379Ssklower 	ENDDEBUG
16936379Ssklower 
17036379Ssklower 	/*
17136379Ssklower 	 *	check checksum if necessary
17236379Ssklower 	 */
173*37469Ssklower 	if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) {
17436379Ssklower 		esis_stat.es_badcsum++;
17536379Ssklower 		goto bad;
17636379Ssklower 	}
17736379Ssklower 
17836379Ssklower 	/* check version */
17936379Ssklower 	if (pdu->esis_vers != ESIS_VERSION) {
18036379Ssklower 		esis_stat.es_badvers++;
18136379Ssklower 		goto bad;
18236379Ssklower 	}
18336379Ssklower 
184*37469Ssklower 	type = pdu->esis_type & 0x1f;
185*37469Ssklower 	switch (type) {
18636379Ssklower 		case ESIS_ESH:
18736379Ssklower 			esis_eshinput(m0, shp);
18836379Ssklower 			return;
18936379Ssklower 
19036379Ssklower 		case ESIS_ISH:
19136379Ssklower 			esis_ishinput(m0, shp);
19236379Ssklower 			return;
19336379Ssklower 
19436379Ssklower 		case ESIS_RD:
19536379Ssklower 			esis_rdinput(m0, shp);
19636379Ssklower 			return;
19736379Ssklower 
19836379Ssklower 		default: {
19936379Ssklower 			esis_stat.es_badtype++;
20036379Ssklower 			goto bad;
20136379Ssklower 		}
20236379Ssklower 	}
20336379Ssklower 
20436379Ssklower bad:
20536379Ssklower 	m_freem(m0);
20636379Ssklower }
20736379Ssklower 
20836379Ssklower /*
20936379Ssklower  * FUNCTION:		esis_rdoutput
21036379Ssklower  *
21136379Ssklower  * PURPOSE:			Transmit a redirect pdu
21236379Ssklower  *
21336379Ssklower  * RETURNS:			nothing
21436379Ssklower  *
21536379Ssklower  * SIDE EFFECTS:
21636379Ssklower  *
21736379Ssklower  * NOTES:			Assumes there is enough space for fixed part of header,
21836379Ssklower  *					DA, BSNPA and NET in first mbuf.
21936379Ssklower  */
22036379Ssklower esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, nhop_sc)
22136379Ssklower struct snpa_hdr		*inbound_shp;	/* snpa hdr from incoming packet */
22236379Ssklower struct mbuf			*inbound_m;		/* incoming pkt itself */
22336379Ssklower struct clnp_optidx	*inbound_oidx;	/* clnp options assoc with incoming pkt */
22436379Ssklower struct iso_addr		*rd_dstnsap;	/* ultimate destination of pkt */
22536379Ssklower struct snpa_cache	*nhop_sc;		/* snpa cache info regarding next hop of
22636379Ssklower 										pkt */
22736379Ssklower {
22836379Ssklower 	struct mbuf			*m, *m0;
22936379Ssklower 	caddr_t				cp;
23036379Ssklower 	struct esis_fixed	*pdu;
23136379Ssklower 	int					len, total_len = 0;
23236379Ssklower 	struct sockaddr_iso	siso;
23336379Ssklower 	struct ifnet 		*ifp = inbound_shp->snh_ifp;
23436379Ssklower 
23536379Ssklower 	esis_stat.es_rdsent++;
23636379Ssklower 
23736379Ssklower 	IFDEBUG(D_ESISOUTPUT)
23836379Ssklower 		printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n",
23936379Ssklower 			ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m,
24036379Ssklower 			inbound_oidx);
24136379Ssklower 		printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap));
24236379Ssklower 		printf("\tredirected toward:%s\n", clnp_iso_addrp(&nhop_sc->sc_nsap));
24336379Ssklower 	ENDDEBUG
24436379Ssklower 
245*37469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
24636379Ssklower 		esis_stat.es_nomem++;
24736379Ssklower 		return;
24836379Ssklower 	}
249*37469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
25036379Ssklower 
25136379Ssklower 	pdu = mtod(m, struct esis_fixed *);
252*37469Ssklower 	cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */
25336379Ssklower 	len = sizeof(struct esis_fixed);
25436379Ssklower 
25536379Ssklower 	/*
25636379Ssklower 	 *	Build fixed part of header
25736379Ssklower 	 */
25836379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
25936379Ssklower 	pdu->esis_vers = ESIS_VERSION;
26036379Ssklower 	pdu->esis_type = ESIS_RD;
26136379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time);
26236379Ssklower 
26336379Ssklower 	/* Insert destination address */
264*37469Ssklower 	(void) esis_insert_addr(&cp, &len, rd_dstnsap, m);
26536379Ssklower 
26636379Ssklower 	/* Insert the snpa of better next hop */
26736379Ssklower 	*cp++ = nhop_sc->sc_len;
268*37469Ssklower 	bcopy((caddr_t)nhop_sc->sc_snpa, cp, nhop_sc->sc_len);
26936379Ssklower 	len += (nhop_sc->sc_len + 1);
27036379Ssklower 
27136379Ssklower 	/*
27236379Ssklower 	 *	If the next hop is not the destination, then it ought to be
27336379Ssklower 	 *	an IS and it should be inserted next. Else, set the
27436379Ssklower 	 *	NETL to 0
27536379Ssklower 	 */
27636379Ssklower 	/* PHASE2 use mask from ifp of outgoing interface */
27736379Ssklower 	if (!iso_addrmatch1(rd_dstnsap, &nhop_sc->sc_nsap)) {
27836379Ssklower 		if ((nhop_sc->sc_flags & SNPA_IS) == 0) {
27936379Ssklower 			/* this should not happen */
28036379Ssklower 			printf("esis_rdoutput: next hop is not dst and not an IS\n");
28136379Ssklower 			m_freem(m0);
28236379Ssklower 			return;
28336379Ssklower 		}
284*37469Ssklower 		(void) esis_insert_addr(&cp, &len, &nhop_sc->sc_nsap, m);
28536379Ssklower 	} else {
28636379Ssklower 		*cp++ = 0;	/* NETL */
28736379Ssklower 		len++;
28836379Ssklower 	}
289*37469Ssklower 	m->m_len = len;
29036379Ssklower 
29136379Ssklower 	/*
29236379Ssklower 	 *	PHASE2
29336379Ssklower 	 *	If redirect is to an IS, add an address mask. The mask to be
29436379Ssklower 	 *	used should be the mask present in the routing entry used to
29536379Ssklower 	 *	forward the original data packet.
29636379Ssklower 	 */
29736379Ssklower 
29836379Ssklower 	/*
29936379Ssklower 	 *	Copy Qos, priority, or security options present in original npdu
30036379Ssklower 	 */
30136379Ssklower 	if (inbound_oidx) {
30236379Ssklower 		/* THIS CODE IS CURRENTLY UNTESTED */
30336379Ssklower 		int optlen = 0;
30436379Ssklower 		if (inbound_oidx->cni_qos_formatp)
30536379Ssklower 			optlen += (inbound_oidx->cni_qos_len + 2);
30636379Ssklower 		if (inbound_oidx->cni_priorp)	/* priority option is 1 byte long */
30736379Ssklower 			optlen += 3;
30836379Ssklower 		if (inbound_oidx->cni_securep)
30936379Ssklower 			optlen += (inbound_oidx->cni_secure_len + 2);
310*37469Ssklower 		if (M_TRAILINGSPACE(m) < optlen) {
311*37469Ssklower 			EXTEND_PACKET(m, m0, cp);
312*37469Ssklower 			m->m_len = 0;
31336379Ssklower 			/* assumes MLEN > optlen */
31436379Ssklower 		}
31536379Ssklower 		/* assume MLEN-len > optlen */
31636379Ssklower 		/*
31736379Ssklower 		 *	When copying options, copy from ptr - 2 in order to grab
31836379Ssklower 		 *	the option code and length
31936379Ssklower 		 */
32036379Ssklower 		if (inbound_oidx->cni_qos_formatp) {
321*37469Ssklower 			bcopy((caddr_t)(inbound_m + inbound_oidx->cni_qos_formatp - 2), cp,
322*37469Ssklower 				(unsigned)(inbound_oidx->cni_qos_len + 2));
32336379Ssklower 			len += inbound_oidx->cni_qos_len + 2;
32436379Ssklower 		}
32536379Ssklower 		if (inbound_oidx->cni_priorp) {
326*37469Ssklower 			bcopy((caddr_t)(inbound_m + inbound_oidx->cni_priorp - 2), cp, 3);
32736379Ssklower 			len += 3;
32836379Ssklower 		}
32936379Ssklower 		if (inbound_oidx->cni_securep) {
330*37469Ssklower 			bcopy((caddr_t)(inbound_m + inbound_oidx->cni_securep - 2), cp,
331*37469Ssklower 				(unsigned)(inbound_oidx->cni_secure_len + 2));
33236379Ssklower 			len += inbound_oidx->cni_secure_len + 2;
33336379Ssklower 		}
334*37469Ssklower 		m->m_len += optlen;
33536379Ssklower 	}
33636379Ssklower 
337*37469Ssklower 	pdu->esis_hdr_len = m0->m_pkthdr.len = len;
33836379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
33936379Ssklower 
340*37469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
341*37469Ssklower 	siso.siso_len = 12;
34236379Ssklower 	siso.siso_family = AF_ISO;
343*37469Ssklower 	siso.siso_data[0] = AFI_SNA;
344*37469Ssklower 	siso.siso_nlen = 6 + 1;	/* should be taken from snpa_hdr */
34536379Ssklower 										/* +1 is for AFI */
346*37469Ssklower 	bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6);
34736379Ssklower 	(ifp->if_output)(ifp, m0, &siso);
34836379Ssklower }
34936379Ssklower 
35036379Ssklower /*
35136379Ssklower  * FUNCTION:		esis_insert_addr
35236379Ssklower  *
35336379Ssklower  * PURPOSE:			Insert an iso_addr into a buffer
35436379Ssklower  *
35536379Ssklower  * RETURNS:			true if buffer was big enough, else false
35636379Ssklower  *
35736379Ssklower  * SIDE EFFECTS:	Increment buf & len according to size of iso_addr
35836379Ssklower  *
35936379Ssklower  * NOTES:			Plus 1 here is for length byte
36036379Ssklower  */
361*37469Ssklower esis_insert_addr(buf, len, isoa, m)
36236379Ssklower caddr_t			*buf;		/* ptr to buffer to put address into */
36336379Ssklower int				*len;		/* ptr to length of buffer so far */
36436379Ssklower struct iso_addr	*isoa;		/* ptr to address */
365*37469Ssklower register struct mbuf	*m;	/* determine if there remains space */
36636379Ssklower {
367*37469Ssklower 	register int newlen = isoa->isoa_len + 1;
36836379Ssklower 
369*37469Ssklower 	if (newlen > M_TRAILINGSPACE(m))
37036379Ssklower 		return(0);
371*37469Ssklower 	bcopy((caddr_t)isoa, *buf, newlen);
372*37469Ssklower 	*len += newlen;
373*37469Ssklower 	*buf += newlen;
374*37469Ssklower 	m->m_len += newlen;
37536379Ssklower 	return(1);
37636379Ssklower }
37736379Ssklower 
37836379Ssklower /*
37936379Ssklower 
38036379Ssklower /*
38136379Ssklower  * FUNCTION:		esis_eshinput
38236379Ssklower  *
38336379Ssklower  * PURPOSE:			Process an incoming ESH pdu
38436379Ssklower  *
38536379Ssklower  * RETURNS:			nothing
38636379Ssklower  *
38736379Ssklower  * SIDE EFFECTS:
38836379Ssklower  *
38936379Ssklower  * NOTES:
39036379Ssklower  */
39136379Ssklower esis_eshinput(m, shp)
39236379Ssklower struct mbuf		*m;	/* esh pdu */
39336379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
39436379Ssklower {
39536379Ssklower 	struct esis_fixed	*pdu = mtod(m, struct esis_fixed *);
39636379Ssklower 	u_short				ht;		/* holding time */
397*37469Ssklower 	struct iso_addr		*nsap;
398*37469Ssklower 	int					naddr = 0;
399*37469Ssklower 	u_char				*buf = (u_char *)(pdu + 1);
40036379Ssklower 	int					len = pdu->esis_hdr_len - sizeof(struct esis_fixed);
401*37469Ssklower 	int					optlen, new_entry;
40236379Ssklower 
40336379Ssklower 	esis_stat.es_eshrcvd++;
40436379Ssklower 
40536379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
40636379Ssklower 
40736379Ssklower 	if (len > 0) {
40836379Ssklower 		naddr = *buf++;
40936379Ssklower 		len--;
41036379Ssklower 	} else
41136379Ssklower 		goto bad;
41236379Ssklower 
41336379Ssklower 	IFDEBUG(D_ESISINPUT)
41436379Ssklower 		printf("esis_eshinput: esh: ht %d, naddr %d\n", ht, naddr);
41536379Ssklower 	ENDDEBUG
41636379Ssklower 
41736379Ssklower 	while (naddr-- > 0) {
418*37469Ssklower 		nsap = (struct iso_addr *)buf;
419*37469Ssklower 		if ((len -=  (optlen = *buf++)) >= 0) {
420*37469Ssklower 			buf += optlen;
421*37469Ssklower 			new_entry = (snpac_look(nsap) == NULL);
42236379Ssklower 
42336379Ssklower 			IFDEBUG(D_ESISINPUT)
42436379Ssklower 				printf("esis_eshinput: nsap %s is %s\n",
425*37469Ssklower 					clnp_iso_addrp(nsap), new_entry ? "new" : "old");
42636379Ssklower 			ENDDEBUG
42736379Ssklower 
428*37469Ssklower 			snpac_add(shp->snh_ifp, nsap, shp->snh_shost, 6, SNPA_ES, ht);
42936379Ssklower 			if (new_entry)
43036379Ssklower 				esis_shoutput(shp->snh_ifp,
43136379Ssklower 					iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
43236379Ssklower 					esis_holding_time, shp->snh_shost, 6);
43336379Ssklower 		} else {
434*37469Ssklower bad:
43536379Ssklower 			esis_stat.es_toosmall++;
43636379Ssklower 			break;
43736379Ssklower 		}
43836379Ssklower 	}
43936379Ssklower 
44036379Ssklower 	m_freem(m);
44136379Ssklower }
44236379Ssklower 
44336379Ssklower /*
44436379Ssklower  * FUNCTION:		esis_ishinput
44536379Ssklower  *
44636379Ssklower  * PURPOSE:			process an incoming ISH pdu
44736379Ssklower  *
44836379Ssklower  * RETURNS:
44936379Ssklower  *
45036379Ssklower  * SIDE EFFECTS:
45136379Ssklower  *
45236379Ssklower  * NOTES:
45336379Ssklower  */
45436379Ssklower esis_ishinput(m, shp)
45536379Ssklower struct mbuf		*m;	/* esh pdu */
45636379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
45736379Ssklower {
45836379Ssklower 	struct esis_fixed	*pdu = mtod(m, struct esis_fixed *);
45936379Ssklower 	u_short				ht;		/* holding time */
460*37469Ssklower 	struct iso_addr		*nsap;
46136379Ssklower 	caddr_t				buf = (caddr_t)pdu + sizeof(struct esis_fixed);
46236379Ssklower 	int					len = pdu->esis_hdr_len - sizeof(struct esis_fixed);
463*37469Ssklower 	int					optlen, new_entry;
46436379Ssklower 
46536379Ssklower 	esis_stat.es_ishrcvd++;
46636379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
46736379Ssklower 
46836379Ssklower 	IFDEBUG(D_ESISINPUT)
46936379Ssklower 		printf("esis_ishinput: ish: ht %d\n", ht);
47036379Ssklower 	ENDDEBUG
47136379Ssklower 
472*37469Ssklower 	nsap = (struct iso_addr *)buf;
473*37469Ssklower 	if ((len -=  (optlen = *buf++)) < 0)
474*37469Ssklower 		goto bad;
475*37469Ssklower 	buf += optlen;
47636379Ssklower 
477*37469Ssklower 	/* process options */
478*37469Ssklower 	while (len > 0) {
479*37469Ssklower 		switch (*buf++) {
480*37469Ssklower 		case ESISOVAL_ESCT:
481*37469Ssklower 			if (*buf != 2)
482*37469Ssklower 				goto bad;
483*37469Ssklower 			CTOH(buf[0], buf[1], esis_config_time);
484*37469Ssklower 		}
485*37469Ssklower 		if ((len -=  (optlen = *buf)) < 0) {
486*37469Ssklower 	bad:
487*37469Ssklower 			esis_stat.es_toosmall++;
488*37469Ssklower 			m_freem(m);
489*37469Ssklower 			return;
490*37469Ssklower 		}
491*37469Ssklower 		buf += 1 + optlen;
492*37469Ssklower 	}
493*37469Ssklower 	new_entry = (snpac_look(nsap) == NULL);
49436379Ssklower 
495*37469Ssklower 	IFDEBUG(D_ESISINPUT)
496*37469Ssklower 		printf("esis_ishinput: nsap %s is %s\n",
497*37469Ssklower 			clnp_iso_addrp(nsap), new_entry ? "new" : "old");
498*37469Ssklower 	ENDDEBUG
499*37469Ssklower 
500*37469Ssklower 	snpac_add(shp->snh_ifp, nsap, shp->snh_shost, 6, SNPA_IS, ht);
501*37469Ssklower 	if (new_entry)
502*37469Ssklower 		esis_shoutput(shp->snh_ifp,
503*37469Ssklower 			iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
504*37469Ssklower 			esis_holding_time, shp->snh_shost, 6);
50536379Ssklower 	m_freem(m);
50636379Ssklower }
50736379Ssklower 
50836379Ssklower /*
50936379Ssklower  * FUNCTION:		esis_rdinput
51036379Ssklower  *
51136379Ssklower  * PURPOSE:			Process an incoming RD pdu
51236379Ssklower  *
51336379Ssklower  * RETURNS:
51436379Ssklower  *
51536379Ssklower  * SIDE EFFECTS:
51636379Ssklower  *
51736379Ssklower  * NOTES:
51836379Ssklower  */
51936379Ssklower esis_rdinput(m0, shp)
52036379Ssklower struct mbuf		*m0;	/* esh pdu */
52136379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
52236379Ssklower {
52336379Ssklower 	struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
52436379Ssklower 	u_short				ht;		/* holding time */
525*37469Ssklower 	register struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0;
526*37469Ssklower 	u_char				*buf = (u_char *)(pdu + 1);
527*37469Ssklower 	int					len = pdu->esis_hdr_len - sizeof(struct esis_fixed);
528*37469Ssklower 	int					optlen, bsnpalen;
52936379Ssklower 	caddr_t				bsnpa;
53036379Ssklower 
53136379Ssklower 	esis_stat.es_rdrcvd++;
53236379Ssklower 
53336379Ssklower 	/* intermediate systems ignore redirects */
53436379Ssklower 	if (iso_systype & SNPA_IS)
53536379Ssklower 		goto bad;
53636379Ssklower 
53736379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
538*37469Ssklower 	if (len <= 0)
539*37469Ssklower 		goto bad;
54036379Ssklower 
54136379Ssklower 	/* Extract DA */
542*37469Ssklower 	da = (struct iso_addr *)buf;
543*37469Ssklower 	if ((len -=  (optlen = *buf++)) <= 0)
54436379Ssklower 		goto bad;
545*37469Ssklower 	buf += optlen;
546*37469Ssklower 
54736379Ssklower 	/* Extract better snpa */
548*37469Ssklower 	if ((len -=  (bsnpalen = *buf++)) < 0)
54936379Ssklower 		goto bad;
550*37469Ssklower 	bsnpa = (caddr_t)buf;
551*37469Ssklower 	buf += optlen;
552*37469Ssklower 
553*37469Ssklower 	/* Extract NET if present */
554*37469Ssklower 	if (len) {
555*37469Ssklower 		net = (struct iso_addr *)buf;
556*37469Ssklower 		if ((len -=  (optlen = *buf++)) < 0)
557*37469Ssklower 			goto bad;
558*37469Ssklower 		buf += optlen;
55936379Ssklower 	}
56036379Ssklower 
561*37469Ssklower 	/* process options */
562*37469Ssklower 	while (len > 0) {
563*37469Ssklower 		switch (*buf++) {
564*37469Ssklower 		case ESISOVAL_SNPAMASK:
565*37469Ssklower 			if (snpamask) /* duplicate */
566*37469Ssklower 				goto bad;
567*37469Ssklower 			snpamask = (struct iso_addr *)buf;
568*37469Ssklower 			break;
569*37469Ssklower 
570*37469Ssklower 		case ESISOVAL_NETMASK:
571*37469Ssklower 			if (netmask) /* duplicate */
572*37469Ssklower 				goto bad;
573*37469Ssklower 			netmask = (struct iso_addr *)buf;
574*37469Ssklower 		}
575*37469Ssklower 		if ((len -=  (optlen = *buf)) < 0)
57636379Ssklower 			goto bad;
577*37469Ssklower 		buf += 1 + optlen;
57836379Ssklower 	}
57936379Ssklower 
58036379Ssklower 	IFDEBUG(D_ESISINPUT)
581*37469Ssklower 		printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da));
582*37469Ssklower 		if (net)
583*37469Ssklower 			printf("\t: net %s\n", clnp_iso_addrp(net));
58436379Ssklower 	ENDDEBUG
58536379Ssklower 	/*
58636379Ssklower 	 *	If netl is zero, then redirect is to an ES. We need to add an entry
58736379Ssklower 	 *	to the snpa cache for (destination, better snpa).
58836379Ssklower 	 *	If netl is not zero, then the redirect is to an IS. In this
58936379Ssklower 	 *	case, add an snpa cache entry for (net, better snpa).
59036379Ssklower 	 *
59136379Ssklower 	 *	If the redirect is to an IS, add a route entry towards that
59236379Ssklower 	 *	IS.
59336379Ssklower 	 */
594*37469Ssklower 	if ((net == 0) || (snpamask)) {
59536379Ssklower 		/* redirect to an ES */
596*37469Ssklower 		snpac_add(shp->snh_ifp, da, bsnpa, bsnpalen, SNPA_ES, ht);
59736379Ssklower 	} else {
598*37469Ssklower 		struct iso_addr bsnpa_ia;
599*37469Ssklower 
600*37469Ssklower 		snpac_add(shp->snh_ifp, net, bsnpa, bsnpalen, SNPA_IS, ht);
601*37469Ssklower 		bcopy(bsnpa, bsnpa_ia.isoa_genaddr, bsnpa_ia.isoa_len = 1 + bsnpalen);
602*37469Ssklower 		bsnpa_ia.isoa_genaddr[0] = AFI_SNA;
603*37469Ssklower 		snpac_addrt(da, &bsnpa_ia, net, netmask);
60436379Ssklower 	}
60536379Ssklower bad:
60636379Ssklower 	m_freem(m0);
60736379Ssklower }
60836379Ssklower 
60936379Ssklower /*
61036379Ssklower  * FUNCTION:		esis_config
61136379Ssklower  *
61236379Ssklower  * PURPOSE:			Report configuration
61336379Ssklower  *
61436379Ssklower  * RETURNS:
61536379Ssklower  *
61636379Ssklower  * SIDE EFFECTS:
61736379Ssklower  *
61836379Ssklower  * NOTES:			Called every esis_config_time seconds
61936379Ssklower  */
62036379Ssklower esis_config()
62136379Ssklower {
62236379Ssklower 	register struct ifnet	*ifp;
62336379Ssklower 
62436379Ssklower 	timeout(esis_config, (caddr_t)0, hz * esis_config_time);
62536379Ssklower 
62636379Ssklower 	/*
62736379Ssklower 	 *	Report configuration for each interface that
62836379Ssklower 	 *	- is UP
62936379Ssklower 	 *	- is not loopback
63036379Ssklower 	 *	- has broadcast capabilities
63136379Ssklower 	 *	- has an ISO address
63236379Ssklower 	 */
63336379Ssklower 
63436379Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
63536379Ssklower 		if ((ifp->if_flags & IFF_UP) &&
63636379Ssklower 			(ifp->if_flags & IFF_BROADCAST) &&
63736379Ssklower 			((ifp->if_flags & IFF_LOOPBACK) == 0)) {
63836379Ssklower 			/* search for an ISO address family */
63936379Ssklower 			struct ifaddr	*ia;
64036379Ssklower 
64136379Ssklower 			for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {
642*37469Ssklower 				if (ia->ifa_addr->sa_family == AF_ISO) {
64336379Ssklower 					esis_shoutput(ifp,
64436379Ssklower 						iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
64536379Ssklower 						esis_holding_time,
646*37469Ssklower 						(caddr_t)(iso_systype & SNPA_ES ? all_is.sc_snpa :
647*37469Ssklower 						all_es.sc_snpa), 6);
64836379Ssklower 					break;
64936379Ssklower 				}
65036379Ssklower 			}
65136379Ssklower 		}
65236379Ssklower 	}
65336379Ssklower }
65436379Ssklower 
65536379Ssklower /*
65636379Ssklower  * FUNCTION:		esis_shoutput
65736379Ssklower  *
65836379Ssklower  * PURPOSE:			Transmit an esh or ish pdu
65936379Ssklower  *
66036379Ssklower  * RETURNS:			nothing
66136379Ssklower  *
66236379Ssklower  * SIDE EFFECTS:
66336379Ssklower  *
66436379Ssklower  * NOTES:
66536379Ssklower  */
66636379Ssklower esis_shoutput(ifp, type, ht, sn_addr, sn_len)
66736379Ssklower struct ifnet	*ifp;
66836379Ssklower int				type;
66936379Ssklower short			ht;
67036379Ssklower caddr_t 		sn_addr;
67136379Ssklower int				sn_len;
67236379Ssklower {
67336379Ssklower 	struct mbuf			*m, *m0;
67436379Ssklower 	caddr_t				cp, naddrp;
67536379Ssklower 	int					naddr = 0;
67636379Ssklower 	struct esis_fixed	*pdu;
67736379Ssklower 	struct ifaddr		*ifa;
678*37469Ssklower 	int					len;
67936379Ssklower 	struct sockaddr_iso	siso;
68036379Ssklower 
68136379Ssklower 	if (type == ESIS_ESH)
68236379Ssklower 		esis_stat.es_eshsent++;
68336379Ssklower 	else if (type == ESIS_ISH)
68436379Ssklower 		esis_stat.es_ishsent++;
68536379Ssklower 	else {
68636379Ssklower 		printf("esis_shoutput: bad pdu type\n");
68736379Ssklower 		return;
68836379Ssklower 	}
68936379Ssklower 
69036379Ssklower 	IFDEBUG(D_ESISOUTPUT)
69136379Ssklower 		int	i;
69236379Ssklower 		printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ",
69336379Ssklower 			ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish",
69436379Ssklower 			ht, sn_len);
69536379Ssklower 		for (i=0; i<sn_len; i++)
69636379Ssklower 			printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' ');
69736379Ssklower 		printf("\n");
69836379Ssklower 	ENDDEBUG
69936379Ssklower 
700*37469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
70136379Ssklower 		esis_stat.es_nomem++;
70236379Ssklower 		return;
70336379Ssklower 	}
704*37469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
70536379Ssklower 
70636379Ssklower 	pdu = mtod(m, struct esis_fixed *);
707*37469Ssklower 	naddrp = cp = (caddr_t)(pdu + 1);
70836379Ssklower 	len = sizeof(struct esis_fixed);
70936379Ssklower 
71036379Ssklower 	/*
71136379Ssklower 	 *	Build fixed part of header
71236379Ssklower 	 */
71336379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
71436379Ssklower 	pdu->esis_vers = ESIS_VERSION;
71536379Ssklower 	pdu->esis_type = type;
71636379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
71736379Ssklower 
71836379Ssklower 	if (type == ESIS_ESH) {
71936379Ssklower 		cp++;
72036379Ssklower 		len++;
72136379Ssklower 	}
72236379Ssklower 
723*37469Ssklower 	m->m_len = len;
72436379Ssklower 	for (ifa = ifp->if_addrlist; ifa; ifa=ifa->ifa_next) {
725*37469Ssklower 		if (ifa->ifa_addr->sa_family == AF_ISO) {
72636379Ssklower 			IFDEBUG(D_ESISOUTPUT)
72736379Ssklower 				printf("esis_shoutput: adding nsap %s\n",
72836379Ssklower 					clnp_iso_addrp(&IA_SIS(ifa)->siso_addr));
72936379Ssklower 			ENDDEBUG
730*37469Ssklower 			if (!esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr, m)) {
731*37469Ssklower 				EXTEND_PACKET(m, m0, cp);
732*37469Ssklower 				(void) esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr, m);
73336379Ssklower 			}
73436379Ssklower 			naddr++;
73536379Ssklower 			if (type == ESIS_ISH)
73636379Ssklower 				break;
73736379Ssklower 		}
73836379Ssklower 	}
73936379Ssklower 
74036379Ssklower 	if (type == ESIS_ESH)
74136379Ssklower 		*naddrp = naddr;
74236379Ssklower 
743*37469Ssklower 	m0->m_pkthdr.len = len;
744*37469Ssklower 	pdu->esis_hdr_len = len;
74536379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
74636379Ssklower 
747*37469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
74836379Ssklower 	siso.siso_family = AF_ISO;
749*37469Ssklower 	siso.siso_data[0] = AFI_SNA;
750*37469Ssklower 	siso.siso_nlen = sn_len + 1;
751*37469Ssklower 	siso.siso_len  = sn_len + 6;
752*37469Ssklower 	bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len);
75336379Ssklower 	(ifp->if_output)(ifp, m0, &siso);
75436379Ssklower }
75536379Ssklower 
75636379Ssklower /*
75736379Ssklower  * FUNCTION:		esis_ctlinput
75836379Ssklower  *
75936379Ssklower  * PURPOSE:			Handle the PRC_IFDOWN transition
76036379Ssklower  *
76136379Ssklower  * RETURNS:			nothing
76236379Ssklower  *
76336379Ssklower  * SIDE EFFECTS:
76436379Ssklower  *
76536379Ssklower  * NOTES:			Calls snpac_flush for interface specified.
76636379Ssklower  *					The loop through iso_ifaddr is stupid because
76736379Ssklower  *					back in if_down, we knew the ifp...
76836379Ssklower  */
76936379Ssklower esis_ctlinput(req, siso)
77036379Ssklower int						req;		/* request: we handle only PRC_IFDOWN */
77136379Ssklower struct sockaddr_iso		*siso;		/* address of ifp */
77236379Ssklower {
77336379Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
77436379Ssklower 
775*37469Ssklower 	if (req == PRC_IFDOWN)
776*37469Ssklower 		for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
777*37469Ssklower 			if (iso_addrmatch(IA_SIS(ia), siso))
778*37469Ssklower 				snpac_flushifp(ia->ia_ifp);
779*37469Ssklower 		}
78036379Ssklower }
78136379Ssklower 
78236379Ssklower #endif	ISO
783