xref: /csrg-svn/sys/netiso/esis.c (revision 61300)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*61300Ssklower  *	@(#)esis.c	7.24 (Berkeley) 06/04/93
849268Sbostic  */
949268Sbostic 
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 
3956533Sbostic #include <sys/param.h>
4056533Sbostic #include <sys/systm.h>
4156533Sbostic #include <sys/mbuf.h>
4256533Sbostic #include <sys/domain.h>
4356533Sbostic #include <sys/protosw.h>
4456533Sbostic #include <sys/socket.h>
4556533Sbostic #include <sys/socketvar.h>
4656533Sbostic #include <sys/errno.h>
4756533Sbostic #include <sys/kernel.h>
4836379Ssklower 
4956533Sbostic #include <net/if.h>
5056533Sbostic #include <net/if_dl.h>
5156533Sbostic #include <net/route.h>
5256533Sbostic #include <net/raw_cb.h>
5336379Ssklower 
5456533Sbostic #include <netiso/iso.h>
5556533Sbostic #include <netiso/iso_pcb.h>
5656533Sbostic #include <netiso/iso_var.h>
5756533Sbostic #include <netiso/iso_snpac.h>
5856533Sbostic #include <netiso/clnl.h>
5956533Sbostic #include <netiso/clnp.h>
6056533Sbostic #include <netiso/clnp_stat.h>
6156533Sbostic #include <netiso/esis.h>
6256533Sbostic #include <netiso/argo_debug.h>
6336379Ssklower 
6436379Ssklower /*
6536379Ssklower  *	Global variables to esis implementation
6636379Ssklower  *
6736379Ssklower  *	esis_holding_time - the holding time (sec) parameter for outgoing pdus
6836379Ssklower  *	esis_config_time  - the frequency (sec) that hellos are generated
6943421Ssklower  *	esis_esconfig_time - suggested es configuration time placed in the
7043421Ssklower  *						ish.
7136379Ssklower  *
7236379Ssklower  */
7343421Ssklower struct rawcb	esis_pcb;
7458988Ssklower void				esis_config(), snpac_age();
7536379Ssklower int				esis_sendspace = 2048;
7636379Ssklower int				esis_recvspace = 2048;
7736379Ssklower short			esis_holding_time = ESIS_HT;
7836379Ssklower short			esis_config_time = ESIS_CONFIG;
7943421Ssklower short			esis_esconfig_time = ESIS_CONFIG;
8036379Ssklower extern int		iso_systype;
8143421Ssklower struct sockaddr_dl	esis_dl = { sizeof(esis_dl), AF_LINK };
8243332Ssklower extern char		all_es_snpa[], all_is_snpa[];
8336379Ssklower 
8437469Ssklower #define EXTEND_PACKET(m, mhdr, cp)\
8536379Ssklower 	if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\
8636379Ssklower 		esis_stat.es_nomem++;\
8736379Ssklower 		m_freem(mhdr);\
8836379Ssklower 		return;\
8936379Ssklower 	} else {\
9036379Ssklower 		(m) = (m)->m_next;\
9136379Ssklower 		(cp) = mtod((m), caddr_t);\
9236379Ssklower 	}
9336379Ssklower /*
9436379Ssklower  * FUNCTION:		esis_init
9536379Ssklower  *
9636379Ssklower  * PURPOSE:			Initialize the kernel portion of esis protocol
9736379Ssklower  *
9836379Ssklower  * RETURNS:			nothing
9936379Ssklower  *
10036379Ssklower  * SIDE EFFECTS:
10136379Ssklower  *
10236379Ssklower  * NOTES:
10336379Ssklower  */
10436379Ssklower esis_init()
10536379Ssklower {
10636379Ssklower 	extern struct clnl_protosw clnl_protox[256];
10743892Ssklower 	int	esis_input(), isis_input();
10836379Ssklower #ifdef	ISO_X25ESIS
10943892Ssklower 	int	x25esis_input();
110*61300Ssklower #endif	/* ISO_X25ESIS */
11136379Ssklower 
11243421Ssklower 	esis_pcb.rcb_next = esis_pcb.rcb_prev = &esis_pcb;
11343421Ssklower 	llinfo_llc.lc_next = llinfo_llc.lc_prev = &llinfo_llc;
11436379Ssklower 
11536379Ssklower 	timeout(snpac_age, (caddr_t)0, hz);
11636379Ssklower 	timeout(esis_config, (caddr_t)0, hz);
11736379Ssklower 
11843892Ssklower 	clnl_protox[ISO9542_ESIS].clnl_input = esis_input;
11943892Ssklower 	clnl_protox[ISO10589_ISIS].clnl_input = isis_input;
12036379Ssklower #ifdef	ISO_X25ESIS
12136379Ssklower 	clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input;
122*61300Ssklower #endif	/* ISO_X25ESIS */
12336379Ssklower }
12436379Ssklower 
12536379Ssklower /*
12636379Ssklower  * FUNCTION:		esis_usrreq
12736379Ssklower  *
12836379Ssklower  * PURPOSE:			Handle user level esis requests
12936379Ssklower  *
13036379Ssklower  * RETURNS:			0 or appropriate errno
13136379Ssklower  *
13236379Ssklower  * SIDE EFFECTS:
13336379Ssklower  *
13436379Ssklower  */
13537469Ssklower /*ARGSUSED*/
13640775Ssklower esis_usrreq(so, req, m, nam, control)
13736379Ssklower struct socket	*so;		/* socket: used only to get to this code */
13836379Ssklower int				req;		/* request */
13936379Ssklower struct mbuf		*m;			/* data for request */
14036379Ssklower struct mbuf		*nam;		/* optional name */
14140775Ssklower struct mbuf		*control;	/* optional control */
14236379Ssklower {
14343421Ssklower 	struct rawcb *rp = sotorawcb(so);
14443421Ssklower 	int error = 0;
14543421Ssklower 
14650234Ssklower 	if ((so->so_state & SS_PRIV) == 0) {
14743421Ssklower 		error = EACCES;
14843421Ssklower 		goto release;
14943421Ssklower 	}
15043421Ssklower 	if (rp == NULL && req != PRU_ATTACH) {
15143421Ssklower 		error = EINVAL;
15243421Ssklower 		goto release;
15343421Ssklower 	}
15443421Ssklower 
15543421Ssklower 	switch (req) {
15643421Ssklower 	case PRU_ATTACH:
15743421Ssklower 		if (rp != NULL) {
15843421Ssklower 			error = EINVAL;
15943421Ssklower 			break;
16043421Ssklower 		}
16143421Ssklower 		MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
16243421Ssklower 		if (so->so_pcb = (caddr_t)rp) {
16343421Ssklower 			bzero(so->so_pcb, sizeof(*rp));
16443421Ssklower 			insque(rp, &esis_pcb);
16544946Ssklower 			rp->rcb_socket = so;
16643421Ssklower 			error = soreserve(so, esis_sendspace, esis_recvspace);
16743421Ssklower 		} else
16843421Ssklower 			error = ENOBUFS;
16943421Ssklower 		break;
17043421Ssklower 
17143421Ssklower 	case PRU_SEND:
17243421Ssklower 		if (nam == NULL) {
17343421Ssklower 			error = EINVAL;
17443421Ssklower 			break;
17543421Ssklower 		}
17643421Ssklower 		/* error checking here */
17743421Ssklower 		error = isis_output(mtod(nam,struct sockaddr_dl *), m);
17843421Ssklower 		m = NULL;
17943421Ssklower 		break;
18043421Ssklower 
18143421Ssklower 	case PRU_DETACH:
18243421Ssklower 		raw_detach(rp);
18343421Ssklower 		break;
18443421Ssklower 
18543421Ssklower 	case PRU_SHUTDOWN:
18643421Ssklower 		socantsendmore(so);
18743421Ssklower 		break;
18843421Ssklower 
18943421Ssklower 	case PRU_ABORT:
19043421Ssklower 		soisdisconnected(so);
19143421Ssklower 		raw_detach(rp);
19243421Ssklower 		break;
19343421Ssklower 
19443421Ssklower 	case PRU_SENSE:
19543421Ssklower 		return (0);
19643421Ssklower 
19743421Ssklower 	default:
19843421Ssklower 		return (EOPNOTSUPP);
19943421Ssklower 	}
20043421Ssklower release:
20136379Ssklower 	if (m != NULL)
20236379Ssklower 		m_freem(m);
20336379Ssklower 
20443421Ssklower 	return (error);
20536379Ssklower }
20636379Ssklower 
20736379Ssklower /*
20836379Ssklower  * FUNCTION:		esis_input
20936379Ssklower  *
21036379Ssklower  * PURPOSE:			Process an incoming esis packet
21136379Ssklower  *
21236379Ssklower  * RETURNS:			nothing
21336379Ssklower  *
21436379Ssklower  * SIDE EFFECTS:
21536379Ssklower  *
21636379Ssklower  * NOTES:
21736379Ssklower  */
21836379Ssklower esis_input(m0, shp)
21936379Ssklower struct mbuf		*m0;		/* ptr to first mbuf of pkt */
22036379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
22136379Ssklower {
22243421Ssklower 	register struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
22337469Ssklower 	register int type;
22436379Ssklower 
22536379Ssklower 	/*
22636379Ssklower 	 *	check checksum if necessary
22736379Ssklower 	 */
22837469Ssklower 	if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) {
22936379Ssklower 		esis_stat.es_badcsum++;
23036379Ssklower 		goto bad;
23136379Ssklower 	}
23236379Ssklower 
23336379Ssklower 	/* check version */
23436379Ssklower 	if (pdu->esis_vers != ESIS_VERSION) {
23536379Ssklower 		esis_stat.es_badvers++;
23636379Ssklower 		goto bad;
23736379Ssklower 	}
23837469Ssklower 	type = pdu->esis_type & 0x1f;
23937469Ssklower 	switch (type) {
24036379Ssklower 		case ESIS_ESH:
24136379Ssklower 			esis_eshinput(m0, shp);
24243421Ssklower 			break;
24336379Ssklower 
24436379Ssklower 		case ESIS_ISH:
24536379Ssklower 			esis_ishinput(m0, shp);
24643421Ssklower 			break;
24736379Ssklower 
24836379Ssklower 		case ESIS_RD:
24936379Ssklower 			esis_rdinput(m0, shp);
25043421Ssklower 			break;
25136379Ssklower 
25243421Ssklower 		default:
25336379Ssklower 			esis_stat.es_badtype++;
25436379Ssklower 	}
25536379Ssklower 
25636379Ssklower bad:
25743421Ssklower 	if (esis_pcb.rcb_next != &esis_pcb)
25843421Ssklower 		isis_input(m0, shp);
25943421Ssklower 	else
26043421Ssklower 		m_freem(m0);
26136379Ssklower }
26236379Ssklower 
26336379Ssklower /*
26436379Ssklower  * FUNCTION:		esis_rdoutput
26536379Ssklower  *
26636379Ssklower  * PURPOSE:			Transmit a redirect pdu
26736379Ssklower  *
26836379Ssklower  * RETURNS:			nothing
26936379Ssklower  *
27036379Ssklower  * SIDE EFFECTS:
27136379Ssklower  *
27236379Ssklower  * NOTES:			Assumes there is enough space for fixed part of header,
27336379Ssklower  *					DA, BSNPA and NET in first mbuf.
27436379Ssklower  */
27543332Ssklower esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt)
27636379Ssklower struct snpa_hdr		*inbound_shp;	/* snpa hdr from incoming packet */
27736379Ssklower struct mbuf			*inbound_m;		/* incoming pkt itself */
27836379Ssklower struct clnp_optidx	*inbound_oidx;	/* clnp options assoc with incoming pkt */
27936379Ssklower struct iso_addr		*rd_dstnsap;	/* ultimate destination of pkt */
28043332Ssklower struct rtentry		*rt;			/* snpa cache info regarding next hop of
28136379Ssklower 										pkt */
28236379Ssklower {
28336379Ssklower 	struct mbuf			*m, *m0;
28436379Ssklower 	caddr_t				cp;
28536379Ssklower 	struct esis_fixed	*pdu;
28636379Ssklower 	int					len, total_len = 0;
28736379Ssklower 	struct sockaddr_iso	siso;
28836379Ssklower 	struct ifnet 		*ifp = inbound_shp->snh_ifp;
28943332Ssklower 	struct sockaddr_dl *sdl;
29043332Ssklower 	struct iso_addr *rd_gwnsap;
29136379Ssklower 
29243332Ssklower 	if (rt->rt_flags & RTF_GATEWAY) {
29343332Ssklower 		rd_gwnsap = &((struct sockaddr_iso *)rt->rt_gateway)->siso_addr;
29443332Ssklower 		rt = rtalloc1(rt->rt_gateway, 0);
29543332Ssklower 	} else
29643332Ssklower 		rd_gwnsap = &((struct sockaddr_iso *)rt_key(rt))->siso_addr;
29743332Ssklower 	if (rt == 0 || (sdl = (struct sockaddr_dl *)rt->rt_gateway) == 0 ||
29843332Ssklower 		sdl->sdl_family != AF_LINK) {
29943332Ssklower 		/* maybe we should have a function that you
30043332Ssklower 		   could put in the iso_ifaddr structure
30143332Ssklower 		   which could translate iso_addrs into snpa's
30243332Ssklower 		   where there is a known mapping for that address type */
30343332Ssklower 		esis_stat.es_badtype++;
30443332Ssklower 		return;
30543332Ssklower 	}
30636379Ssklower 	esis_stat.es_rdsent++;
30736379Ssklower 	IFDEBUG(D_ESISOUTPUT)
30836379Ssklower 		printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n",
30936379Ssklower 			ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m,
31036379Ssklower 			inbound_oidx);
31136379Ssklower 		printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap));
31243332Ssklower 		printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap));
31336379Ssklower 	ENDDEBUG
31436379Ssklower 
31537469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
31636379Ssklower 		esis_stat.es_nomem++;
31736379Ssklower 		return;
31836379Ssklower 	}
31937469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
32036379Ssklower 
32136379Ssklower 	pdu = mtod(m, struct esis_fixed *);
32237469Ssklower 	cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */
32336379Ssklower 	len = sizeof(struct esis_fixed);
32436379Ssklower 
32536379Ssklower 	/*
32636379Ssklower 	 *	Build fixed part of header
32736379Ssklower 	 */
32836379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
32936379Ssklower 	pdu->esis_vers = ESIS_VERSION;
33036379Ssklower 	pdu->esis_type = ESIS_RD;
33136379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time);
33236379Ssklower 
33336379Ssklower 	/* Insert destination address */
33443072Ssklower 	(void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0);
33536379Ssklower 
33636379Ssklower 	/* Insert the snpa of better next hop */
33743332Ssklower 	*cp++ = sdl->sdl_alen;
33843332Ssklower 	bcopy(LLADDR(sdl), cp, sdl->sdl_alen);
33943332Ssklower 	cp += sdl->sdl_alen;
34043332Ssklower 	len += (sdl->sdl_alen + 1);
34136379Ssklower 
34236379Ssklower 	/*
34336379Ssklower 	 *	If the next hop is not the destination, then it ought to be
34436379Ssklower 	 *	an IS and it should be inserted next. Else, set the
34536379Ssklower 	 *	NETL to 0
34636379Ssklower 	 */
34736379Ssklower 	/* PHASE2 use mask from ifp of outgoing interface */
34843332Ssklower 	if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) {
34943332Ssklower 		/* this should not happen:
35036379Ssklower 		if ((nhop_sc->sc_flags & SNPA_IS) == 0) {
35136379Ssklower 			printf("esis_rdoutput: next hop is not dst and not an IS\n");
35236379Ssklower 			m_freem(m0);
35336379Ssklower 			return;
35443332Ssklower 		} */
35543332Ssklower 		(void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0);
35636379Ssklower 	} else {
35736379Ssklower 		*cp++ = 0;	/* NETL */
35836379Ssklower 		len++;
35936379Ssklower 	}
36037469Ssklower 	m->m_len = len;
36136379Ssklower 
36236379Ssklower 	/*
36336379Ssklower 	 *	PHASE2
36436379Ssklower 	 *	If redirect is to an IS, add an address mask. The mask to be
36536379Ssklower 	 *	used should be the mask present in the routing entry used to
36636379Ssklower 	 *	forward the original data packet.
36736379Ssklower 	 */
36836379Ssklower 
36936379Ssklower 	/*
37036379Ssklower 	 *	Copy Qos, priority, or security options present in original npdu
37136379Ssklower 	 */
37236379Ssklower 	if (inbound_oidx) {
37343332Ssklower 		/* THIS CODE IS CURRENTLY (mostly) UNTESTED */
37436379Ssklower 		int optlen = 0;
37536379Ssklower 		if (inbound_oidx->cni_qos_formatp)
37636379Ssklower 			optlen += (inbound_oidx->cni_qos_len + 2);
37736379Ssklower 		if (inbound_oidx->cni_priorp)	/* priority option is 1 byte long */
37836379Ssklower 			optlen += 3;
37936379Ssklower 		if (inbound_oidx->cni_securep)
38036379Ssklower 			optlen += (inbound_oidx->cni_secure_len + 2);
38137469Ssklower 		if (M_TRAILINGSPACE(m) < optlen) {
38237469Ssklower 			EXTEND_PACKET(m, m0, cp);
38337469Ssklower 			m->m_len = 0;
38436379Ssklower 			/* assumes MLEN > optlen */
38536379Ssklower 		}
38636379Ssklower 		/* assume MLEN-len > optlen */
38736379Ssklower 		/*
38836379Ssklower 		 *	When copying options, copy from ptr - 2 in order to grab
38936379Ssklower 		 *	the option code and length
39036379Ssklower 		 */
39136379Ssklower 		if (inbound_oidx->cni_qos_formatp) {
39243332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_qos_formatp - 2,
39343332Ssklower 				cp, (unsigned)(inbound_oidx->cni_qos_len + 2));
39443332Ssklower 			cp += inbound_oidx->cni_qos_len + 2;
39536379Ssklower 		}
39636379Ssklower 		if (inbound_oidx->cni_priorp) {
39743332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_priorp - 2,
39843332Ssklower 					cp, 3);
39943332Ssklower 			cp += 3;
40036379Ssklower 		}
40136379Ssklower 		if (inbound_oidx->cni_securep) {
40243332Ssklower 			bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_securep - 2, cp,
40337469Ssklower 				(unsigned)(inbound_oidx->cni_secure_len + 2));
40443332Ssklower 			cp += inbound_oidx->cni_secure_len + 2;
40536379Ssklower 		}
40637469Ssklower 		m->m_len += optlen;
40743332Ssklower 		len += optlen;
40836379Ssklower 	}
40936379Ssklower 
41037469Ssklower 	pdu->esis_hdr_len = m0->m_pkthdr.len = len;
41136379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
41236379Ssklower 
41337469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
41436379Ssklower 	siso.siso_family = AF_ISO;
41537469Ssklower 	siso.siso_data[0] = AFI_SNA;
41637469Ssklower 	siso.siso_nlen = 6 + 1;	/* should be taken from snpa_hdr */
41736379Ssklower 										/* +1 is for AFI */
41837469Ssklower 	bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6);
41952625Ssklower 	(ifp->if_output)(ifp, m0, (struct sockaddr *)&siso, 0);
42036379Ssklower }
42136379Ssklower 
42236379Ssklower /*
42336379Ssklower  * FUNCTION:		esis_insert_addr
42436379Ssklower  *
42536379Ssklower  * PURPOSE:			Insert an iso_addr into a buffer
42636379Ssklower  *
42736379Ssklower  * RETURNS:			true if buffer was big enough, else false
42836379Ssklower  *
42936379Ssklower  * SIDE EFFECTS:	Increment buf & len according to size of iso_addr
43036379Ssklower  *
43136379Ssklower  * NOTES:			Plus 1 here is for length byte
43236379Ssklower  */
43343072Ssklower esis_insert_addr(buf, len, isoa, m, nsellen)
43443332Ssklower register caddr_t			*buf;		/* ptr to buffer to put address into */
43543332Ssklower int							*len;		/* ptr to length of buffer so far */
43643332Ssklower register struct iso_addr	*isoa;		/* ptr to address */
43743332Ssklower register struct mbuf		*m;			/* determine if there remains space */
43843332Ssklower int							nsellen;
43936379Ssklower {
44043332Ssklower 	register int newlen, result = 0;
44136379Ssklower 
44243332Ssklower 	isoa->isoa_len -= nsellen;
44343332Ssklower 	newlen = isoa->isoa_len + 1;
44443332Ssklower 	if (newlen <=  M_TRAILINGSPACE(m)) {
44543332Ssklower 		bcopy((caddr_t)isoa, *buf, newlen);
44643332Ssklower 		*len += newlen;
44743332Ssklower 		*buf += newlen;
44843332Ssklower 		m->m_len += newlen;
44943332Ssklower 		result = 1;
45043332Ssklower 	}
45143332Ssklower 	isoa->isoa_len += nsellen;
45243332Ssklower 	return (result);
45336379Ssklower }
45436379Ssklower 
45539950Ssklower #define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \
45639950Ssklower 	    if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
45739950Ssklower #define ESIS_NEXT_OPTION(b)	{ b += (2 + b[1]); \
45839950Ssklower 	    if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
45943430Ssklower int ESHonly = 0;
46036379Ssklower /*
46136379Ssklower 
46236379Ssklower /*
46336379Ssklower  * FUNCTION:		esis_eshinput
46436379Ssklower  *
46536379Ssklower  * PURPOSE:			Process an incoming ESH pdu
46636379Ssklower  *
46736379Ssklower  * RETURNS:			nothing
46836379Ssklower  *
46936379Ssklower  * SIDE EFFECTS:
47036379Ssklower  *
47136379Ssklower  * NOTES:
47236379Ssklower  */
47336379Ssklower esis_eshinput(m, shp)
47436379Ssklower struct mbuf		*m;	/* esh pdu */
47536379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
47636379Ssklower {
47743072Ssklower 	struct	esis_fixed	*pdu = mtod(m, struct esis_fixed *);
47836379Ssklower 	u_short				ht;		/* holding time */
47943072Ssklower 	struct	iso_addr	*nsap;
48039950Ssklower 	int					naddr;
48137469Ssklower 	u_char				*buf = (u_char *)(pdu + 1);
48239950Ssklower 	u_char				*buflim = pdu->esis_hdr_len + (u_char *)pdu;
48343332Ssklower 	int					new_entry = 0;
48436379Ssklower 
48536379Ssklower 	esis_stat.es_eshrcvd++;
48636379Ssklower 
48736379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
48836379Ssklower 
48939950Ssklower 	naddr = *buf++;
49039950Ssklower 	if (buf >= buflim)
49136379Ssklower 		goto bad;
49243332Ssklower 	if (naddr == 1) {
49339950Ssklower 		ESIS_EXTRACT_ADDR(nsap, buf);
49443332Ssklower 		new_entry = snpac_add(shp->snh_ifp,
49543332Ssklower 								 nsap, shp->snh_shost, SNPA_ES, ht, 0);
49643332Ssklower 	} else {
49743332Ssklower 		int nsellength = 0, nlen = 0;
49843332Ssklower 		{
49943332Ssklower 		/* See if we want to compress out multiple nsaps differing
50043332Ssklower 		   only by nsel */
50143332Ssklower 			register struct ifaddr *ifa = shp->snh_ifp->if_addrlist;
50243332Ssklower 			for (; ifa; ifa = ifa->ifa_next)
50343332Ssklower 				if (ifa->ifa_addr->sa_family == AF_ISO) {
50443332Ssklower 					nsellength = ((struct iso_ifaddr *)ifa)->ia_addr.siso_tlen;
50543332Ssklower 					break;
50643332Ssklower 			}
50743332Ssklower 		}
50839950Ssklower 		IFDEBUG(D_ESISINPUT)
50943332Ssklower 			printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n",
51043332Ssklower 					ht, naddr, nsellength);
51139950Ssklower 		ENDDEBUG
51243332Ssklower 		while (naddr-- > 0) {
51343332Ssklower 			struct iso_addr *nsap2; u_char *buf2;
51443332Ssklower 			ESIS_EXTRACT_ADDR(nsap, buf);
51543332Ssklower 			/* see if there is at least one more nsap in ESH differing
51643332Ssklower 			   only by nsel */
51743332Ssklower 			if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) {
51843332Ssklower 				ESIS_EXTRACT_ADDR(nsap2, buf2);
51943332Ssklower 				IFDEBUG(D_ESISINPUT)
52043332Ssklower 					printf("esis_eshinput: comparing %s ",
52143332Ssklower 						clnp_iso_addrp(nsap));
52243332Ssklower 					printf("and %s\n", clnp_iso_addrp(nsap2));
52343332Ssklower 				ENDDEBUG
52443332Ssklower 				if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr,
52543332Ssklower 						 nsap->isoa_len - nsellength) == 0) {
52643332Ssklower 					nlen = nsellength;
52743332Ssklower 					break;
52843332Ssklower 				}
52943332Ssklower 			}
53043332Ssklower 			new_entry |= snpac_add(shp->snh_ifp,
53143332Ssklower 									nsap, shp->snh_shost, SNPA_ES, ht, nlen);
53243332Ssklower 			nlen = 0;
53343332Ssklower 		}
53439950Ssklower 	}
53543332Ssklower 	IFDEBUG(D_ESISINPUT)
53643332Ssklower 		printf("esis_eshinput: nsap %s is %s\n",
53743332Ssklower 			clnp_iso_addrp(nsap), new_entry ? "new" : "old");
53843332Ssklower 	ENDDEBUG
53943332Ssklower 	if (new_entry && (iso_systype & SNPA_IS))
54043332Ssklower 		esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time,
54143332Ssklower 						shp->snh_shost, 6, (struct iso_addr *)0);
54237469Ssklower bad:
54339950Ssklower 	return;
54436379Ssklower }
54536379Ssklower 
54636379Ssklower /*
54736379Ssklower  * FUNCTION:		esis_ishinput
54836379Ssklower  *
54936379Ssklower  * PURPOSE:			process an incoming ISH pdu
55036379Ssklower  *
55136379Ssklower  * RETURNS:
55236379Ssklower  *
55336379Ssklower  * SIDE EFFECTS:
55436379Ssklower  *
55536379Ssklower  * NOTES:
55636379Ssklower  */
55736379Ssklower esis_ishinput(m, shp)
55836379Ssklower struct mbuf		*m;	/* esh pdu */
55936379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
56036379Ssklower {
56136379Ssklower 	struct esis_fixed	*pdu = mtod(m, struct esis_fixed *);
56243430Ssklower 	u_short				ht, newct;			/* holding time */
56339950Ssklower 	struct iso_addr		*nsap; 				/* Network Entity Title */
56439950Ssklower 	register u_char		*buf = (u_char *) (pdu + 1);
56539950Ssklower 	register u_char		*buflim = pdu->esis_hdr_len + (u_char *)pdu;
56639950Ssklower 	int					new_entry;
56736379Ssklower 
56836379Ssklower 	esis_stat.es_ishrcvd++;
56936379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
57036379Ssklower 
57136379Ssklower 	IFDEBUG(D_ESISINPUT)
57236379Ssklower 		printf("esis_ishinput: ish: ht %d\n", ht);
57336379Ssklower 	ENDDEBUG
57439950Ssklower 	if (ESHonly)
57537469Ssklower 		goto bad;
57636379Ssklower 
57739950Ssklower 	ESIS_EXTRACT_ADDR(nsap, buf);
57839950Ssklower 
57939950Ssklower 	while (buf < buflim) {
58039950Ssklower 		switch (*buf) {
58137469Ssklower 		case ESISOVAL_ESCT:
58244946Ssklower 			if (iso_systype & SNPA_IS)
58344946Ssklower 				break;
58439950Ssklower 			if (buf[1] != 2)
58537469Ssklower 				goto bad;
58643430Ssklower 			CTOH(buf[2], buf[3], newct);
58743430Ssklower 			if (esis_config_time != newct) {
58843430Ssklower 				untimeout(esis_config,0);
58943430Ssklower 				esis_config_time = newct;
59043430Ssklower 				esis_config();
59143430Ssklower 			}
59239950Ssklower 			break;
59339950Ssklower 
59439950Ssklower 		default:
59539950Ssklower 			printf("Unknown ISH option: %x\n", *buf);
59637469Ssklower 		}
59739950Ssklower 		ESIS_NEXT_OPTION(buf);
59837469Ssklower 	}
59943332Ssklower 	new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0);
60037469Ssklower 	IFDEBUG(D_ESISINPUT)
60137469Ssklower 		printf("esis_ishinput: nsap %s is %s\n",
60237469Ssklower 			clnp_iso_addrp(nsap), new_entry ? "new" : "old");
60337469Ssklower 	ENDDEBUG
60437469Ssklower 
60537469Ssklower 	if (new_entry)
60637469Ssklower 		esis_shoutput(shp->snh_ifp,
60737469Ssklower 			iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
60843332Ssklower 			esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0);
60939950Ssklower bad:
61039950Ssklower 	return;
61136379Ssklower }
61236379Ssklower 
61336379Ssklower /*
61436379Ssklower  * FUNCTION:		esis_rdinput
61536379Ssklower  *
61636379Ssklower  * PURPOSE:			Process an incoming RD pdu
61736379Ssklower  *
61836379Ssklower  * RETURNS:
61936379Ssklower  *
62036379Ssklower  * SIDE EFFECTS:
62136379Ssklower  *
62236379Ssklower  * NOTES:
62336379Ssklower  */
62436379Ssklower esis_rdinput(m0, shp)
62536379Ssklower struct mbuf		*m0;	/* esh pdu */
62636379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
62736379Ssklower {
62836379Ssklower 	struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
62936379Ssklower 	u_short				ht;		/* holding time */
63039950Ssklower 	struct iso_addr		*da, *net = 0, *netmask = 0, *snpamask = 0;
63139950Ssklower 	register struct iso_addr *bsnpa;
63239950Ssklower 	register u_char		*buf = (u_char *)(pdu + 1);
63339950Ssklower 	register u_char		*buflim = pdu->esis_hdr_len + (u_char *)pdu;
63436379Ssklower 
63536379Ssklower 	esis_stat.es_rdrcvd++;
63636379Ssklower 
63736379Ssklower 	/* intermediate systems ignore redirects */
63836379Ssklower 	if (iso_systype & SNPA_IS)
63943421Ssklower 		return;
64039950Ssklower 	if (ESHonly)
64143421Ssklower 		return;
64236379Ssklower 
64336379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
64439950Ssklower 	if (buf >= buflim)
64543421Ssklower 		return;
64636379Ssklower 
64736379Ssklower 	/* Extract DA */
64839950Ssklower 	ESIS_EXTRACT_ADDR(da, buf);
64937469Ssklower 
65036379Ssklower 	/* Extract better snpa */
65139950Ssklower 	ESIS_EXTRACT_ADDR(bsnpa, buf);
65239950Ssklower 
65337469Ssklower 	/* Extract NET if present */
65439950Ssklower 	if (buf < buflim) {
65543332Ssklower 		if (*buf == 0)
65643332Ssklower 			buf++; /* no NET present, skip NETL anyway */
65743332Ssklower 		else
65843332Ssklower 			ESIS_EXTRACT_ADDR(net, buf);
65936379Ssklower 	}
66036379Ssklower 
66137469Ssklower 	/* process options */
66239950Ssklower 	while (buf < buflim) {
66339950Ssklower 		switch (*buf) {
66437469Ssklower 		case ESISOVAL_SNPAMASK:
66537469Ssklower 			if (snpamask) /* duplicate */
66643421Ssklower 				return;
66739950Ssklower 			snpamask = (struct iso_addr *)(buf + 1);
66837469Ssklower 			break;
66937469Ssklower 
67037469Ssklower 		case ESISOVAL_NETMASK:
67137469Ssklower 			if (netmask) /* duplicate */
67243421Ssklower 				return;
67339950Ssklower 			netmask = (struct iso_addr *)(buf + 1);
67439950Ssklower 			break;
67539950Ssklower 
67639950Ssklower 		default:
67739950Ssklower 			printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]);
67837469Ssklower 		}
67939950Ssklower 		ESIS_NEXT_OPTION(buf);
68036379Ssklower 	}
68136379Ssklower 
68236379Ssklower 	IFDEBUG(D_ESISINPUT)
68337469Ssklower 		printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da));
68437469Ssklower 		if (net)
68537469Ssklower 			printf("\t: net %s\n", clnp_iso_addrp(net));
68636379Ssklower 	ENDDEBUG
68736379Ssklower 	/*
68836379Ssklower 	 *	If netl is zero, then redirect is to an ES. We need to add an entry
68936379Ssklower 	 *	to the snpa cache for (destination, better snpa).
69036379Ssklower 	 *	If netl is not zero, then the redirect is to an IS. In this
69136379Ssklower 	 *	case, add an snpa cache entry for (net, better snpa).
69236379Ssklower 	 *
69336379Ssklower 	 *	If the redirect is to an IS, add a route entry towards that
69436379Ssklower 	 *	IS.
69536379Ssklower 	 */
69639950Ssklower 	if (net == 0 || net->isoa_len == 0 || snpamask) {
69736379Ssklower 		/* redirect to an ES */
69839950Ssklower 		snpac_add(shp->snh_ifp, da,
69943332Ssklower 				bsnpa->isoa_genaddr, SNPA_ES, ht, 0);
70036379Ssklower 	} else {
70139950Ssklower 		snpac_add(shp->snh_ifp, net,
70243332Ssklower 				bsnpa->isoa_genaddr, SNPA_IS, ht, 0);
70339950Ssklower 		snpac_addrt(shp->snh_ifp, da, net, netmask);
70436379Ssklower 	}
70543421Ssklower bad: ;    /* Needed by ESIS_NEXT_OPTION */
70636379Ssklower }
70736379Ssklower 
70836379Ssklower /*
70936379Ssklower  * FUNCTION:		esis_config
71036379Ssklower  *
71136379Ssklower  * PURPOSE:			Report configuration
71236379Ssklower  *
71336379Ssklower  * RETURNS:
71436379Ssklower  *
71536379Ssklower  * SIDE EFFECTS:
71636379Ssklower  *
71736379Ssklower  * NOTES:			Called every esis_config_time seconds
71836379Ssklower  */
71958988Ssklower void
72036379Ssklower esis_config()
72136379Ssklower {
72236379Ssklower 	register struct ifnet	*ifp;
72336379Ssklower 
72436379Ssklower 	timeout(esis_config, (caddr_t)0, hz * esis_config_time);
72536379Ssklower 
72636379Ssklower 	/*
72736379Ssklower 	 *	Report configuration for each interface that
72836379Ssklower 	 *	- is UP
72948963Ssklower 	 *	- has BROADCAST capability
73036379Ssklower 	 *	- has an ISO address
73136379Ssklower 	 */
73248963Ssklower 	/* Todo: a better way would be to construct the esh or ish
73348963Ssklower 	 * once and copy it out for all devices, possibly calling
73448963Ssklower 	 * a method in the iso_ifaddr structure to encapsulate and
73548963Ssklower 	 * transmit it.  This could work to advantage for non-broadcast media
73648963Ssklower 	 */
73736379Ssklower 
73836379Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
73936379Ssklower 		if ((ifp->if_flags & IFF_UP) &&
74048963Ssklower 		    (ifp->if_flags & IFF_BROADCAST)) {
74136379Ssklower 			/* search for an ISO address family */
74236379Ssklower 			struct ifaddr	*ia;
74336379Ssklower 
74436379Ssklower 			for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {
74537469Ssklower 				if (ia->ifa_addr->sa_family == AF_ISO) {
74636379Ssklower 					esis_shoutput(ifp,
74736379Ssklower 						iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
74836379Ssklower 						esis_holding_time,
74943332Ssklower 						(caddr_t)(iso_systype & SNPA_ES ? all_is_snpa :
75043332Ssklower 						all_es_snpa), 6, (struct iso_addr *)0);
75136379Ssklower 					break;
75236379Ssklower 				}
75336379Ssklower 			}
75436379Ssklower 		}
75536379Ssklower 	}
75636379Ssklower }
75736379Ssklower 
75836379Ssklower /*
75936379Ssklower  * FUNCTION:		esis_shoutput
76036379Ssklower  *
76136379Ssklower  * PURPOSE:			Transmit an esh or ish pdu
76236379Ssklower  *
76336379Ssklower  * RETURNS:			nothing
76436379Ssklower  *
76536379Ssklower  * SIDE EFFECTS:
76636379Ssklower  *
76736379Ssklower  * NOTES:
76836379Ssklower  */
76943332Ssklower esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa)
77036379Ssklower struct ifnet	*ifp;
77136379Ssklower int				type;
77236379Ssklower short			ht;
77336379Ssklower caddr_t 		sn_addr;
77436379Ssklower int				sn_len;
77543332Ssklower struct	iso_addr *isoa;
77636379Ssklower {
77736379Ssklower 	struct mbuf			*m, *m0;
77836379Ssklower 	caddr_t				cp, naddrp;
77936379Ssklower 	int					naddr = 0;
78036379Ssklower 	struct esis_fixed	*pdu;
78143332Ssklower 	struct iso_ifaddr	*ia;
78237469Ssklower 	int					len;
78336379Ssklower 	struct sockaddr_iso	siso;
78436379Ssklower 
78536379Ssklower 	if (type == ESIS_ESH)
78636379Ssklower 		esis_stat.es_eshsent++;
78736379Ssklower 	else if (type == ESIS_ISH)
78836379Ssklower 		esis_stat.es_ishsent++;
78936379Ssklower 	else {
79036379Ssklower 		printf("esis_shoutput: bad pdu type\n");
79136379Ssklower 		return;
79236379Ssklower 	}
79336379Ssklower 
79436379Ssklower 	IFDEBUG(D_ESISOUTPUT)
79536379Ssklower 		int	i;
79636379Ssklower 		printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ",
79736379Ssklower 			ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish",
79836379Ssklower 			ht, sn_len);
79936379Ssklower 		for (i=0; i<sn_len; i++)
80036379Ssklower 			printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' ');
80136379Ssklower 		printf("\n");
80236379Ssklower 	ENDDEBUG
80336379Ssklower 
80437469Ssklower 	if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
80536379Ssklower 		esis_stat.es_nomem++;
80636379Ssklower 		return;
80736379Ssklower 	}
80837469Ssklower 	bzero(mtod(m, caddr_t), MHLEN);
80936379Ssklower 
81036379Ssklower 	pdu = mtod(m, struct esis_fixed *);
81137469Ssklower 	naddrp = cp = (caddr_t)(pdu + 1);
81236379Ssklower 	len = sizeof(struct esis_fixed);
81336379Ssklower 
81436379Ssklower 	/*
81536379Ssklower 	 *	Build fixed part of header
81636379Ssklower 	 */
81736379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
81836379Ssklower 	pdu->esis_vers = ESIS_VERSION;
81936379Ssklower 	pdu->esis_type = type;
82036379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
82136379Ssklower 
82236379Ssklower 	if (type == ESIS_ESH) {
82336379Ssklower 		cp++;
82436379Ssklower 		len++;
82536379Ssklower 	}
82636379Ssklower 
82737469Ssklower 	m->m_len = len;
82843332Ssklower 	if (isoa) {
82943332Ssklower 		/*
83043332Ssklower 		 * Here we are responding to a clnp packet sent to an NSAP
83143332Ssklower 		 * that is ours which was sent to the MAC addr all_es's.
83243332Ssklower 		 * It is possible that we did not specifically advertise this
83343332Ssklower 		 * NSAP, even though it is ours, so we will respond
83443332Ssklower 		 * directly to the sender that we are here.  If we do have
83543332Ssklower 		 * multiple NSEL's we'll tack them on so he can compress them out.
83643332Ssklower 		 */
83743332Ssklower 		(void) esis_insert_addr(&cp, &len, isoa, m, 0);
83843332Ssklower 		naddr = 1;
83943332Ssklower 	}
84043332Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
84143332Ssklower 		int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0);
84243332Ssklower 		int n = ia->ia_addr.siso_nlen;
84343332Ssklower 		register struct iso_ifaddr *ia2;
84443332Ssklower 
84543332Ssklower 		if (type == ESIS_ISH && naddr > 0)
84643332Ssklower 			break;
84743332Ssklower 		for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next)
84843332Ssklower 			if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0)
84943332Ssklower 					break;
85043332Ssklower 		if (ia2 != ia)
85143332Ssklower 			continue;	/* Means we have previously copied this nsap */
85243332Ssklower 		if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) {
85343332Ssklower 			isoa = 0;
85443332Ssklower 			continue;	/* Ditto */
85536379Ssklower 		}
85643332Ssklower 		IFDEBUG(D_ESISOUTPUT)
85743332Ssklower 			printf("esis_shoutput: adding NSAP %s\n",
85843332Ssklower 				clnp_iso_addrp(&ia->ia_addr.siso_addr));
85943332Ssklower 		ENDDEBUG
86043332Ssklower 		if (!esis_insert_addr(&cp, &len,
86143332Ssklower 							  &ia->ia_addr.siso_addr, m, nsellen)) {
86243332Ssklower 			EXTEND_PACKET(m, m0, cp);
86343332Ssklower 			(void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m,
86443332Ssklower 									nsellen);
86543332Ssklower 		}
86643332Ssklower 		naddr++;
86736379Ssklower 	}
86836379Ssklower 
86936379Ssklower 	if (type == ESIS_ESH)
87036379Ssklower 		*naddrp = naddr;
87144254Ssklower 	else {
87244254Ssklower 		/* add suggested es config timer option to ISH */
87344254Ssklower 		if (M_TRAILINGSPACE(m) < 4) {
87444254Ssklower 			printf("esis_shoutput: extending packet\n");
87544254Ssklower 			EXTEND_PACKET(m, m0, cp);
87644254Ssklower 		}
87744254Ssklower 		*cp++ = ESISOVAL_ESCT;
87844254Ssklower 		*cp++ = 2;
87944254Ssklower 		HTOC(*cp, *(cp+1), esis_esconfig_time);
88044254Ssklower 		len += 4;
88144254Ssklower 		m->m_len += 4;
88244254Ssklower 		IFDEBUG(D_ESISOUTPUT)
88344254Ssklower 			printf("m0 0x%x, m 0x%x, data 0x%x, len %d, cp 0x%x\n",
88444254Ssklower 			m0, m, m->m_data, m->m_len, cp);
88544254Ssklower 		ENDDEBUG
88644254Ssklower 	}
88736379Ssklower 
88837469Ssklower 	m0->m_pkthdr.len = len;
88937469Ssklower 	pdu->esis_hdr_len = len;
89036379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
89136379Ssklower 
89237469Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
89336379Ssklower 	siso.siso_family = AF_ISO;
89437469Ssklower 	siso.siso_data[0] = AFI_SNA;
89537469Ssklower 	siso.siso_nlen = sn_len + 1;
89637469Ssklower 	bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len);
89752625Ssklower 	(ifp->if_output)(ifp, m0, (struct sockaddr *)&siso, 0);
89836379Ssklower }
89936379Ssklower 
90036379Ssklower /*
90143421Ssklower  * FUNCTION:		isis_input
90243421Ssklower  *
90343421Ssklower  * PURPOSE:			Process an incoming isis packet
90443421Ssklower  *
90543421Ssklower  * RETURNS:			nothing
90643421Ssklower  *
90743421Ssklower  * SIDE EFFECTS:
90843421Ssklower  *
90943421Ssklower  * NOTES:
91043421Ssklower  */
91143421Ssklower isis_input(m0, shp)
91243421Ssklower struct mbuf		*m0;		/* ptr to first mbuf of pkt */
91343421Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
91443421Ssklower {
91543421Ssklower 	register int type;
91643961Ssklower 	register struct rawcb *rp, *first_rp = 0;
91743421Ssklower 	struct ifnet *ifp = shp->snh_ifp;
91843421Ssklower 	char workbuf[16];
91943421Ssklower 	struct mbuf *mm;
92043421Ssklower 
92143421Ssklower 	IFDEBUG(D_ISISINPUT)
92243421Ssklower 		int i;
92343421Ssklower 
92443421Ssklower 		printf("isis_input: pkt on ifp x%x (%s%d): from:", ifp,
92543421Ssklower 			ifp->if_name, ifp->if_unit);
92643421Ssklower 		for (i=0; i<6; i++)
92743421Ssklower 			printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' ');
92843421Ssklower 		printf(" to:");
92943421Ssklower 		for (i=0; i<6; i++)
93043421Ssklower 			printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' ');
93143421Ssklower 		printf("\n");
93243421Ssklower 	ENDDEBUG
93343421Ssklower 	esis_dl.sdl_alen = ifp->if_addrlen;
93443421Ssklower 	esis_dl.sdl_index = ifp->if_index;
93543421Ssklower 	bcopy(shp->snh_shost, (caddr_t)esis_dl.sdl_data, esis_dl.sdl_alen);
93643421Ssklower 	for (rp = esis_pcb.rcb_next; rp != &esis_pcb; rp = rp->rcb_next) {
93743961Ssklower 		if (first_rp == 0) {
93843961Ssklower 			first_rp = rp;
93943421Ssklower 			continue;
94043421Ssklower 		}
94143421Ssklower 		if (mm = m_copy(m0, 0, M_COPYALL)) { /*can't block at interrupt level */
94243421Ssklower 			if (sbappendaddr(&rp->rcb_socket->so_rcv,
94352114Ssklower 							  &esis_dl, mm, (struct mbuf *)0) != 0) {
94443421Ssklower 				sorwakeup(rp->rcb_socket);
94552114Ssklower 			 } else {
94643421Ssklower 				IFDEBUG(D_ISISINPUT)
94743421Ssklower 					printf("Error in sbappenaddr, mm = 0x%x\n", mm);
94843421Ssklower 				ENDDEBUG
94943421Ssklower 				m_freem(mm);
95043421Ssklower 			}
95143421Ssklower 		}
95243421Ssklower 	}
95343961Ssklower 	if (first_rp && sbappendaddr(&first_rp->rcb_socket->so_rcv,
95444946Ssklower 							  &esis_dl, m0, (struct mbuf *)0) != 0) {
95543961Ssklower 		sorwakeup(first_rp->rcb_socket);
95643961Ssklower 		return;
95743421Ssklower 	}
95843961Ssklower 	m_freem(m0);
95943421Ssklower }
96043421Ssklower 
96143421Ssklower isis_output(sdl, m)
96243421Ssklower register struct sockaddr_dl	*sdl;
96343421Ssklower struct mbuf *m;
96443421Ssklower {
96543421Ssklower 	register struct ifnet *ifp;
96643421Ssklower 	struct ifaddr *ifa, *ifa_ifwithnet();
96743421Ssklower 	struct sockaddr_iso siso;
96843421Ssklower 	int error = 0;
96943421Ssklower 	unsigned sn_len;
97043421Ssklower 
97152625Ssklower 	ifa = ifa_ifwithnet((struct sockaddr *)sdl);	/* get ifp from sdl */
97243421Ssklower 	if (ifa == 0) {
97343421Ssklower 		IFDEBUG(D_ISISOUTPUT)
97443421Ssklower 			printf("isis_output: interface not found\n");
97543421Ssklower 		ENDDEBUG
97643421Ssklower 		error = EINVAL;
97743421Ssklower 		goto release;
97843421Ssklower 	}
97943421Ssklower 	ifp = ifa->ifa_ifp;
98045896Ssklower 	sn_len = sdl->sdl_alen;
98143421Ssklower 	IFDEBUG(D_ISISOUTPUT)
98243421Ssklower 		u_char *cp = (u_char *)LLADDR(sdl), *cplim = cp + sn_len;
98343421Ssklower 		printf("isis_output: ifp 0x%x (%s%d), to: ",
98443421Ssklower 			ifp, ifp->if_name, ifp->if_unit);
98543421Ssklower 		while (cp < cplim) {
98643421Ssklower 			printf("%x", *cp++);
98743421Ssklower 			printf("%c", (cp < cplim) ? ':' : ' ');
98843421Ssklower 		}
98943421Ssklower 		printf("\n");
99043421Ssklower 	ENDDEBUG
99143421Ssklower 	bzero((caddr_t)&siso, sizeof(siso));
99243421Ssklower 	siso.siso_family = AF_ISO; /* This convention may be useful for X.25 */
99343421Ssklower 	siso.siso_data[0] = AFI_SNA;
99443421Ssklower 	siso.siso_nlen = sn_len + 1;
99543421Ssklower 	bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len);
99643421Ssklower 	error = (ifp->if_output)(ifp, m, (struct sockaddr *)&siso, 0);
99743421Ssklower 	if (error) {
99843421Ssklower 		IFDEBUG(D_ISISOUTPUT)
99943421Ssklower 			printf("isis_output: error from ether_output is %d\n", error);
100043421Ssklower 		ENDDEBUG
100143421Ssklower 	}
100243421Ssklower 	return (error);
100343421Ssklower 
100443421Ssklower release:
100543421Ssklower 	if (m != NULL)
100643421Ssklower 		m_freem(m);
100743421Ssklower 	return(error);
100843421Ssklower }
100943421Ssklower 
101043421Ssklower 
101143421Ssklower /*
101236379Ssklower  * FUNCTION:		esis_ctlinput
101336379Ssklower  *
101436379Ssklower  * PURPOSE:			Handle the PRC_IFDOWN transition
101536379Ssklower  *
101636379Ssklower  * RETURNS:			nothing
101736379Ssklower  *
101836379Ssklower  * SIDE EFFECTS:
101936379Ssklower  *
102036379Ssklower  * NOTES:			Calls snpac_flush for interface specified.
102136379Ssklower  *					The loop through iso_ifaddr is stupid because
102236379Ssklower  *					back in if_down, we knew the ifp...
102336379Ssklower  */
102436379Ssklower esis_ctlinput(req, siso)
102536379Ssklower int						req;		/* request: we handle only PRC_IFDOWN */
102636379Ssklower struct sockaddr_iso		*siso;		/* address of ifp */
102736379Ssklower {
102836379Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
102936379Ssklower 
103037469Ssklower 	if (req == PRC_IFDOWN)
103137469Ssklower 		for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
103237469Ssklower 			if (iso_addrmatch(IA_SIS(ia), siso))
103337469Ssklower 				snpac_flushifp(ia->ia_ifp);
103437469Ssklower 		}
103536379Ssklower }
103636379Ssklower 
1037*61300Ssklower #endif	/* ISO */
1038