xref: /csrg-svn/sys/netiso/esis.c (revision 36379)
1*36379Ssklower /***********************************************************
2*36379Ssklower 		Copyright IBM Corporation 1987
3*36379Ssklower 
4*36379Ssklower                       All Rights Reserved
5*36379Ssklower 
6*36379Ssklower Permission to use, copy, modify, and distribute this software and its
7*36379Ssklower documentation for any purpose and without fee is hereby granted,
8*36379Ssklower provided that the above copyright notice appear in all copies and that
9*36379Ssklower both that copyright notice and this permission notice appear in
10*36379Ssklower supporting documentation, and that the name of IBM not be
11*36379Ssklower used in advertising or publicity pertaining to distribution of the
12*36379Ssklower software without specific, written prior permission.
13*36379Ssklower 
14*36379Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15*36379Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16*36379Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17*36379Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18*36379Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19*36379Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*36379Ssklower SOFTWARE.
21*36379Ssklower 
22*36379Ssklower ******************************************************************/
23*36379Ssklower 
24*36379Ssklower /*
25*36379Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26*36379Ssklower  */
27*36379Ssklower #ifndef lint
28*36379Ssklower static char *rcsid = "$Header: esis.c,v 4.10 88/09/15 18:57:03 hagens Exp $";
29*36379Ssklower #endif
30*36379Ssklower 
31*36379Ssklower #ifdef ISO
32*36379Ssklower 
33*36379Ssklower #include "../h/types.h"
34*36379Ssklower #include "../h/param.h"
35*36379Ssklower #include "../h/mbuf.h"
36*36379Ssklower #include "../h/domain.h"
37*36379Ssklower #include "../h/protosw.h"
38*36379Ssklower #include "../h/dir.h"
39*36379Ssklower #include "../h/user.h"
40*36379Ssklower #include "../h/socket.h"
41*36379Ssklower #include "../h/socketvar.h"
42*36379Ssklower #include "../h/errno.h"
43*36379Ssklower #include "../h/kernel.h"
44*36379Ssklower 
45*36379Ssklower #include "../net/if.h"
46*36379Ssklower #include "../net/route.h"
47*36379Ssklower 
48*36379Ssklower #include "../netiso/iso.h"
49*36379Ssklower #include "../netiso/iso_pcb.h"
50*36379Ssklower #include "../netiso/iso_var.h"
51*36379Ssklower #include "../netiso/iso_snpac.h"
52*36379Ssklower #include "../netiso/clnl.h"
53*36379Ssklower #include "../netiso/clnp.h"
54*36379Ssklower #include "../netiso/clnp_stat.h"
55*36379Ssklower #include "../netiso/argo_debug.h"
56*36379Ssklower #include "../netiso/esis.h"
57*36379Ssklower 
58*36379Ssklower /*
59*36379Ssklower  *	Global variables to esis implementation
60*36379Ssklower  *
61*36379Ssklower  *	esis_holding_time - the holding time (sec) parameter for outgoing pdus
62*36379Ssklower  *	esis_config_time  - the frequency (sec) that hellos are generated
63*36379Ssklower  *
64*36379Ssklower  */
65*36379Ssklower struct isopcb	esis_pcb;
66*36379Ssklower int				esis_sendspace = 2048;
67*36379Ssklower int				esis_recvspace = 2048;
68*36379Ssklower short			esis_holding_time = ESIS_HT;
69*36379Ssklower short			esis_config_time = ESIS_CONFIG;
70*36379Ssklower extern int		iso_systype;
71*36379Ssklower extern struct snpa_cache	all_es, all_is;
72*36379Ssklower 
73*36379Ssklower #define EXTEND_PACKET(m, mhdr, len, cp)\
74*36379Ssklower 	if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\
75*36379Ssklower 		esis_stat.es_nomem++;\
76*36379Ssklower 		m_freem(mhdr);\
77*36379Ssklower 		return;\
78*36379Ssklower 	} else {\
79*36379Ssklower 		(m)->m_len = (len);\
80*36379Ssklower 		(m) = (m)->m_next;\
81*36379Ssklower 		(len) = 0;\
82*36379Ssklower 		(cp) = mtod((m), caddr_t);\
83*36379Ssklower 	}
84*36379Ssklower /*
85*36379Ssklower  * FUNCTION:		esis_init
86*36379Ssklower  *
87*36379Ssklower  * PURPOSE:			Initialize the kernel portion of esis protocol
88*36379Ssklower  *
89*36379Ssklower  * RETURNS:			nothing
90*36379Ssklower  *
91*36379Ssklower  * SIDE EFFECTS:
92*36379Ssklower  *
93*36379Ssklower  * NOTES:
94*36379Ssklower  */
95*36379Ssklower esis_init()
96*36379Ssklower {
97*36379Ssklower 	extern struct clnl_protosw clnl_protox[256];
98*36379Ssklower 	int esis_input();
99*36379Ssklower 	int snpac_age();
100*36379Ssklower 	int	esis_config();
101*36379Ssklower #ifdef	ISO_X25ESIS
102*36379Ssklower 	x25esis_input();
103*36379Ssklower #endif	ISO_X25ESIS
104*36379Ssklower 
105*36379Ssklower 	esis_pcb.isop_next = esis_pcb.isop_prev = &esis_pcb;
106*36379Ssklower 
107*36379Ssklower 	clnl_protox[ISO9542_ESIS].clnl_input = esis_input;
108*36379Ssklower 	timeout(snpac_age, (caddr_t)0, hz);
109*36379Ssklower 	timeout(esis_config, (caddr_t)0, hz);
110*36379Ssklower 
111*36379Ssklower #ifdef	ISO_X25ESIS
112*36379Ssklower 	clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input;
113*36379Ssklower #endif	ISO_X25ESIS
114*36379Ssklower }
115*36379Ssklower 
116*36379Ssklower /*
117*36379Ssklower  * FUNCTION:		esis_usrreq
118*36379Ssklower  *
119*36379Ssklower  * PURPOSE:			Handle user level esis requests
120*36379Ssklower  *
121*36379Ssklower  * RETURNS:			0 or appropriate errno
122*36379Ssklower  *
123*36379Ssklower  * SIDE EFFECTS:
124*36379Ssklower  *
125*36379Ssklower  * NOTES:			This is here only so esis gets initialized.
126*36379Ssklower  */
127*36379Ssklower esis_usrreq(so, req, m, nam, rights)
128*36379Ssklower struct socket	*so;		/* socket: used only to get to this code */
129*36379Ssklower int				req;		/* request */
130*36379Ssklower struct mbuf		*m;			/* data for request */
131*36379Ssklower struct mbuf		*nam;		/* optional name */
132*36379Ssklower struct mbuf		*rights;	/* optional rights */
133*36379Ssklower {
134*36379Ssklower 	if (m != NULL)
135*36379Ssklower 		m_freem(m);
136*36379Ssklower 
137*36379Ssklower 	return(EOPNOTSUPP);
138*36379Ssklower }
139*36379Ssklower 
140*36379Ssklower /*
141*36379Ssklower  * FUNCTION:		esis_input
142*36379Ssklower  *
143*36379Ssklower  * PURPOSE:			Process an incoming esis packet
144*36379Ssklower  *
145*36379Ssklower  * RETURNS:			nothing
146*36379Ssklower  *
147*36379Ssklower  * SIDE EFFECTS:
148*36379Ssklower  *
149*36379Ssklower  * NOTES:
150*36379Ssklower  */
151*36379Ssklower esis_input(m0, shp)
152*36379Ssklower struct mbuf		*m0;		/* ptr to first mbuf of pkt */
153*36379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
154*36379Ssklower {
155*36379Ssklower 	struct isopcb		*isop;
156*36379Ssklower 	struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
157*36379Ssklower 
158*36379Ssklower 	IFDEBUG(D_ESISINPUT)
159*36379Ssklower 		int i;
160*36379Ssklower 
161*36379Ssklower 		printf("esis_input: pdu on ifp x%x (%s%d): from:", shp->snh_ifp,
162*36379Ssklower 			shp->snh_ifp->if_name, shp->snh_ifp->if_unit);
163*36379Ssklower 		for (i=0; i<6; i++)
164*36379Ssklower 			printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' ');
165*36379Ssklower 		printf(" to:");
166*36379Ssklower 		for (i=0; i<6; i++)
167*36379Ssklower 			printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' ');
168*36379Ssklower 		printf("\n");
169*36379Ssklower 	ENDDEBUG
170*36379Ssklower 
171*36379Ssklower 	/*
172*36379Ssklower 	 *	check checksum if necessary
173*36379Ssklower 	 */
174*36379Ssklower 	if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, pdu->esis_hdr_len)) {
175*36379Ssklower 		esis_stat.es_badcsum++;
176*36379Ssklower 		goto bad;
177*36379Ssklower 	}
178*36379Ssklower 
179*36379Ssklower 	/* check version */
180*36379Ssklower 	if (pdu->esis_vers != ESIS_VERSION) {
181*36379Ssklower 		esis_stat.es_badvers++;
182*36379Ssklower 		goto bad;
183*36379Ssklower 	}
184*36379Ssklower 
185*36379Ssklower 	switch(pdu->esis_type) {
186*36379Ssklower 		case ESIS_ESH:
187*36379Ssklower 			esis_eshinput(m0, shp);
188*36379Ssklower 			return;
189*36379Ssklower 
190*36379Ssklower 		case ESIS_ISH:
191*36379Ssklower 			esis_ishinput(m0, shp);
192*36379Ssklower 			return;
193*36379Ssklower 
194*36379Ssklower 		case ESIS_RD:
195*36379Ssklower 			esis_rdinput(m0, shp);
196*36379Ssklower 			return;
197*36379Ssklower 
198*36379Ssklower 		default: {
199*36379Ssklower 			esis_stat.es_badtype++;
200*36379Ssklower 			goto bad;
201*36379Ssklower 		}
202*36379Ssklower 	}
203*36379Ssklower 
204*36379Ssklower bad:
205*36379Ssklower 	m_freem(m0);
206*36379Ssklower }
207*36379Ssklower 
208*36379Ssklower /*
209*36379Ssklower  * FUNCTION:		esis_rdoutput
210*36379Ssklower  *
211*36379Ssklower  * PURPOSE:			Transmit a redirect pdu
212*36379Ssklower  *
213*36379Ssklower  * RETURNS:			nothing
214*36379Ssklower  *
215*36379Ssklower  * SIDE EFFECTS:
216*36379Ssklower  *
217*36379Ssklower  * NOTES:			Assumes there is enough space for fixed part of header,
218*36379Ssklower  *					DA, BSNPA and NET in first mbuf.
219*36379Ssklower  */
220*36379Ssklower esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, nhop_sc)
221*36379Ssklower struct snpa_hdr		*inbound_shp;	/* snpa hdr from incoming packet */
222*36379Ssklower struct mbuf			*inbound_m;		/* incoming pkt itself */
223*36379Ssklower struct clnp_optidx	*inbound_oidx;	/* clnp options assoc with incoming pkt */
224*36379Ssklower struct iso_addr		*rd_dstnsap;	/* ultimate destination of pkt */
225*36379Ssklower struct snpa_cache	*nhop_sc;		/* snpa cache info regarding next hop of
226*36379Ssklower 										pkt */
227*36379Ssklower {
228*36379Ssklower 	struct mbuf			*m, *m0;
229*36379Ssklower 	caddr_t				cp;
230*36379Ssklower 	struct esis_fixed	*pdu;
231*36379Ssklower 	int					len, total_len = 0;
232*36379Ssklower 	struct sockaddr_iso	siso;
233*36379Ssklower 	struct ifnet 		*ifp = inbound_shp->snh_ifp;
234*36379Ssklower 
235*36379Ssklower 	esis_stat.es_rdsent++;
236*36379Ssklower 
237*36379Ssklower 	IFDEBUG(D_ESISOUTPUT)
238*36379Ssklower 		int	i;
239*36379Ssklower 		printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n",
240*36379Ssklower 			ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m,
241*36379Ssklower 			inbound_oidx);
242*36379Ssklower 		printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap));
243*36379Ssklower 		printf("\tredirected toward:%s\n", clnp_iso_addrp(&nhop_sc->sc_nsap));
244*36379Ssklower 	ENDDEBUG
245*36379Ssklower 
246*36379Ssklower 	if ((m0 = m = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {
247*36379Ssklower 		esis_stat.es_nomem++;
248*36379Ssklower 		return;
249*36379Ssklower 	}
250*36379Ssklower 
251*36379Ssklower 	pdu = mtod(m, struct esis_fixed *);
252*36379Ssklower 	cp = (caddr_t)pdu + sizeof(struct esis_fixed);
253*36379Ssklower 	len = sizeof(struct esis_fixed);
254*36379Ssklower 
255*36379Ssklower 	/*
256*36379Ssklower 	 *	Build fixed part of header
257*36379Ssklower 	 */
258*36379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
259*36379Ssklower 	pdu->esis_vers = ESIS_VERSION;
260*36379Ssklower 	pdu->esis_type = ESIS_RD;
261*36379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time);
262*36379Ssklower 
263*36379Ssklower 	/* Insert destination address */
264*36379Ssklower 	(void) esis_insert_addr(&cp, &len, rd_dstnsap, MLEN - len);
265*36379Ssklower 
266*36379Ssklower 	/* Insert the snpa of better next hop */
267*36379Ssklower 	*cp++ = nhop_sc->sc_len;
268*36379Ssklower 	bcopy(nhop_sc->sc_snpa, cp, nhop_sc->sc_len);
269*36379Ssklower 	len += (nhop_sc->sc_len + 1);
270*36379Ssklower 
271*36379Ssklower 	/*
272*36379Ssklower 	 *	If the next hop is not the destination, then it ought to be
273*36379Ssklower 	 *	an IS and it should be inserted next. Else, set the
274*36379Ssklower 	 *	NETL to 0
275*36379Ssklower 	 */
276*36379Ssklower 	/* PHASE2 use mask from ifp of outgoing interface */
277*36379Ssklower 	if (!iso_addrmatch1(rd_dstnsap, &nhop_sc->sc_nsap)) {
278*36379Ssklower 		if ((nhop_sc->sc_flags & SNPA_IS) == 0) {
279*36379Ssklower 			/* this should not happen */
280*36379Ssklower 			printf("esis_rdoutput: next hop is not dst and not an IS\n");
281*36379Ssklower 			m_freem(m0);
282*36379Ssklower 			return;
283*36379Ssklower 		}
284*36379Ssklower 		(void) esis_insert_addr(&cp, &len, &nhop_sc->sc_nsap, MLEN - len);
285*36379Ssklower 	} else {
286*36379Ssklower 		*cp++ = 0;	/* NETL */
287*36379Ssklower 		len++;
288*36379Ssklower 	}
289*36379Ssklower 
290*36379Ssklower 	/*
291*36379Ssklower 	 *	PHASE2
292*36379Ssklower 	 *	If redirect is to an IS, add an address mask. The mask to be
293*36379Ssklower 	 *	used should be the mask present in the routing entry used to
294*36379Ssklower 	 *	forward the original data packet.
295*36379Ssklower 	 */
296*36379Ssklower 
297*36379Ssklower 	/*
298*36379Ssklower 	 *	Copy Qos, priority, or security options present in original npdu
299*36379Ssklower 	 */
300*36379Ssklower 	if (inbound_oidx) {
301*36379Ssklower 		/* THIS CODE IS CURRENTLY UNTESTED */
302*36379Ssklower 		int optlen = 0;
303*36379Ssklower 		if (inbound_oidx->cni_qos_formatp)
304*36379Ssklower 			optlen += (inbound_oidx->cni_qos_len + 2);
305*36379Ssklower 		if (inbound_oidx->cni_priorp)	/* priority option is 1 byte long */
306*36379Ssklower 			optlen += 3;
307*36379Ssklower 		if (inbound_oidx->cni_securep)
308*36379Ssklower 			optlen += (inbound_oidx->cni_secure_len + 2);
309*36379Ssklower 		if (MLEN-len < optlen) {
310*36379Ssklower 			total_len += len;
311*36379Ssklower 			EXTEND_PACKET(m, m0, len, cp);
312*36379Ssklower 			/* assumes MLEN > optlen */
313*36379Ssklower 		}
314*36379Ssklower 		/* assume MLEN-len > optlen */
315*36379Ssklower 		/*
316*36379Ssklower 		 *	When copying options, copy from ptr - 2 in order to grab
317*36379Ssklower 		 *	the option code and length
318*36379Ssklower 		 */
319*36379Ssklower 		if (inbound_oidx->cni_qos_formatp) {
320*36379Ssklower 			bcopy(inbound_m + inbound_oidx->cni_qos_formatp - 2, cp,
321*36379Ssklower 				inbound_oidx->cni_qos_len + 2);
322*36379Ssklower 			len += inbound_oidx->cni_qos_len + 2;
323*36379Ssklower 		}
324*36379Ssklower 		if (inbound_oidx->cni_priorp) {
325*36379Ssklower 			bcopy(inbound_m + inbound_oidx->cni_priorp - 2, cp, 3);
326*36379Ssklower 			len += 3;
327*36379Ssklower 		}
328*36379Ssklower 		if (inbound_oidx->cni_securep) {
329*36379Ssklower 			bcopy(inbound_m + inbound_oidx->cni_securep - 2, cp,
330*36379Ssklower 				inbound_oidx->cni_secure_len + 2);
331*36379Ssklower 			len += inbound_oidx->cni_secure_len + 2;
332*36379Ssklower 		}
333*36379Ssklower 	}
334*36379Ssklower 
335*36379Ssklower 	m->m_len = len;
336*36379Ssklower 	total_len += len;
337*36379Ssklower 	pdu->esis_hdr_len = total_len;
338*36379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
339*36379Ssklower 
340*36379Ssklower 	siso.siso_family = AF_ISO;
341*36379Ssklower 	siso.siso_addr.isoa_afi = AFI_SNA;
342*36379Ssklower 	siso.siso_addr.isoa_len = 6 + 1;	/* should be taken from snpa_hdr */
343*36379Ssklower 										/* +1 is for AFI */
344*36379Ssklower 	bcopy(inbound_shp->snh_shost, siso.siso_addr.sna_idi, 6);
345*36379Ssklower 	(ifp->if_output)(ifp, m0, &siso);
346*36379Ssklower }
347*36379Ssklower 
348*36379Ssklower /*
349*36379Ssklower  * FUNCTION:		esis_extract_addr
350*36379Ssklower  *
351*36379Ssklower  * PURPOSE:			Remove an addr from a buffer, and stuff in iso_addr
352*36379Ssklower  *
353*36379Ssklower  * RETURNS:			true if the address was complete, else false
354*36379Ssklower  *
355*36379Ssklower  * SIDE EFFECTS:	Increment buf and decrement len according to the
356*36379Ssklower  *					size of the iso_addr
357*36379Ssklower  *
358*36379Ssklower  * NOTES:
359*36379Ssklower  */
360*36379Ssklower esis_extract_addr(buf, isoa, len)
361*36379Ssklower caddr_t			*buf;		/* ptr to buffer to put address into */
362*36379Ssklower struct iso_addr	*isoa;		/* ptr to address */
363*36379Ssklower int				*len;		/* ptr to length of buffer */
364*36379Ssklower {
365*36379Ssklower 	caddr_t		bp = *buf;
366*36379Ssklower 
367*36379Ssklower 	if (*len <= 0)
368*36379Ssklower 		return(0);
369*36379Ssklower 
370*36379Ssklower 	bzero((caddr_t)isoa, sizeof (struct iso_addr));
371*36379Ssklower 	isoa->isoa_len = *bp++;
372*36379Ssklower 	*len -= 1;
373*36379Ssklower 	if (isoa->isoa_len > *len)
374*36379Ssklower 		return(0);	/* too big */
375*36379Ssklower 	bcopy(bp, (caddr_t)isoa, isoa->isoa_len);
376*36379Ssklower 	*len -= isoa->isoa_len;
377*36379Ssklower 	bp += isoa->isoa_len;
378*36379Ssklower 	*buf = bp;
379*36379Ssklower 
380*36379Ssklower 	return(1);
381*36379Ssklower }
382*36379Ssklower 
383*36379Ssklower /*
384*36379Ssklower  * FUNCTION:		esis_insert_addr
385*36379Ssklower  *
386*36379Ssklower  * PURPOSE:			Insert an iso_addr into a buffer
387*36379Ssklower  *
388*36379Ssklower  * RETURNS:			true if buffer was big enough, else false
389*36379Ssklower  *
390*36379Ssklower  * SIDE EFFECTS:	Increment buf & len according to size of iso_addr
391*36379Ssklower  *
392*36379Ssklower  * NOTES:			Plus 1 here is for length byte
393*36379Ssklower  */
394*36379Ssklower esis_insert_addr(buf, len, isoa, remaining)
395*36379Ssklower caddr_t			*buf;		/* ptr to buffer to put address into */
396*36379Ssklower int				*len;		/* ptr to length of buffer so far */
397*36379Ssklower struct iso_addr	*isoa;		/* ptr to address */
398*36379Ssklower int				remaining;	/* length of buffer */
399*36379Ssklower {
400*36379Ssklower 	caddr_t		bp = *buf;
401*36379Ssklower 
402*36379Ssklower 	if ((isoa->isoa_len+1) > remaining)
403*36379Ssklower 		return(0);
404*36379Ssklower 	*bp++ = isoa->isoa_len;
405*36379Ssklower 	*len += 1;
406*36379Ssklower 	bcopy((caddr_t)isoa, bp, isoa->isoa_len);
407*36379Ssklower 	bp += isoa->isoa_len;
408*36379Ssklower 	*len += isoa->isoa_len;
409*36379Ssklower 	*buf = bp;
410*36379Ssklower 	return(1);
411*36379Ssklower }
412*36379Ssklower 
413*36379Ssklower /*
414*36379Ssklower 
415*36379Ssklower /*
416*36379Ssklower  * FUNCTION:		esis_eshinput
417*36379Ssklower  *
418*36379Ssklower  * PURPOSE:			Process an incoming ESH pdu
419*36379Ssklower  *
420*36379Ssklower  * RETURNS:			nothing
421*36379Ssklower  *
422*36379Ssklower  * SIDE EFFECTS:
423*36379Ssklower  *
424*36379Ssklower  * NOTES:
425*36379Ssklower  */
426*36379Ssklower esis_eshinput(m, shp)
427*36379Ssklower struct mbuf		*m;	/* esh pdu */
428*36379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
429*36379Ssklower {
430*36379Ssklower 	struct esis_fixed	*pdu = mtod(m, struct esis_fixed *);
431*36379Ssklower 	u_short				ht;		/* holding time */
432*36379Ssklower 	struct iso_addr		nsap;
433*36379Ssklower 	int					naddr;
434*36379Ssklower 	caddr_t				buf = (caddr_t)pdu + sizeof(struct esis_fixed);
435*36379Ssklower 	int					len = pdu->esis_hdr_len - sizeof(struct esis_fixed);
436*36379Ssklower 
437*36379Ssklower 	esis_stat.es_eshrcvd++;
438*36379Ssklower 
439*36379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
440*36379Ssklower 
441*36379Ssklower 	if (len > 0) {
442*36379Ssklower 		naddr = *buf++;
443*36379Ssklower 		len--;
444*36379Ssklower 	} else
445*36379Ssklower 		goto bad;
446*36379Ssklower 
447*36379Ssklower 	IFDEBUG(D_ESISINPUT)
448*36379Ssklower 		printf("esis_eshinput: esh: ht %d, naddr %d\n", ht, naddr);
449*36379Ssklower 	ENDDEBUG
450*36379Ssklower 
451*36379Ssklower 	while (naddr-- > 0) {
452*36379Ssklower 		if (esis_extract_addr(&buf, &nsap, &len)) {
453*36379Ssklower 			int new_entry = (snpac_look(&nsap) == NULL);
454*36379Ssklower 
455*36379Ssklower 			IFDEBUG(D_ESISINPUT)
456*36379Ssklower 				printf("esis_eshinput: nsap %s is %s\n",
457*36379Ssklower 					clnp_iso_addrp(&nsap), new_entry ? "new" : "old");
458*36379Ssklower 			ENDDEBUG
459*36379Ssklower 
460*36379Ssklower 			snpac_add(shp->snh_ifp, &nsap, shp->snh_shost, 6, SNPA_ES, ht);
461*36379Ssklower 			if (new_entry)
462*36379Ssklower 				esis_shoutput(shp->snh_ifp,
463*36379Ssklower 					iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
464*36379Ssklower 					esis_holding_time, shp->snh_shost, 6);
465*36379Ssklower 		} else {
466*36379Ssklower 			esis_stat.es_toosmall++;
467*36379Ssklower 			break;
468*36379Ssklower 		}
469*36379Ssklower 	}
470*36379Ssklower 
471*36379Ssklower bad:
472*36379Ssklower 	m_freem(m);
473*36379Ssklower }
474*36379Ssklower 
475*36379Ssklower /*
476*36379Ssklower  * FUNCTION:		esis_ishinput
477*36379Ssklower  *
478*36379Ssklower  * PURPOSE:			process an incoming ISH pdu
479*36379Ssklower  *
480*36379Ssklower  * RETURNS:
481*36379Ssklower  *
482*36379Ssklower  * SIDE EFFECTS:
483*36379Ssklower  *
484*36379Ssklower  * NOTES:
485*36379Ssklower  */
486*36379Ssklower esis_ishinput(m, shp)
487*36379Ssklower struct mbuf		*m;	/* esh pdu */
488*36379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
489*36379Ssklower {
490*36379Ssklower 	struct esis_fixed	*pdu = mtod(m, struct esis_fixed *);
491*36379Ssklower 	u_short				ht;		/* holding time */
492*36379Ssklower 	struct iso_addr		nsap;
493*36379Ssklower 	caddr_t				buf = (caddr_t)pdu + sizeof(struct esis_fixed);
494*36379Ssklower 	int					len = pdu->esis_hdr_len - sizeof(struct esis_fixed);
495*36379Ssklower 
496*36379Ssklower 	esis_stat.es_ishrcvd++;
497*36379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
498*36379Ssklower 
499*36379Ssklower 	IFDEBUG(D_ESISINPUT)
500*36379Ssklower 		printf("esis_ishinput: ish: ht %d\n", ht);
501*36379Ssklower 	ENDDEBUG
502*36379Ssklower 
503*36379Ssklower 	if (esis_extract_addr(&buf, &nsap, &len)) {
504*36379Ssklower 		int new_entry = (snpac_look(&nsap) == NULL);
505*36379Ssklower 
506*36379Ssklower 		IFDEBUG(D_ESISINPUT)
507*36379Ssklower 			printf("esis_ishinput: nsap %s is %s\n",
508*36379Ssklower 				clnp_iso_addrp(&nsap), new_entry ? "new" : "old");
509*36379Ssklower 		ENDDEBUG
510*36379Ssklower 
511*36379Ssklower 		snpac_add(shp->snh_ifp, &nsap, shp->snh_shost, 6, SNPA_IS, ht);
512*36379Ssklower 		if (new_entry)
513*36379Ssklower 			esis_shoutput(shp->snh_ifp,
514*36379Ssklower 				iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
515*36379Ssklower 				esis_holding_time, shp->snh_shost, 6);
516*36379Ssklower 	} else {
517*36379Ssklower 		esis_stat.es_toosmall++;
518*36379Ssklower 	}
519*36379Ssklower 	m_freem(m);
520*36379Ssklower }
521*36379Ssklower 
522*36379Ssklower /*
523*36379Ssklower  * FUNCTION:		esis_rdinput
524*36379Ssklower  *
525*36379Ssklower  * PURPOSE:			Process an incoming RD pdu
526*36379Ssklower  *
527*36379Ssklower  * RETURNS:
528*36379Ssklower  *
529*36379Ssklower  * SIDE EFFECTS:
530*36379Ssklower  *
531*36379Ssklower  * NOTES:
532*36379Ssklower  */
533*36379Ssklower esis_rdinput(m0, shp)
534*36379Ssklower struct mbuf		*m0;	/* esh pdu */
535*36379Ssklower struct snpa_hdr	*shp;	/* subnetwork header */
536*36379Ssklower {
537*36379Ssklower 	struct esis_fixed	*pdu = mtod(m0, struct esis_fixed *);
538*36379Ssklower 	u_short				ht;		/* holding time */
539*36379Ssklower 	struct iso_addr		da;
540*36379Ssklower 	caddr_t				bsnpa;
541*36379Ssklower 	int					bsnpalen;
542*36379Ssklower 	struct iso_addr		net;
543*36379Ssklower 	int					netl;
544*36379Ssklower 	caddr_t				buf = (caddr_t)pdu + sizeof(struct esis_fixed);
545*36379Ssklower 	int					len = pdu->esis_hdr_len - sizeof(struct esis_fixed);
546*36379Ssklower 
547*36379Ssklower 	esis_stat.es_rdrcvd++;
548*36379Ssklower 
549*36379Ssklower 	/* intermediate systems ignore redirects */
550*36379Ssklower 	if (iso_systype & SNPA_IS)
551*36379Ssklower 		goto bad;
552*36379Ssklower 
553*36379Ssklower 	CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
554*36379Ssklower 
555*36379Ssklower 	/* Extract DA */
556*36379Ssklower 	if (!esis_extract_addr(&buf, &da, &len)) {
557*36379Ssklower 		esis_stat.es_toosmall++;
558*36379Ssklower 		goto bad;
559*36379Ssklower 	}
560*36379Ssklower 
561*36379Ssklower 	/* Extract better snpa */
562*36379Ssklower 	bsnpalen = *buf++;
563*36379Ssklower 	if (bsnpalen > len) {
564*36379Ssklower 		esis_stat.es_toosmall++;
565*36379Ssklower 		goto bad;
566*36379Ssklower 	} else {
567*36379Ssklower 		bsnpa = buf;
568*36379Ssklower 		buf += bsnpalen;
569*36379Ssklower 		len -= bsnpalen;
570*36379Ssklower 	}
571*36379Ssklower 
572*36379Ssklower 	/* Extract NET if present */
573*36379Ssklower 	if ((netl = *buf) > 0) {
574*36379Ssklower 		if (!esis_extract_addr(&buf, &net, &len)) {
575*36379Ssklower 			esis_stat.es_toosmall++;
576*36379Ssklower 			goto bad;
577*36379Ssklower 		}
578*36379Ssklower 	}
579*36379Ssklower 
580*36379Ssklower 	IFDEBUG(D_ESISINPUT)
581*36379Ssklower 		printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(&da));
582*36379Ssklower 		if (netl)
583*36379Ssklower 			printf("\t: net %s\n", clnp_iso_addrp(&net));
584*36379Ssklower 	ENDDEBUG
585*36379Ssklower 
586*36379Ssklower 	/*
587*36379Ssklower 	 *	If netl is zero, then redirect is to an ES. We need to add an entry
588*36379Ssklower 	 *	to the snpa cache for (destination, better snpa).
589*36379Ssklower 	 *	If netl is not zero, then the redirect is to an IS. In this
590*36379Ssklower 	 *	case, add an snpa cache entry for (net, better snpa).
591*36379Ssklower 	 *
592*36379Ssklower 	 *	If the redirect is to an IS, add a route entry towards that
593*36379Ssklower 	 *	IS.
594*36379Ssklower 	 */
595*36379Ssklower 	if (netl == 0) {
596*36379Ssklower 		/* redirect to an ES */
597*36379Ssklower 		snpac_add(shp->snh_ifp, &da, bsnpa, bsnpalen, SNPA_ES, ht);
598*36379Ssklower 	} else {
599*36379Ssklower 		snpac_add(shp->snh_ifp, &net, bsnpa, bsnpalen, SNPA_IS, ht);
600*36379Ssklower 		snpac_addrt(&da, &net);
601*36379Ssklower 	}
602*36379Ssklower bad:
603*36379Ssklower 	m_freem(m0);
604*36379Ssklower }
605*36379Ssklower 
606*36379Ssklower /*
607*36379Ssklower  * FUNCTION:		esis_config
608*36379Ssklower  *
609*36379Ssklower  * PURPOSE:			Report configuration
610*36379Ssklower  *
611*36379Ssklower  * RETURNS:
612*36379Ssklower  *
613*36379Ssklower  * SIDE EFFECTS:
614*36379Ssklower  *
615*36379Ssklower  * NOTES:			Called every esis_config_time seconds
616*36379Ssklower  */
617*36379Ssklower esis_config()
618*36379Ssklower {
619*36379Ssklower 	register struct ifnet	*ifp;
620*36379Ssklower 
621*36379Ssklower 	timeout(esis_config, (caddr_t)0, hz * esis_config_time);
622*36379Ssklower 
623*36379Ssklower 	/*
624*36379Ssklower 	 *	Report configuration for each interface that
625*36379Ssklower 	 *	- is UP
626*36379Ssklower 	 *	- is not loopback
627*36379Ssklower 	 *	- has broadcast capabilities
628*36379Ssklower 	 *	- has an ISO address
629*36379Ssklower 	 */
630*36379Ssklower 
631*36379Ssklower 	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
632*36379Ssklower 		if ((ifp->if_flags & IFF_UP) &&
633*36379Ssklower 			(ifp->if_flags & IFF_BROADCAST) &&
634*36379Ssklower 			((ifp->if_flags & IFF_LOOPBACK) == 0)) {
635*36379Ssklower 			/* search for an ISO address family */
636*36379Ssklower 			struct ifaddr	*ia;
637*36379Ssklower 
638*36379Ssklower 			for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {
639*36379Ssklower 				if (ia->ifa_addr.sa_family == AF_ISO) {
640*36379Ssklower 					esis_shoutput(ifp,
641*36379Ssklower 						iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
642*36379Ssklower 						esis_holding_time,
643*36379Ssklower 						iso_systype & SNPA_ES ? all_is.sc_snpa :
644*36379Ssklower 						all_es.sc_snpa, 6);
645*36379Ssklower 					break;
646*36379Ssklower 				}
647*36379Ssklower 			}
648*36379Ssklower 		}
649*36379Ssklower 	}
650*36379Ssklower }
651*36379Ssklower 
652*36379Ssklower /*
653*36379Ssklower  * FUNCTION:		esis_shoutput
654*36379Ssklower  *
655*36379Ssklower  * PURPOSE:			Transmit an esh or ish pdu
656*36379Ssklower  *
657*36379Ssklower  * RETURNS:			nothing
658*36379Ssklower  *
659*36379Ssklower  * SIDE EFFECTS:
660*36379Ssklower  *
661*36379Ssklower  * NOTES:
662*36379Ssklower  */
663*36379Ssklower esis_shoutput(ifp, type, ht, sn_addr, sn_len)
664*36379Ssklower struct ifnet	*ifp;
665*36379Ssklower int				type;
666*36379Ssklower short			ht;
667*36379Ssklower caddr_t 		sn_addr;
668*36379Ssklower int				sn_len;
669*36379Ssklower {
670*36379Ssklower 	struct mbuf			*m, *m0;
671*36379Ssklower 	caddr_t				cp, naddrp;
672*36379Ssklower 	int					naddr = 0;
673*36379Ssklower 	struct esis_fixed	*pdu;
674*36379Ssklower 	struct ifaddr		*ifa;
675*36379Ssklower 	int					len, total_len = 0;
676*36379Ssklower 	struct sockaddr_iso	siso;
677*36379Ssklower 
678*36379Ssklower 	if (type == ESIS_ESH)
679*36379Ssklower 		esis_stat.es_eshsent++;
680*36379Ssklower 	else if (type == ESIS_ISH)
681*36379Ssklower 		esis_stat.es_ishsent++;
682*36379Ssklower 	else {
683*36379Ssklower 		printf("esis_shoutput: bad pdu type\n");
684*36379Ssklower 		return;
685*36379Ssklower 	}
686*36379Ssklower 
687*36379Ssklower 	IFDEBUG(D_ESISOUTPUT)
688*36379Ssklower 		int	i;
689*36379Ssklower 		printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ",
690*36379Ssklower 			ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish",
691*36379Ssklower 			ht, sn_len);
692*36379Ssklower 		for (i=0; i<sn_len; i++)
693*36379Ssklower 			printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' ');
694*36379Ssklower 		printf("\n");
695*36379Ssklower 	ENDDEBUG
696*36379Ssklower 
697*36379Ssklower 	if ((m0 = m = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {
698*36379Ssklower 		esis_stat.es_nomem++;
699*36379Ssklower 		return;
700*36379Ssklower 	}
701*36379Ssklower 
702*36379Ssklower 	pdu = mtod(m, struct esis_fixed *);
703*36379Ssklower 	naddrp = cp = (caddr_t)pdu + sizeof(struct esis_fixed);
704*36379Ssklower 	len = sizeof(struct esis_fixed);
705*36379Ssklower 
706*36379Ssklower 	/*
707*36379Ssklower 	 *	Build fixed part of header
708*36379Ssklower 	 */
709*36379Ssklower 	pdu->esis_proto_id = ISO9542_ESIS;
710*36379Ssklower 	pdu->esis_vers = ESIS_VERSION;
711*36379Ssklower 	pdu->esis_type = type;
712*36379Ssklower 	HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
713*36379Ssklower 
714*36379Ssklower 	if (type == ESIS_ESH) {
715*36379Ssklower 		cp++;
716*36379Ssklower 		len++;
717*36379Ssklower 	}
718*36379Ssklower 
719*36379Ssklower 	for (ifa = ifp->if_addrlist; ifa; ifa=ifa->ifa_next) {
720*36379Ssklower 		if (ifa->ifa_addr.sa_family == AF_ISO) {
721*36379Ssklower 			IFDEBUG(D_ESISOUTPUT)
722*36379Ssklower 				printf("esis_shoutput: adding nsap %s\n",
723*36379Ssklower 					clnp_iso_addrp(&IA_SIS(ifa)->siso_addr));
724*36379Ssklower 			ENDDEBUG
725*36379Ssklower 			if (!esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr,
726*36379Ssklower 				MLEN - len)) {
727*36379Ssklower 				total_len += len;
728*36379Ssklower 				EXTEND_PACKET(m, m0, len, cp);
729*36379Ssklower 				(void) esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr,
730*36379Ssklower 					MLEN - len);
731*36379Ssklower 			}
732*36379Ssklower 			naddr++;
733*36379Ssklower 			if (type == ESIS_ISH)
734*36379Ssklower 				break;
735*36379Ssklower 		}
736*36379Ssklower 	}
737*36379Ssklower 
738*36379Ssklower 	if (type == ESIS_ESH)
739*36379Ssklower 		*naddrp = naddr;
740*36379Ssklower 
741*36379Ssklower 	m->m_len = len;
742*36379Ssklower 	total_len += len;
743*36379Ssklower 	pdu->esis_hdr_len = total_len;
744*36379Ssklower 	iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
745*36379Ssklower 
746*36379Ssklower 	siso.siso_family = AF_ISO;
747*36379Ssklower 	siso.siso_addr.isoa_afi = AFI_SNA;
748*36379Ssklower 	siso.siso_addr.isoa_len = sn_len + 1;
749*36379Ssklower 	bcopy(sn_addr, siso.siso_addr.sna_idi, sn_len);
750*36379Ssklower 	(ifp->if_output)(ifp, m0, &siso);
751*36379Ssklower }
752*36379Ssklower 
753*36379Ssklower /*
754*36379Ssklower  * FUNCTION:		esis_ctlinput
755*36379Ssklower  *
756*36379Ssklower  * PURPOSE:			Handle the PRC_IFDOWN transition
757*36379Ssklower  *
758*36379Ssklower  * RETURNS:			nothing
759*36379Ssklower  *
760*36379Ssklower  * SIDE EFFECTS:
761*36379Ssklower  *
762*36379Ssklower  * NOTES:			Calls snpac_flush for interface specified.
763*36379Ssklower  *					The loop through iso_ifaddr is stupid because
764*36379Ssklower  *					back in if_down, we knew the ifp...
765*36379Ssklower  */
766*36379Ssklower esis_ctlinput(req, siso)
767*36379Ssklower int						req;		/* request: we handle only PRC_IFDOWN */
768*36379Ssklower struct sockaddr_iso		*siso;		/* address of ifp */
769*36379Ssklower {
770*36379Ssklower 	register struct iso_ifaddr *ia;	/* scan through interface addresses */
771*36379Ssklower 
772*36379Ssklower 	for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
773*36379Ssklower 		if (iso_addrmatch(IA_SIS(ia), siso))
774*36379Ssklower 			snpac_flushifp(ia->ia_ifp);
775*36379Ssklower 	}
776*36379Ssklower }
777*36379Ssklower 
778*36379Ssklower #endif	ISO
779