xref: /csrg-svn/sys/netiso/esis.c (revision 49268)
1*49268Sbostic /*-
2*49268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
3*49268Sbostic  * All rights reserved.
4*49268Sbostic  *
5*49268Sbostic  * %sccs.include.redist.c%
6*49268Sbostic  *
7*49268Sbostic  *	@(#)esis.c	7.18 (Berkeley) 05/06/91
8*49268Sbostic  */
9*49268Sbostic 
1036379Ssklower /***********************************************************
1136379Ssklower 		Copyright IBM Corporation 1987
1236379Ssklower 
1336379Ssklower                       All Rights Reserved
1436379Ssklower 
1536379Ssklower Permission to use, copy, modify, and distribute this software and its
1636379Ssklower documentation for any purpose and without fee is hereby granted,
1736379Ssklower provided that the above copyright notice appear in all copies and that
1836379Ssklower both that copyright notice and this permission notice appear in
1936379Ssklower supporting documentation, and that the name of IBM not be
2036379Ssklower used in advertising or publicity pertaining to distribution of the
2136379Ssklower software without specific, written prior permission.
2236379Ssklower 
2336379Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436379Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536379Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636379Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736379Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836379Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936379Ssklower SOFTWARE.
3036379Ssklower 
3136379Ssklower ******************************************************************/
3236379Ssklower 
3336379Ssklower /*
3436379Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536379Ssklower  */
3636379Ssklower 
3736379Ssklower #ifdef ISO
3836379Ssklower 
3937469Ssklower #include "types.h"
4037469Ssklower #include "param.h"
4143451Smckusick #include "systm.h"
4237469Ssklower #include "mbuf.h"
4337469Ssklower #include "domain.h"
4437469Ssklower #include "protosw.h"
4537469Ssklower #include "user.h"
4637469Ssklower #include "socket.h"
4737469Ssklower #include "socketvar.h"
4837469Ssklower #include "errno.h"
4937469Ssklower #include "kernel.h"
5036379Ssklower 
5136379Ssklower #include "../net/if.h"
5243332Ssklower #include "../net/if_dl.h"
5336379Ssklower #include "../net/route.h"
5443421Ssklower #include "../net/raw_cb.h"
5536379Ssklower 
5637469Ssklower #include "iso.h"
5737469Ssklower #include "iso_pcb.h"
5837469Ssklower #include "iso_var.h"
5937469Ssklower #include "iso_snpac.h"
6037469Ssklower #include "clnl.h"
6137469Ssklower #include "clnp.h"
6237469Ssklower #include "clnp_stat.h"
6338841Ssklower #include "esis.h"
6437469Ssklower #include "argo_debug.h"
6536379Ssklower 
6636379Ssklower /*
6736379Ssklower  *	Global variables to esis implementation
6836379Ssklower  *
6936379Ssklower  *	esis_holding_time - the holding time (sec) parameter for outgoing pdus
7036379Ssklower  *	esis_config_time  - the frequency (sec) that hellos are generated
7143421Ssklower  *	esis_esconfig_time - suggested es configuration time placed in the
7243421Ssklower  *						ish.
7336379Ssklower  *
7436379Ssklower  */
7543421Ssklower struct rawcb	esis_pcb;
7636379Ssklower int				esis_sendspace = 2048;
7736379Ssklower int				esis_recvspace = 2048;
7836379Ssklower short			esis_holding_time = ESIS_HT;
7936379Ssklower short			esis_config_time = ESIS_CONFIG;
8043421Ssklower short			esis_esconfig_time = ESIS_CONFIG;
8136379Ssklower extern int		iso_systype;
8243421Ssklower struct sockaddr_dl	esis_dl = { sizeof(esis_dl), AF_LINK };
8343332Ssklower extern char		all_es_snpa[], all_is_snpa[];
8436379Ssklower 
8537469Ssklower #define EXTEND_PACKET(m, mhdr, cp)\
8636379Ssklower 	if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\
8736379Ssklower 		esis_stat.es_nomem++;\
8836379Ssklower 		m_freem(mhdr);\
8936379Ssklower 		return;\
9036379Ssklower 	} else {\
9136379Ssklower 		(m) = (m)->m_next;\
9236379Ssklower 		(cp) = mtod((m), caddr_t);\
9336379Ssklower 	}
9436379Ssklower /*
9536379Ssklower  * FUNCTION:		esis_init
9636379Ssklower  *
9736379Ssklower  * PURPOSE:			Initialize the kernel portion of esis protocol
9836379Ssklower  *
9936379Ssklower  * RETURNS:			nothing
10036379Ssklower  *
10136379Ssklower  * SIDE EFFECTS:
10236379Ssklower  *
10336379Ssklower  * NOTES:
10436379Ssklower  */
10536379Ssklower esis_init()
10636379Ssklower {
10736379Ssklower 	extern struct clnl_protosw clnl_protox[256];
10843892Ssklower 	int	esis_input(), isis_input();
10943892Ssklower 	int	esis_config(), snpac_age();
11036379Ssklower #ifdef	ISO_X25ESIS
11143892Ssklower 	int	x25esis_input();
11236379Ssklower #endif	ISO_X25ESIS
11336379Ssklower 
11443421Ssklower 	esis_pcb.rcb_next = esis_pcb.rcb_prev = &esis_pcb;
11543421Ssklower 	llinfo_llc.lc_next = llinfo_llc.lc_prev = &llinfo_llc;
11636379Ssklower 
11736379Ssklower 	timeout(snpac_age, (caddr_t)0, hz);
11836379Ssklower 	timeout(esis_config, (caddr_t)0, hz);
11936379Ssklower 
12043892Ssklower 	clnl_protox[ISO9542_ESIS].clnl_input = esis_input;
12143892Ssklower 	clnl_protox[ISO10589_ISIS].clnl_input = isis_input;
12236379Ssklower #ifdef	ISO_X25ESIS
12336379Ssklower 	clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input;
12436379Ssklower #endif	ISO_X25ESIS
12536379Ssklower }
12636379Ssklower 
12736379Ssklower /*
12836379Ssklower  * FUNCTION:		esis_usrreq
12936379Ssklower  *
13036379Ssklower  * PURPOSE:			Handle user level esis requests
13136379Ssklower  *
13236379Ssklower  * RETURNS:			0 or appropriate errno
13336379Ssklower  *
13436379Ssklower  * SIDE EFFECTS:
13536379Ssklower  *
13636379Ssklower  */
13737469Ssklower /*ARGSUSED*/
13840775Ssklower esis_usrreq(so, req, m, nam, control)
13936379Ssklower struct socket	*so;		/* socket: used only to get to this code */
14036379Ssklower int				req;		/* request */
14136379Ssklower struct mbuf		*m;			/* data for request */
14236379Ssklower struct mbuf		*nam;		/* optional name */
14340775Ssklower struct mbuf		*control;	/* optional control */
14436379Ssklower {
14543421Ssklower 	struct rawcb *rp = sotorawcb(so);
14643421Ssklower 	int error = 0;
14743421Ssklower 
14843421Ssklower 	if (suser(u.u_cred, &u.u_acflag)) {
14943421Ssklower 		error = EACCES;
15043421Ssklower 		goto release;
15143421Ssklower 	}
15243421Ssklower 	if (rp == NULL && req != PRU_ATTACH) {
15343421Ssklower 		error = EINVAL;
15443421Ssklower 		goto release;
15543421Ssklower 	}
15643421Ssklower 
15743421Ssklower 	switch (req) {
15843421Ssklower 	case PRU_ATTACH:
15943421Ssklower 		if (rp != NULL) {
16043421Ssklower 			error = EINVAL;
16143421Ssklower 			break;
16243421Ssklower 		}
16343421Ssklower 		MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
16443421Ssklower 		if (so->so_pcb = (caddr_t)rp) {
16543421Ssklower 			bzero(so->so_pcb, sizeof(*rp));
16643421Ssklower 			insque(rp, &esis_pcb);
16744946Ssklower 			rp->rcb_socket = so;
16843421Ssklower 			error = soreserve(so, esis_sendspace, esis_recvspace);
16943421Ssklower 		} else
17043421Ssklower 			error = ENOBUFS;
17143421Ssklower 		break;
17243421Ssklower 
17343421Ssklower 	case PRU_SEND:
17443421Ssklower 		if (nam == NULL) {
17543421Ssklower 			error = EINVAL;
17643421Ssklower 			break;
17743421Ssklower 		}
17843421Ssklower 		/* error checking here */
17943421Ssklower 		error = isis_output(mtod(nam,struct sockaddr_dl *), m);
18043421Ssklower 		m = NULL;
18143421Ssklower 		break;
18243421Ssklower 
18343421Ssklower 	case PRU_DETACH:
18443421Ssklower 		raw_detach(rp);
18543421Ssklower 		break;
18643421Ssklower 
18743421Ssklower 	case PRU_SHUTDOWN:
18843421Ssklower 		socantsendmore(so);
18943421Ssklower 		break;
19043421Ssklower 
19143421Ssklower 	case PRU_ABORT:
19243421Ssklower 		soisdisconnected(so);
19343421Ssklower 		raw_detach(rp);
19443421Ssklower 		break;
19543421Ssklower 
19643421Ssklower 	case PRU_SENSE:
19743421Ssklower 		return (0);
19843421Ssklower 
19943421Ssklower 	default:
20043421Ssklower 		return (EOPNOTSUPP);
20143421Ssklower 	}
20243421Ssklower release:
20336379Ssklower 	if (m != NULL)
20436379Ssklower 		m_freem(m);
20536379Ssklower 
20643421Ssklower 	return (error);
20736379Ssklower }
20836379Ssklower 
20936379Ssklower /*
21036379Ssklower  * FUNCTION:		esis_input
21136379Ssklower  *
21236379Ssklower  * PURPOSE:			Process an incoming esis packet
21336379Ssklower  *
21436379Ssklower  * RETURNS:			nothing
21536379Ssklower  *
21636379Ssklower  * SIDE EFFECTS:
21736379Ssklower  *
21836379Ssklower  * NOTES:
21936379Ssklower  */
22036379Ssklower esis_input(m0, shp)
22136379Ssklower struct mbuf		*m0;		/* ptr to first mbuf of pkt */
22236379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
22336379Ssklower {
22443421Ssklower 	register struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
22537469Ssklower 	register int type;
22636379Ssklower 
22736379Ssklower 	/*
22836379Ssklower 	 *	check checksum if necessary
22936379Ssklower 	 */
23037469Ssklower 	if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) {
23136379Ssklower 		esis_stat.es_badcsum++;
23236379Ssklower 		goto bad;
23336379Ssklower 	}
23436379Ssklower 
23536379Ssklower 	/* check version */
23636379Ssklower 	if (pdu->esis_vers != ESIS_VERSION) {
23736379Ssklower 		esis_stat.es_badvers++;
23836379Ssklower 		goto bad;
23936379Ssklower 	}
24037469Ssklower 	type = pdu->esis_type & 0x1f;
24137469Ssklower 	switch (type) {
24236379Ssklower 		case ESIS_ESH:
24336379Ssklower 			esis_eshinput(m0, shp);
24443421Ssklower 			break;
24536379Ssklower 
24636379Ssklower 		case ESIS_ISH:
24736379Ssklower 			esis_ishinput(m0, shp);
24843421Ssklower 			break;
24936379Ssklower 
25036379Ssklower 		case ESIS_RD:
25136379Ssklower 			esis_rdinput(m0, shp);
25243421Ssklower 			break;
25336379Ssklower 
25443421Ssklower 		default:
25536379Ssklower 			esis_stat.es_badtype++;
25636379Ssklower 	}
25736379Ssklower 
25836379Ssklower bad:
25943421Ssklower 	if (esis_pcb.rcb_next != &esis_pcb)
26043421Ssklower 		isis_input(m0, shp);
26143421Ssklower 	else
26243421Ssklower 		m_freem(m0);
26336379Ssklower }
26436379Ssklower 
26536379Ssklower /*
26636379Ssklower  * FUNCTION:		esis_rdoutput
26736379Ssklower  *
26836379Ssklower  * PURPOSE:			Transmit a redirect pdu
26936379Ssklower  *
27036379Ssklower  * RETURNS:			nothing
27136379Ssklower  *
27236379Ssklower  * SIDE EFFECTS:
27336379Ssklower  *
27436379Ssklower  * NOTES:			Assumes there is enough space for fixed part of header,
27536379Ssklower  *					DA, BSNPA and NET in first mbuf.
27636379Ssklower  */
27743332Ssklower esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt)
27836379Ssklower struct snpa_hdr		*inbound_shp;	/* snpa hdr from incoming packet */
27936379Ssklower struct mbuf			*inbound_m;		/* incoming pkt itself */
28036379Ssklower struct clnp_optidx	*inbound_oidx;	/* clnp options assoc with incoming pkt */
28136379Ssklower struct iso_addr		*rd_dstnsap;	/* ultimate destination of pkt */
28243332Ssklower struct rtentry		*rt;			/* snpa cache info regarding next hop of
28336379Ssklower 										pkt */
28436379Ssklower {
28536379Ssklower 	struct mbuf			*m, *m0;
28636379Ssklower 	caddr_t				cp;
28736379Ssklower 	struct esis_fixed	*pdu;
28836379Ssklower 	int					len, total_len = 0;
28936379Ssklower 	struct sockaddr_iso	siso;
29036379Ssklower 	struct ifnet 		*ifp = inbound_shp->snh_ifp;
29143332Ssklower 	struct sockaddr_dl *sdl;
29243332Ssklower 	struct iso_addr *rd_gwnsap;
29336379Ssklower 
29443332Ssklower 	if (rt->rt_flags & RTF_GATEWAY) {
29543332Ssklower 		rd_gwnsap = &((struct sockaddr_iso *)rt->rt_gateway)->siso_addr;
29643332Ssklower 		rt = rtalloc1(rt->rt_gateway, 0);
29743332Ssklower 	} else
29843332Ssklower 		rd_gwnsap = &((struct sockaddr_iso *)rt_key(rt))->siso_addr;
29943332Ssklower 	if (rt == 0 || (sdl = (struct sockaddr_dl *)rt->rt_gateway) == 0 ||
30043332Ssklower 		sdl->sdl_family != AF_LINK) {
30143332Ssklower 		/* maybe we should have a function that you
30243332Ssklower 		   could put in the iso_ifaddr structure
30343332Ssklower 		   which could translate iso_addrs into snpa's
30443332Ssklower 		   where there is a known mapping for that address type */
30543332Ssklower 		esis_stat.es_badtype++;
30643332Ssklower 		return;
30743332Ssklower 	}
30836379Ssklower 	esis_stat.es_rdsent++;
30936379Ssklower 	IFDEBUG(D_ESISOUTPUT)
31036379Ssklower 		printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n",
31136379Ssklower 			ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m,
31236379Ssklower 			inbound_oidx);
31336379Ssklower 		printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap));
31443332Ssklower 		printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap));
31536379Ssklower 	ENDDEBUG
31636379Ssklower 
31737469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
31836379Ssklower 		esis_stat.es_nomem++;
31936379Ssklower 		return;
32036379Ssklower 	}
32137469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
32236379Ssklower 
32336379Ssklower 	pdu = mtod(m, struct esis_fixed *);
32437469Ssklower 	cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */
32536379Ssklower 	len = sizeof(struct esis_fixed);
32636379Ssklower 
32736379Ssklower 	/*
32836379Ssklower 	 *	Build fixed part of header
32936379Ssklower 	 */
33036379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
33136379Ssklower 	pdu->esis_vers = ESIS_VERSION;
33236379Ssklower 	pdu->esis_type = ESIS_RD;
33336379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time);
33436379Ssklower 
33536379Ssklower 	/* Insert destination address */
33643072Ssklower 	(void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0);
33736379Ssklower 
33836379Ssklower 	/* Insert the snpa of better next hop */
33943332Ssklower 	*cp++ = sdl->sdl_alen;
34043332Ssklower 	bcopy(LLADDR(sdl), cp, sdl->sdl_alen);
34143332Ssklower 	cp += sdl->sdl_alen;
34243332Ssklower 	len += (sdl->sdl_alen + 1);
34336379Ssklower 
34436379Ssklower 	/*
34536379Ssklower 	 *	If the next hop is not the destination, then it ought to be
34636379Ssklower 	 *	an IS and it should be inserted next. Else, set the
34736379Ssklower 	 *	NETL to 0
34836379Ssklower 	 */
34936379Ssklower 	/* PHASE2 use mask from ifp of outgoing interface */
35043332Ssklower 	if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) {
35143332Ssklower 		/* this should not happen:
35236379Ssklower 		if ((nhop_sc->sc_flags & SNPA_IS) == 0) {
35336379Ssklower 			printf("esis_rdoutput: next hop is not dst and not an IS\n");
35436379Ssklower 			m_freem(m0);
35536379Ssklower 			return;
35643332Ssklower 		} */
35743332Ssklower 		(void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0);
35836379Ssklower 	} else {
35936379Ssklower 		*cp++ = 0;	/* NETL */
36036379Ssklower 		len++;
36136379Ssklower 	}
36237469Ssklower 	m->m_len = len;
36336379Ssklower 
36436379Ssklower 	/*
36536379Ssklower 	 *	PHASE2
36636379Ssklower 	 *	If redirect is to an IS, add an address mask. The mask to be
36736379Ssklower 	 *	used should be the mask present in the routing entry used to
36836379Ssklower 	 *	forward the original data packet.
36936379Ssklower 	 */
37036379Ssklower 
37136379Ssklower 	/*
37236379Ssklower 	 *	Copy Qos, priority, or security options present in original npdu
37336379Ssklower 	 */
37436379Ssklower 	if (inbound_oidx) {
37543332Ssklower 		/* THIS CODE IS CURRENTLY (mostly) UNTESTED */
37636379Ssklower 		int optlen = 0;
37736379Ssklower 		if (inbound_oidx->cni_qos_formatp)
37836379Ssklower 			optlen += (inbound_oidx->cni_qos_len + 2);
37936379Ssklower 		if (inbound_oidx->cni_priorp)	/* priority option is 1 byte long */
38036379Ssklower 			optlen += 3;
38136379Ssklower 		if (inbound_oidx->cni_securep)
38236379Ssklower 			optlen += (inbound_oidx->cni_secure_len + 2);
38337469Ssklower 		if (M_TRAILINGSPACE(m) < optlen) {
38437469Ssklower 			EXTEND_PACKET(m, m0, cp);
38537469Ssklower 			m->m_len = 0;
38636379Ssklower 			/* assumes MLEN > optlen */
38736379Ssklower 		}
38836379Ssklower 		/* assume MLEN-len > optlen */
38936379Ssklower 		/*
39036379Ssklower 		 *	When copying options, copy from ptr - 2 in order to grab
39136379Ssklower 		 *	the option code and length
39236379Ssklower 		 */
39336379Ssklower 		if (inbound_oidx->cni_qos_formatp) {
39443332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_qos_formatp - 2,
39543332Ssklower 				cp, (unsigned)(inbound_oidx->cni_qos_len + 2));
39643332Ssklower 			cp += inbound_oidx->cni_qos_len + 2;
39736379Ssklower 		}
39836379Ssklower 		if (inbound_oidx->cni_priorp) {
39943332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_priorp - 2,
40043332Ssklower 					cp, 3);
40143332Ssklower 			cp += 3;
40236379Ssklower 		}
40336379Ssklower 		if (inbound_oidx->cni_securep) {
40443332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_securep - 2, cp,
40537469Ssklower 				(unsigned)(inbound_oidx->cni_secure_len + 2));
40643332Ssklower 			cp += inbound_oidx->cni_secure_len + 2;
40736379Ssklower 		}
40837469Ssklower 		m->m_len += optlen;
40943332Ssklower 		len += optlen;
41036379Ssklower 	}
41136379Ssklower 
41237469Ssklower 	pdu->esis_hdr_len = m0->m_pkthdr.len = len;
41336379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
41436379Ssklower 
41537469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
41636379Ssklower 	siso.siso_family = AF_ISO;
41737469Ssklower 	siso.siso_data[0] = AFI_SNA;
41837469Ssklower 	siso.siso_nlen = 6 + 1;	/* should be taken from snpa_hdr */
41936379Ssklower 										/* +1 is for AFI */
42037469Ssklower 	bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6);
42140775Ssklower 	(ifp->if_output)(ifp, m0, &siso, 0);
42236379Ssklower }
42336379Ssklower 
42436379Ssklower /*
42536379Ssklower  * FUNCTION:		esis_insert_addr
42636379Ssklower  *
42736379Ssklower  * PURPOSE:			Insert an iso_addr into a buffer
42836379Ssklower  *
42936379Ssklower  * RETURNS:			true if buffer was big enough, else false
43036379Ssklower  *
43136379Ssklower  * SIDE EFFECTS:	Increment buf & len according to size of iso_addr
43236379Ssklower  *
43336379Ssklower  * NOTES:			Plus 1 here is for length byte
43436379Ssklower  */
43543072Ssklower esis_insert_addr(buf, len, isoa, m, nsellen)
43643332Ssklower register caddr_t			*buf;		/* ptr to buffer to put address into */
43743332Ssklower int							*len;		/* ptr to length of buffer so far */
43843332Ssklower register struct iso_addr	*isoa;		/* ptr to address */
43943332Ssklower register struct mbuf		*m;			/* determine if there remains space */
44043332Ssklower int							nsellen;
44136379Ssklower {
44243332Ssklower 	register int newlen, result = 0;
44336379Ssklower 
44443332Ssklower 	isoa->isoa_len -= nsellen;
44543332Ssklower 	newlen = isoa->isoa_len + 1;
44643332Ssklower 	if (newlen <=  M_TRAILINGSPACE(m)) {
44743332Ssklower 		bcopy((caddr_t)isoa, *buf, newlen);
44843332Ssklower 		*len += newlen;
44943332Ssklower 		*buf += newlen;
45043332Ssklower 		m->m_len += newlen;
45143332Ssklower 		result = 1;
45243332Ssklower 	}
45343332Ssklower 	isoa->isoa_len += nsellen;
45443332Ssklower 	return (result);
45536379Ssklower }
45636379Ssklower 
45739950Ssklower #define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \
45839950Ssklower 	    if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
45939950Ssklower #define ESIS_NEXT_OPTION(b)	{ b += (2 + b[1]); \
46039950Ssklower 	    if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
46143430Ssklower int ESHonly = 0;
46236379Ssklower /*
46336379Ssklower 
46436379Ssklower /*
46536379Ssklower  * FUNCTION:		esis_eshinput
46636379Ssklower  *
46736379Ssklower  * PURPOSE:			Process an incoming ESH pdu
46836379Ssklower  *
46936379Ssklower  * RETURNS:			nothing
47036379Ssklower  *
47136379Ssklower  * SIDE EFFECTS:
47236379Ssklower  *
47336379Ssklower  * NOTES:
47436379Ssklower  */
47536379Ssklower esis_eshinput(m, shp)
47636379Ssklower struct mbuf		*m;	/* esh pdu */
47736379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
47836379Ssklower {
47943072Ssklower 	struct	esis_fixed	*pdu = mtod(m, struct esis_fixed *);
48036379Ssklower 	u_short				ht;		/* holding time */
48143072Ssklower 	struct	iso_addr	*nsap;
48239950Ssklower 	int					naddr;
48337469Ssklower 	u_char				*buf = (u_char *)(pdu + 1);
48439950Ssklower 	u_char				*buflim = pdu->esis_hdr_len + (u_char *)pdu;
48543332Ssklower 	int					new_entry = 0;
48636379Ssklower 
48736379Ssklower 	esis_stat.es_eshrcvd++;
48836379Ssklower 
48936379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
49036379Ssklower 
49139950Ssklower 	naddr = *buf++;
49239950Ssklower 	if (buf >= buflim)
49336379Ssklower 		goto bad;
49443332Ssklower 	if (naddr == 1) {
49539950Ssklower 		ESIS_EXTRACT_ADDR(nsap, buf);
49643332Ssklower 		new_entry = snpac_add(shp->snh_ifp,
49743332Ssklower 								 nsap, shp->snh_shost, SNPA_ES, ht, 0);
49843332Ssklower 	} else {
49943332Ssklower 		int nsellength = 0, nlen = 0;
50043332Ssklower 		{
50143332Ssklower 		/* See if we want to compress out multiple nsaps differing
50243332Ssklower 		   only by nsel */
50343332Ssklower 			register struct ifaddr *ifa = shp->snh_ifp->if_addrlist;
50443332Ssklower 			for (; ifa; ifa = ifa->ifa_next)
50543332Ssklower 				if (ifa->ifa_addr->sa_family == AF_ISO) {
50643332Ssklower 					nsellength = ((struct iso_ifaddr *)ifa)->ia_addr.siso_tlen;
50743332Ssklower 					break;
50843332Ssklower 			}
50943332Ssklower 		}
51039950Ssklower 		IFDEBUG(D_ESISINPUT)
51143332Ssklower 			printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n",
51243332Ssklower 					ht, naddr, nsellength);
51339950Ssklower 		ENDDEBUG
51443332Ssklower 		while (naddr-- > 0) {
51543332Ssklower 			struct iso_addr *nsap2; u_char *buf2;
51643332Ssklower 			ESIS_EXTRACT_ADDR(nsap, buf);
51743332Ssklower 			/* see if there is at least one more nsap in ESH differing
51843332Ssklower 			   only by nsel */
51943332Ssklower 			if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) {
52043332Ssklower 				ESIS_EXTRACT_ADDR(nsap2, buf2);
52143332Ssklower 				IFDEBUG(D_ESISINPUT)
52243332Ssklower 					printf("esis_eshinput: comparing %s ",
52343332Ssklower 						clnp_iso_addrp(nsap));
52443332Ssklower 					printf("and %s\n", clnp_iso_addrp(nsap2));
52543332Ssklower 				ENDDEBUG
52643332Ssklower 				if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr,
52743332Ssklower 						 nsap->isoa_len - nsellength) == 0) {
52843332Ssklower 					nlen = nsellength;
52943332Ssklower 					break;
53043332Ssklower 				}
53143332Ssklower 			}
53243332Ssklower 			new_entry |= snpac_add(shp->snh_ifp,
53343332Ssklower 									nsap, shp->snh_shost, SNPA_ES, ht, nlen);
53443332Ssklower 			nlen = 0;
53543332Ssklower 		}
53639950Ssklower 	}
53743332Ssklower 	IFDEBUG(D_ESISINPUT)
53843332Ssklower 		printf("esis_eshinput: nsap %s is %s\n",
53943332Ssklower 			clnp_iso_addrp(nsap), new_entry ? "new" : "old");
54043332Ssklower 	ENDDEBUG
54143332Ssklower 	if (new_entry && (iso_systype & SNPA_IS))
54243332Ssklower 		esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time,
54343332Ssklower 						shp->snh_shost, 6, (struct iso_addr *)0);
54437469Ssklower bad:
54539950Ssklower 	return;
54636379Ssklower }
54736379Ssklower 
54836379Ssklower /*
54936379Ssklower  * FUNCTION:		esis_ishinput
55036379Ssklower  *
55136379Ssklower  * PURPOSE:			process an incoming ISH pdu
55236379Ssklower  *
55336379Ssklower  * RETURNS:
55436379Ssklower  *
55536379Ssklower  * SIDE EFFECTS:
55636379Ssklower  *
55736379Ssklower  * NOTES:
55836379Ssklower  */
55936379Ssklower esis_ishinput(m, shp)
56036379Ssklower struct mbuf		*m;	/* esh pdu */
56136379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
56236379Ssklower {
56336379Ssklower 	struct esis_fixed	*pdu = mtod(m, struct esis_fixed *);
56443430Ssklower 	u_short				ht, newct;			/* holding time */
56539950Ssklower 	struct iso_addr		*nsap; 				/* Network Entity Title */
56639950Ssklower 	register u_char		*buf = (u_char *) (pdu + 1);
56739950Ssklower 	register u_char		*buflim = pdu->esis_hdr_len + (u_char *)pdu;
56839950Ssklower 	int					new_entry;
56936379Ssklower 
57036379Ssklower 	esis_stat.es_ishrcvd++;
57136379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
57236379Ssklower 
57336379Ssklower 	IFDEBUG(D_ESISINPUT)
57436379Ssklower 		printf("esis_ishinput: ish: ht %d\n", ht);
57536379Ssklower 	ENDDEBUG
57639950Ssklower 	if (ESHonly)
57737469Ssklower 		goto bad;
57836379Ssklower 
57939950Ssklower 	ESIS_EXTRACT_ADDR(nsap, buf);
58039950Ssklower 
58139950Ssklower 	while (buf < buflim) {
58239950Ssklower 		switch (*buf) {
58337469Ssklower 		case ESISOVAL_ESCT:
58444946Ssklower 			if (iso_systype & SNPA_IS)
58544946Ssklower 				break;
58639950Ssklower 			if (buf[1] != 2)
58737469Ssklower 				goto bad;
58843430Ssklower 			CTOH(buf[2], buf[3], newct);
58943430Ssklower 			if (esis_config_time != newct) {
59043430Ssklower 				untimeout(esis_config,0);
59143430Ssklower 				esis_config_time = newct;
59243430Ssklower 				esis_config();
59343430Ssklower 			}
59439950Ssklower 			break;
59539950Ssklower 
59639950Ssklower 		default:
59739950Ssklower 			printf("Unknown ISH option: %x\n", *buf);
59837469Ssklower 		}
59939950Ssklower 		ESIS_NEXT_OPTION(buf);
60037469Ssklower 	}
60143332Ssklower 	new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0);
60237469Ssklower 	IFDEBUG(D_ESISINPUT)
60337469Ssklower 		printf("esis_ishinput: nsap %s is %s\n",
60437469Ssklower 			clnp_iso_addrp(nsap), new_entry ? "new" : "old");
60537469Ssklower 	ENDDEBUG
60637469Ssklower 
60737469Ssklower 	if (new_entry)
60837469Ssklower 		esis_shoutput(shp->snh_ifp,
60937469Ssklower 			iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
61043332Ssklower 			esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0);
61139950Ssklower bad:
61239950Ssklower 	return;
61336379Ssklower }
61436379Ssklower 
61536379Ssklower /*
61636379Ssklower  * FUNCTION:		esis_rdinput
61736379Ssklower  *
61836379Ssklower  * PURPOSE:			Process an incoming RD pdu
61936379Ssklower  *
62036379Ssklower  * RETURNS:
62136379Ssklower  *
62236379Ssklower  * SIDE EFFECTS:
62336379Ssklower  *
62436379Ssklower  * NOTES:
62536379Ssklower  */
62636379Ssklower esis_rdinput(m0, shp)
62736379Ssklower struct mbuf		*m0;	/* esh pdu */
62836379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
62936379Ssklower {
63036379Ssklower 	struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
63136379Ssklower 	u_short				ht;		/* holding time */
63239950Ssklower 	struct iso_addr		*da, *net = 0, *netmask = 0, *snpamask = 0;
63339950Ssklower 	register struct iso_addr *bsnpa;
63439950Ssklower 	register u_char		*buf = (u_char *)(pdu + 1);
63539950Ssklower 	register u_char		*buflim = pdu->esis_hdr_len + (u_char *)pdu;
63636379Ssklower 
63736379Ssklower 	esis_stat.es_rdrcvd++;
63836379Ssklower 
63936379Ssklower 	/* intermediate systems ignore redirects */
64036379Ssklower 	if (iso_systype & SNPA_IS)
64143421Ssklower 		return;
64239950Ssklower 	if (ESHonly)
64343421Ssklower 		return;
64436379Ssklower 
64536379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
64639950Ssklower 	if (buf >= buflim)
64743421Ssklower 		return;
64836379Ssklower 
64936379Ssklower 	/* Extract DA */
65039950Ssklower 	ESIS_EXTRACT_ADDR(da, buf);
65137469Ssklower 
65236379Ssklower 	/* Extract better snpa */
65339950Ssklower 	ESIS_EXTRACT_ADDR(bsnpa, buf);
65439950Ssklower 
65537469Ssklower 	/* Extract NET if present */
65639950Ssklower 	if (buf < buflim) {
65743332Ssklower 		if (*buf == 0)
65843332Ssklower 			buf++; /* no NET present, skip NETL anyway */
65943332Ssklower 		else
66043332Ssklower 			ESIS_EXTRACT_ADDR(net, buf);
66136379Ssklower 	}
66236379Ssklower 
66337469Ssklower 	/* process options */
66439950Ssklower 	while (buf < buflim) {
66539950Ssklower 		switch (*buf) {
66637469Ssklower 		case ESISOVAL_SNPAMASK:
66737469Ssklower 			if (snpamask) /* duplicate */
66843421Ssklower 				return;
66939950Ssklower 			snpamask = (struct iso_addr *)(buf + 1);
67037469Ssklower 			break;
67137469Ssklower 
67237469Ssklower 		case ESISOVAL_NETMASK:
67337469Ssklower 			if (netmask) /* duplicate */
67443421Ssklower 				return;
67539950Ssklower 			netmask = (struct iso_addr *)(buf + 1);
67639950Ssklower 			break;
67739950Ssklower 
67839950Ssklower 		default:
67939950Ssklower 			printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]);
68037469Ssklower 		}
68139950Ssklower 		ESIS_NEXT_OPTION(buf);
68236379Ssklower 	}
68336379Ssklower 
68436379Ssklower 	IFDEBUG(D_ESISINPUT)
68537469Ssklower 		printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da));
68637469Ssklower 		if (net)
68737469Ssklower 			printf("\t: net %s\n", clnp_iso_addrp(net));
68836379Ssklower 	ENDDEBUG
68936379Ssklower 	/*
69036379Ssklower 	 *	If netl is zero, then redirect is to an ES. We need to add an entry
69136379Ssklower 	 *	to the snpa cache for (destination, better snpa).
69236379Ssklower 	 *	If netl is not zero, then the redirect is to an IS. In this
69336379Ssklower 	 *	case, add an snpa cache entry for (net, better snpa).
69436379Ssklower 	 *
69536379Ssklower 	 *	If the redirect is to an IS, add a route entry towards that
69636379Ssklower 	 *	IS.
69736379Ssklower 	 */
69839950Ssklower 	if (net == 0 || net->isoa_len == 0 || snpamask) {
69936379Ssklower 		/* redirect to an ES */
70039950Ssklower 		snpac_add(shp->snh_ifp, da,
70143332Ssklower 				bsnpa->isoa_genaddr, SNPA_ES, ht, 0);
70236379Ssklower 	} else {
70339950Ssklower 		snpac_add(shp->snh_ifp, net,
70443332Ssklower 				bsnpa->isoa_genaddr, SNPA_IS, ht, 0);
70539950Ssklower 		snpac_addrt(shp->snh_ifp, da, net, netmask);
70636379Ssklower 	}
70743421Ssklower bad: ;    /* Needed by ESIS_NEXT_OPTION */
70836379Ssklower }
70936379Ssklower 
71036379Ssklower /*
71136379Ssklower  * FUNCTION:		esis_config
71236379Ssklower  *
71336379Ssklower  * PURPOSE:			Report configuration
71436379Ssklower  *
71536379Ssklower  * RETURNS:
71636379Ssklower  *
71736379Ssklower  * SIDE EFFECTS:
71836379Ssklower  *
71936379Ssklower  * NOTES:			Called every esis_config_time seconds
72036379Ssklower  */
72136379Ssklower esis_config()
72236379Ssklower {
72336379Ssklower 	register struct ifnet	*ifp;
72436379Ssklower 
72536379Ssklower 	timeout(esis_config, (caddr_t)0, hz * esis_config_time);
72636379Ssklower 
72736379Ssklower 	/*
72836379Ssklower 	 *	Report configuration for each interface that
72936379Ssklower 	 *	- is UP
73048963Ssklower 	 *	- has BROADCAST capability
73136379Ssklower 	 *	- has an ISO address
73236379Ssklower 	 */
73348963Ssklower 	/* Todo: a better way would be to construct the esh or ish
73448963Ssklower 	 * once and copy it out for all devices, possibly calling
73548963Ssklower 	 * a method in the iso_ifaddr structure to encapsulate and
73648963Ssklower 	 * transmit it.  This could work to advantage for non-broadcast media
73748963Ssklower 	 */
73836379Ssklower 
73936379Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
74036379Ssklower 		if ((ifp->if_flags & IFF_UP) &&
74148963Ssklower 		    (ifp->if_flags & IFF_BROADCAST)) {
74236379Ssklower 			/* search for an ISO address family */
74336379Ssklower 			struct ifaddr	*ia;
74436379Ssklower 
74536379Ssklower 			for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {
74637469Ssklower 				if (ia->ifa_addr->sa_family == AF_ISO) {
74736379Ssklower 					esis_shoutput(ifp,
74836379Ssklower 						iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
74936379Ssklower 						esis_holding_time,
75043332Ssklower 						(caddr_t)(iso_systype & SNPA_ES ? all_is_snpa :
75143332Ssklower 						all_es_snpa), 6, (struct iso_addr *)0);
75236379Ssklower 					break;
75336379Ssklower 				}
75436379Ssklower 			}
75536379Ssklower 		}
75636379Ssklower 	}
75736379Ssklower }
75836379Ssklower 
75936379Ssklower /*
76036379Ssklower  * FUNCTION:		esis_shoutput
76136379Ssklower  *
76236379Ssklower  * PURPOSE:			Transmit an esh or ish pdu
76336379Ssklower  *
76436379Ssklower  * RETURNS:			nothing
76536379Ssklower  *
76636379Ssklower  * SIDE EFFECTS:
76736379Ssklower  *
76836379Ssklower  * NOTES:
76936379Ssklower  */
77043332Ssklower esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa)
77136379Ssklower struct ifnet	*ifp;
77236379Ssklower int				type;
77336379Ssklower short			ht;
77436379Ssklower caddr_t 		sn_addr;
77536379Ssklower int				sn_len;
77643332Ssklower struct	iso_addr *isoa;
77736379Ssklower {
77836379Ssklower 	struct mbuf			*m, *m0;
77936379Ssklower 	caddr_t				cp, naddrp;
78036379Ssklower 	int					naddr = 0;
78136379Ssklower 	struct esis_fixed	*pdu;
78243332Ssklower 	struct iso_ifaddr	*ia;
78337469Ssklower 	int					len;
78436379Ssklower 	struct sockaddr_iso	siso;
78536379Ssklower 
78636379Ssklower 	if (type == ESIS_ESH)
78736379Ssklower 		esis_stat.es_eshsent++;
78836379Ssklower 	else if (type == ESIS_ISH)
78936379Ssklower 		esis_stat.es_ishsent++;
79036379Ssklower 	else {
79136379Ssklower 		printf("esis_shoutput: bad pdu type\n");
79236379Ssklower 		return;
79336379Ssklower 	}
79436379Ssklower 
79536379Ssklower 	IFDEBUG(D_ESISOUTPUT)
79636379Ssklower 		int	i;
79736379Ssklower 		printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ",
79836379Ssklower 			ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish",
79936379Ssklower 			ht, sn_len);
80036379Ssklower 		for (i=0; i<sn_len; i++)
80136379Ssklower 			printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' ');
80236379Ssklower 		printf("\n");
80336379Ssklower 	ENDDEBUG
80436379Ssklower 
80537469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
80636379Ssklower 		esis_stat.es_nomem++;
80736379Ssklower 		return;
80836379Ssklower 	}
80937469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
81036379Ssklower 
81136379Ssklower 	pdu = mtod(m, struct esis_fixed *);
81237469Ssklower 	naddrp = cp = (caddr_t)(pdu + 1);
81336379Ssklower 	len = sizeof(struct esis_fixed);
81436379Ssklower 
81536379Ssklower 	/*
81636379Ssklower 	 *	Build fixed part of header
81736379Ssklower 	 */
81836379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
81936379Ssklower 	pdu->esis_vers = ESIS_VERSION;
82036379Ssklower 	pdu->esis_type = type;
82136379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
82236379Ssklower 
82336379Ssklower 	if (type == ESIS_ESH) {
82436379Ssklower 		cp++;
82536379Ssklower 		len++;
82636379Ssklower 	}
82736379Ssklower 
82837469Ssklower 	m->m_len = len;
82943332Ssklower 	if (isoa) {
83043332Ssklower 		/*
83143332Ssklower 		 * Here we are responding to a clnp packet sent to an NSAP
83243332Ssklower 		 * that is ours which was sent to the MAC addr all_es's.
83343332Ssklower 		 * It is possible that we did not specifically advertise this
83443332Ssklower 		 * NSAP, even though it is ours, so we will respond
83543332Ssklower 		 * directly to the sender that we are here.  If we do have
83643332Ssklower 		 * multiple NSEL's we'll tack them on so he can compress them out.
83743332Ssklower 		 */
83843332Ssklower 		(void) esis_insert_addr(&cp, &len, isoa, m, 0);
83943332Ssklower 		naddr = 1;
84043332Ssklower 	}
84143332Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
84243332Ssklower 		int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0);
84343332Ssklower 		int n = ia->ia_addr.siso_nlen;
84443332Ssklower 		register struct iso_ifaddr *ia2;
84543332Ssklower 
84643332Ssklower 		if (type == ESIS_ISH && naddr > 0)
84743332Ssklower 			break;
84843332Ssklower 		for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next)
84943332Ssklower 			if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0)
85043332Ssklower 					break;
85143332Ssklower 		if (ia2 != ia)
85243332Ssklower 			continue;	/* Means we have previously copied this nsap */
85343332Ssklower 		if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) {
85443332Ssklower 			isoa = 0;
85543332Ssklower 			continue;	/* Ditto */
85636379Ssklower 		}
85743332Ssklower 		IFDEBUG(D_ESISOUTPUT)
85843332Ssklower 			printf("esis_shoutput: adding NSAP %s\n",
85943332Ssklower 				clnp_iso_addrp(&ia->ia_addr.siso_addr));
86043332Ssklower 		ENDDEBUG
86143332Ssklower 		if (!esis_insert_addr(&cp, &len,
86243332Ssklower 							  &ia->ia_addr.siso_addr, m, nsellen)) {
86343332Ssklower 			EXTEND_PACKET(m, m0, cp);
86443332Ssklower 			(void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m,
86543332Ssklower 									nsellen);
86643332Ssklower 		}
86743332Ssklower 		naddr++;
86836379Ssklower 	}
86936379Ssklower 
87036379Ssklower 	if (type == ESIS_ESH)
87136379Ssklower 		*naddrp = naddr;
87244254Ssklower 	else {
87344254Ssklower 		/* add suggested es config timer option to ISH */
87444254Ssklower 		if (M_TRAILINGSPACE(m) < 4) {
87544254Ssklower 			printf("esis_shoutput: extending packet\n");
87644254Ssklower 			EXTEND_PACKET(m, m0, cp);
87744254Ssklower 		}
87844254Ssklower 		*cp++ = ESISOVAL_ESCT;
87944254Ssklower 		*cp++ = 2;
88044254Ssklower 		HTOC(*cp, *(cp+1), esis_esconfig_time);
88144254Ssklower 		len += 4;
88244254Ssklower 		m->m_len += 4;
88344254Ssklower 		IFDEBUG(D_ESISOUTPUT)
88444254Ssklower 			printf("m0 0x%x, m 0x%x, data 0x%x, len %d, cp 0x%x\n",
88544254Ssklower 			m0, m, m->m_data, m->m_len, cp);
88644254Ssklower 		ENDDEBUG
88744254Ssklower 	}
88836379Ssklower 
88937469Ssklower 	m0->m_pkthdr.len = len;
89037469Ssklower 	pdu->esis_hdr_len = len;
89136379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
89236379Ssklower 
89337469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
89436379Ssklower 	siso.siso_family = AF_ISO;
89537469Ssklower 	siso.siso_data[0] = AFI_SNA;
89637469Ssklower 	siso.siso_nlen = sn_len + 1;
89737469Ssklower 	bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len);
89840775Ssklower 	(ifp->if_output)(ifp, m0, &siso, 0);
89936379Ssklower }
90036379Ssklower 
90136379Ssklower /*
90243421Ssklower  * FUNCTION:		isis_input
90343421Ssklower  *
90443421Ssklower  * PURPOSE:			Process an incoming isis packet
90543421Ssklower  *
90643421Ssklower  * RETURNS:			nothing
90743421Ssklower  *
90843421Ssklower  * SIDE EFFECTS:
90943421Ssklower  *
91043421Ssklower  * NOTES:
91143421Ssklower  */
91243421Ssklower isis_input(m0, shp)
91343421Ssklower struct mbuf		*m0;		/* ptr to first mbuf of pkt */
91443421Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
91543421Ssklower {
91643421Ssklower 	register int type;
91743961Ssklower 	register struct rawcb *rp, *first_rp = 0;
91843421Ssklower 	struct ifnet *ifp = shp->snh_ifp;
91943421Ssklower 	char workbuf[16];
92043421Ssklower 	struct mbuf *mm;
92143421Ssklower 
92243421Ssklower 	IFDEBUG(D_ISISINPUT)
92343421Ssklower 		int i;
92443421Ssklower 
92543421Ssklower 		printf("isis_input: pkt on ifp x%x (%s%d): from:", ifp,
92643421Ssklower 			ifp->if_name, ifp->if_unit);
92743421Ssklower 		for (i=0; i<6; i++)
92843421Ssklower 			printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' ');
92943421Ssklower 		printf(" to:");
93043421Ssklower 		for (i=0; i<6; i++)
93143421Ssklower 			printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' ');
93243421Ssklower 		printf("\n");
93343421Ssklower 	ENDDEBUG
93443421Ssklower 	esis_dl.sdl_alen = ifp->if_addrlen;
93543421Ssklower 	esis_dl.sdl_index = ifp->if_index;
93643421Ssklower 	bcopy(shp->snh_shost, (caddr_t)esis_dl.sdl_data, esis_dl.sdl_alen);
93743421Ssklower 	for (rp = esis_pcb.rcb_next; rp != &esis_pcb; rp = rp->rcb_next) {
93843961Ssklower 		if (first_rp == 0) {
93943961Ssklower 			first_rp = rp;
94043421Ssklower 			continue;
94143421Ssklower 		}
94243421Ssklower 		if (mm = m_copy(m0, 0, M_COPYALL)) { /*can't block at interrupt level */
94343421Ssklower 			if (sbappendaddr(&rp->rcb_socket->so_rcv,
94443421Ssklower 							  &esis_dl, mm, (struct mbuf *)0) != 0)
94543421Ssklower 				sorwakeup(rp->rcb_socket);
94643421Ssklower 			else {
94743421Ssklower 				IFDEBUG(D_ISISINPUT)
94843421Ssklower 					printf("Error in sbappenaddr, mm = 0x%x\n", mm);
94943421Ssklower 				ENDDEBUG
95043421Ssklower 				m_freem(mm);
95143421Ssklower 			}
95243421Ssklower 		}
95343421Ssklower 	}
95443961Ssklower 	if (first_rp && sbappendaddr(&first_rp->rcb_socket->so_rcv,
95544946Ssklower 							  &esis_dl, m0, (struct mbuf *)0) != 0) {
95643961Ssklower 		sorwakeup(first_rp->rcb_socket);
95743961Ssklower 		return;
95843421Ssklower 	}
95943961Ssklower 	m_freem(m0);
96043421Ssklower }
96143421Ssklower 
96243421Ssklower isis_output(sdl, m)
96343421Ssklower register struct sockaddr_dl	*sdl;
96443421Ssklower struct mbuf *m;
96543421Ssklower {
96643421Ssklower 	register struct ifnet *ifp;
96743421Ssklower 	struct ifaddr *ifa, *ifa_ifwithnet();
96843421Ssklower 	struct sockaddr_iso siso;
96943421Ssklower 	int error = 0;
97043421Ssklower 	unsigned sn_len;
97143421Ssklower 
97243421Ssklower 	ifa = ifa_ifwithnet(sdl);	/* extract ifp from sockaddr_dl */
97343421Ssklower 	if (ifa == 0) {
97443421Ssklower 		IFDEBUG(D_ISISOUTPUT)
97543421Ssklower 			printf("isis_output: interface not found\n");
97643421Ssklower 		ENDDEBUG
97743421Ssklower 		error = EINVAL;
97843421Ssklower 		goto release;
97943421Ssklower 	}
98043421Ssklower 	ifp = ifa->ifa_ifp;
98145896Ssklower 	sn_len = sdl->sdl_alen;
98243421Ssklower 	IFDEBUG(D_ISISOUTPUT)
98343421Ssklower 		u_char *cp = (u_char *)LLADDR(sdl), *cplim = cp + sn_len;
98443421Ssklower 		printf("isis_output: ifp 0x%x (%s%d), to: ",
98543421Ssklower 			ifp, ifp->if_name, ifp->if_unit);
98643421Ssklower 		while (cp < cplim) {
98743421Ssklower 			printf("%x", *cp++);
98843421Ssklower 			printf("%c", (cp < cplim) ? ':' : ' ');
98943421Ssklower 		}
99043421Ssklower 		printf("\n");
99143421Ssklower 	ENDDEBUG
99243421Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
99343421Ssklower 	siso.siso_family = AF_ISO; /* This convention may be useful for X.25 */
99443421Ssklower 	siso.siso_data[0] = AFI_SNA;
99543421Ssklower 	siso.siso_nlen = sn_len + 1;
99643421Ssklower 	bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len);
99743421Ssklower 	error = (ifp->if_output)(ifp, m, (struct sockaddr *)&siso, 0);
99843421Ssklower 	if (error) {
99943421Ssklower 		IFDEBUG(D_ISISOUTPUT)
100043421Ssklower 			printf("isis_output: error from ether_output is %d\n", error);
100143421Ssklower 		ENDDEBUG
100243421Ssklower 	}
100343421Ssklower 	return (error);
100443421Ssklower 
100543421Ssklower release:
100643421Ssklower 	if (m != NULL)
100743421Ssklower 		m_freem(m);
100843421Ssklower 	return(error);
100943421Ssklower }
101043421Ssklower 
101143421Ssklower 
101243421Ssklower /*
101336379Ssklower  * FUNCTION:		esis_ctlinput
101436379Ssklower  *
101536379Ssklower  * PURPOSE:			Handle the PRC_IFDOWN transition
101636379Ssklower  *
101736379Ssklower  * RETURNS:			nothing
101836379Ssklower  *
101936379Ssklower  * SIDE EFFECTS:
102036379Ssklower  *
102136379Ssklower  * NOTES:			Calls snpac_flush for interface specified.
102236379Ssklower  *					The loop through iso_ifaddr is stupid because
102336379Ssklower  *					back in if_down, we knew the ifp...
102436379Ssklower  */
102536379Ssklower esis_ctlinput(req, siso)
102636379Ssklower int						req;		/* request: we handle only PRC_IFDOWN */
102736379Ssklower struct sockaddr_iso		*siso;		/* address of ifp */
102836379Ssklower {
102936379Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
103036379Ssklower 
103137469Ssklower 	if (req == PRC_IFDOWN)
103237469Ssklower 		for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
103337469Ssklower 			if (iso_addrmatch(IA_SIS(ia), siso))
103437469Ssklower 				snpac_flushifp(ia->ia_ifp);
103537469Ssklower 		}
103636379Ssklower }
103736379Ssklower 
103836379Ssklower #endif	ISO
1039