xref: /csrg-svn/sys/netiso/tp_iso.c (revision 36403)
1*36403Ssklower /***********************************************************
2*36403Ssklower 		Copyright IBM Corporation 1987
3*36403Ssklower 
4*36403Ssklower                       All Rights Reserved
5*36403Ssklower 
6*36403Ssklower Permission to use, copy, modify, and distribute this software and its
7*36403Ssklower documentation for any purpose and without fee is hereby granted,
8*36403Ssklower provided that the above copyright notice appear in all copies and that
9*36403Ssklower both that copyright notice and this permission notice appear in
10*36403Ssklower supporting documentation, and that the name of IBM not be
11*36403Ssklower used in advertising or publicity pertaining to distribution of the
12*36403Ssklower software without specific, written prior permission.
13*36403Ssklower 
14*36403Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15*36403Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16*36403Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17*36403Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18*36403Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19*36403Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*36403Ssklower SOFTWARE.
21*36403Ssklower 
22*36403Ssklower ******************************************************************/
23*36403Ssklower 
24*36403Ssklower /*
25*36403Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26*36403Ssklower  */
27*36403Ssklower /*
28*36403Ssklower  * ARGO TP
29*36403Ssklower  * $Header: tp_iso.c,v 5.3 88/11/18 17:27:57 nhall Exp $
30*36403Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_iso.c,v $
31*36403Ssklower  *
32*36403Ssklower  * Here is where you find the iso-dependent code.  We've tried
33*36403Ssklower  * keep all net-level and (primarily) address-family-dependent stuff
34*36403Ssklower  * out of the tp source, and everthing here is reached indirectly
35*36403Ssklower  * through a switch table (struct nl_protosw *) tpcb->tp_nlproto
36*36403Ssklower  * (see tp_pcb.c).
37*36403Ssklower  * The routines here are:
38*36403Ssklower  * 		iso_getsufx: gets transport suffix out of an isopcb structure.
39*36403Ssklower  * 		iso_putsufx: put transport suffix into an isopcb structure.
40*36403Ssklower  *		iso_putnetaddr: put a whole net addr into an isopcb.
41*36403Ssklower  *		iso_getnetaddr: get a whole net addr from an isopcb.
42*36403Ssklower  *		iso_recycle_suffix: clear suffix for reuse in isopcb
43*36403Ssklower  * 		tpclnp_ctlinput: handle ER CNLPdu : icmp-like stuff
44*36403Ssklower  * 		tpclnp_mtu: figure out what size tpdu to use
45*36403Ssklower  *		tpclnp_input: take a pkt from clnp, strip off its clnp header,
46*36403Ssklower  *				give to tp
47*36403Ssklower  *		tpclnp_output_dg: package a pkt for clnp given 2 addresses & some data
48*36403Ssklower  *		tpclnp_output: package a pkt for clnp given an isopcb & some data
49*36403Ssklower  */
50*36403Ssklower 
51*36403Ssklower #ifndef lint
52*36403Ssklower static char *rcsid = "$Header: tp_iso.c,v 5.3 88/11/18 17:27:57 nhall Exp $";
53*36403Ssklower #endif lint
54*36403Ssklower 
55*36403Ssklower #ifdef ISO
56*36403Ssklower 
57*36403Ssklower #include "../h/types.h"
58*36403Ssklower #include "../h/socket.h"
59*36403Ssklower #include "../h/socketvar.h"
60*36403Ssklower #include "../h/domain.h"
61*36403Ssklower #include "../h/mbuf.h"
62*36403Ssklower #include "../h/errno.h"
63*36403Ssklower #include "../h/time.h"
64*36403Ssklower #include "../net/if.h"
65*36403Ssklower #include "../net/route.h"
66*36403Ssklower #include "../h/protosw.h"
67*36403Ssklower 
68*36403Ssklower #include "../netiso/tp_param.h"
69*36403Ssklower #include "../netiso/argo_debug.h"
70*36403Ssklower #include "../netiso/tp_stat.h"
71*36403Ssklower #include "../netiso/tp_pcb.h"
72*36403Ssklower #include "../netiso/tp_trace.h"
73*36403Ssklower #include "../netiso/tp_stat.h"
74*36403Ssklower #include "../netiso/tp_tpdu.h"
75*36403Ssklower #include "../netiso/tp_clnp.h"
76*36403Ssklower 
77*36403Ssklower /*
78*36403Ssklower  * CALLED FROM:
79*36403Ssklower  * 	pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
80*36403Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
81*36403Ssklower  * 	Return a transport suffix from an isopcb structure (inp).
82*36403Ssklower  *  (CAST TO AN INT)
83*36403Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
84*36403Ssklower  */
85*36403Ssklower 
86*36403Ssklower short
87*36403Ssklower iso_getsufx(isop,  which)
88*36403Ssklower 	struct isopcb *isop;
89*36403Ssklower 	int which;
90*36403Ssklower {
91*36403Ssklower 	switch (which) {
92*36403Ssklower 	case TP_LOCAL:
93*36403Ssklower 		return  htons(isop->isop_laddr.siso_tsuffix);
94*36403Ssklower 
95*36403Ssklower 	case TP_FOREIGN:
96*36403Ssklower 		return  htons(isop->isop_faddr.siso_tsuffix);
97*36403Ssklower 	}
98*36403Ssklower }
99*36403Ssklower 
100*36403Ssklower /* CALLED FROM:
101*36403Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
102*36403Ssklower  * 	incoming CR_TPDU.
103*36403Ssklower  *
104*36403Ssklower  * FUNCTION, ARGUMENTS:
105*36403Ssklower  * 	Put a transport suffix (found in name) into an isopcb structure (isop).
106*36403Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
107*36403Ssklower  */
108*36403Ssklower void
109*36403Ssklower iso_putsufx(isop, name, which)
110*36403Ssklower 	struct isopcb *isop;
111*36403Ssklower 	struct sockaddr_iso *name;
112*36403Ssklower 	int which;
113*36403Ssklower {
114*36403Ssklower 	switch (which) {
115*36403Ssklower 	case TP_LOCAL:
116*36403Ssklower 		isop->isop_lport = ntohs(name->siso_tsuffix);
117*36403Ssklower 		break;
118*36403Ssklower 	case TP_FOREIGN:
119*36403Ssklower 		isop->isop_fport = ntohs(name->siso_tsuffix);
120*36403Ssklower 		break;
121*36403Ssklower 	}
122*36403Ssklower }
123*36403Ssklower 
124*36403Ssklower /*
125*36403Ssklower  * CALLED FROM:
126*36403Ssklower  * 	tp.trans whenever we go into REFWAIT state.
127*36403Ssklower  * FUNCTION and ARGUMENT:
128*36403Ssklower  *	 Called when a ref is frozen, to allow the suffix to be reused.
129*36403Ssklower  * 	(isop) is the net level pcb.  This really shouldn't have to be
130*36403Ssklower  * 	done in a NET level pcb but... for the internet world that just
131*36403Ssklower  * 	the way it is done in BSD...
132*36403Ssklower  * 	The alternative is to have the port unusable until the reference
133*36403Ssklower  * 	timer goes off.
134*36403Ssklower  */
135*36403Ssklower void
136*36403Ssklower iso_recycle_tsuffix(isop)
137*36403Ssklower 	struct isopcb	*isop;
138*36403Ssklower {
139*36403Ssklower 	isop->isop_laddr.siso_tsuffix = isop->isop_faddr.siso_tsuffix = 0;
140*36403Ssklower }
141*36403Ssklower 
142*36403Ssklower /*
143*36403Ssklower  * CALLED FROM:
144*36403Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
145*36403Ssklower  * 	incoming CR_TPDU.
146*36403Ssklower  *
147*36403Ssklower  * FUNCTION and ARGUMENTS:
148*36403Ssklower  * 	Copy a whole net addr from a struct sockaddr (name).
149*36403Ssklower  * 	into an isopcb (isop).
150*36403Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
151*36403Ssklower  */
152*36403Ssklower void
153*36403Ssklower iso_putnetaddr(isop, name, which)
154*36403Ssklower 	register struct isopcb	*isop;
155*36403Ssklower 	struct sockaddr_iso	*name;
156*36403Ssklower 	int which;
157*36403Ssklower {
158*36403Ssklower 	switch (which) {
159*36403Ssklower 	case TP_LOCAL:
160*36403Ssklower 		isop->isop_laddr.siso_family = AF_ISO;
161*36403Ssklower 		bcopy((caddr_t)&name->siso_addr,
162*36403Ssklower 			(caddr_t)&isop->isop_laddr.siso_addr, sizeof(struct iso_addr));
163*36403Ssklower 		IFDEBUG(D_TPISO)
164*36403Ssklower 			printf("PUT TP_LOCAL addr\n");
165*36403Ssklower 			dump_isoaddr(&isop->isop_laddr);
166*36403Ssklower 		ENDDEBUG
167*36403Ssklower 		break;
168*36403Ssklower 	case TP_FOREIGN:
169*36403Ssklower 		isop->isop_faddr.siso_family = AF_ISO;
170*36403Ssklower 		if( name != (struct sockaddr_iso *)0 ) {
171*36403Ssklower 			bcopy((caddr_t)&name->siso_addr,
172*36403Ssklower 				(caddr_t)&isop->isop_faddr.siso_addr, sizeof(struct iso_addr));
173*36403Ssklower 		}
174*36403Ssklower 		IFDEBUG(D_TPISO)
175*36403Ssklower 			printf("PUT TP_FOREIGN addr\n");
176*36403Ssklower 			dump_isoaddr(&isop->isop_faddr);
177*36403Ssklower 		ENDDEBUG
178*36403Ssklower 	}
179*36403Ssklower }
180*36403Ssklower 
181*36403Ssklower /*
182*36403Ssklower  * CALLED FROM:
183*36403Ssklower  *  pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
184*36403Ssklower  * FUNCTION and ARGUMENTS:
185*36403Ssklower  * 	Copy a whole net addr from an isopcb (isop) into
186*36403Ssklower  * 	a struct sockaddr (name).
187*36403Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
188*36403Ssklower  */
189*36403Ssklower 
190*36403Ssklower void
191*36403Ssklower iso_getnetaddr( isop, name, which)
192*36403Ssklower 	struct isopcb *isop;
193*36403Ssklower 	struct sockaddr_iso *name;
194*36403Ssklower 	int which;
195*36403Ssklower {
196*36403Ssklower 	switch (which) {
197*36403Ssklower 	case TP_LOCAL:
198*36403Ssklower 		bcopy( (caddr_t)&isop->isop_laddr.siso_addr,
199*36403Ssklower 			(caddr_t)&name->siso_addr, sizeof(struct iso_addr));
200*36403Ssklower 		break;
201*36403Ssklower 
202*36403Ssklower 	case TP_FOREIGN:
203*36403Ssklower 		bcopy( (caddr_t)&isop->isop_faddr.siso_addr,
204*36403Ssklower 			(caddr_t)&name->siso_addr, sizeof(struct iso_addr));
205*36403Ssklower 		break;
206*36403Ssklower 	}
207*36403Ssklower }
208*36403Ssklower 
209*36403Ssklower /*
210*36403Ssklower  * CALLED FROM:
211*36403Ssklower  *  tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
212*36403Ssklower  * FUNCTION, ARGUMENTS, SIDE EFFECTS and RETURN VALUE:
213*36403Ssklower  * Determine the proper maximum transmission unit, i.e., MTU, to use, given
214*36403Ssklower  * a) the header size for the network protocol and the max transmission
215*36403Ssklower  *	  unit on the subnet interface, determined from the information in (isop),
216*36403Ssklower  * b) the max size negotiated so far (negot)
217*36403Ssklower  * c) the window size used by the tp connection (found in so),
218*36403Ssklower  *
219*36403Ssklower  * The result is put in the integer *size in its integer form and in
220*36403Ssklower  * *negot in its logarithmic form.
221*36403Ssklower  *
222*36403Ssklower  * The rules are:
223*36403Ssklower  * a) can only negotiate down from the value found in *negot.
224*36403Ssklower  * b) the MTU must be < the windowsize,
225*36403Ssklower  * c) If src and dest are on the same net,
226*36403Ssklower  * 	  we will negotiate the closest size larger than  MTU but really USE
227*36403Ssklower  *    the actual device mtu - ll hdr sizes.
228*36403Ssklower  *   otherwise we negotiate the closest size smaller than MTU - ll hdr sizes.
229*36403Ssklower  */
230*36403Ssklower 
231*36403Ssklower void
232*36403Ssklower tpclnp_mtu(so, isop, size, negot )
233*36403Ssklower 	struct socket *so;
234*36403Ssklower 	struct isopcb *isop;
235*36403Ssklower 	int *size;
236*36403Ssklower 	u_char *negot;
237*36403Ssklower {
238*36403Ssklower 	struct ifnet *ifp;
239*36403Ssklower 	register int i;
240*36403Ssklower 	int windowsize = so->so_rcv.sb_hiwat;
241*36403Ssklower 	int clnp_size;
242*36403Ssklower 	int sizeismtu = 0;
243*36403Ssklower 
244*36403Ssklower 	struct ifnet	*iso_routeifp();
245*36403Ssklower 
246*36403Ssklower 	IFDEBUG(D_CONN)
247*36403Ssklower 		printf("tpclnp_mtu(0x%x,0x%x,0x%x,0x%x)\n", so, isop, size, negot);
248*36403Ssklower 	ENDDEBUG
249*36403Ssklower 	IFTRACE(D_CONN)
250*36403Ssklower 		tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0);
251*36403Ssklower 	ENDTRACE
252*36403Ssklower 
253*36403Ssklower 	*size = 1 << *negot;
254*36403Ssklower 
255*36403Ssklower 	if( *size > windowsize ) {
256*36403Ssklower 		*size = windowsize;
257*36403Ssklower 	}
258*36403Ssklower 
259*36403Ssklower 	if ((ifp = iso_routeifp(&isop->isop_faddr)) == (struct ifnet *)0)
260*36403Ssklower 		return;
261*36403Ssklower 
262*36403Ssklower 	/* TODO - make this indirect off the socket structure to the
263*36403Ssklower 	 * network layer to get headersize
264*36403Ssklower 	 */
265*36403Ssklower 	clnp_size = clnp_hdrsize(isop->isop_laddr.siso_addr.isoa_len);
266*36403Ssklower 
267*36403Ssklower 	if(*size > ifp->if_mtu - clnp_size) {
268*36403Ssklower 		*size = ifp->if_mtu - clnp_size;
269*36403Ssklower 		sizeismtu = 1;
270*36403Ssklower 	}
271*36403Ssklower 	IFTRACE(D_CONN)
272*36403Ssklower 		tptrace(TPPTmisc, "GET MTU MID: tpcb size negot i \n",
273*36403Ssklower 		*size, *negot, i, 0);
274*36403Ssklower 	ENDTRACE
275*36403Ssklower 
276*36403Ssklower 	/* have to transform size to the log2 of size */
277*36403Ssklower 	for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i) <= *size)) ; i++)
278*36403Ssklower 		;
279*36403Ssklower 	i--;
280*36403Ssklower 
281*36403Ssklower 	/* are we on the same LAN? if so, negotiate one tpdu size larger,
282*36403Ssklower 	 * and actually send the real mtu size
283*36403Ssklower 	 */
284*36403Ssklower 	/* PHASE2: replace with iso_on_localnet(&isop->isop_faddr);
285*36403Ssklower 	 * or something along those lines
286*36403Ssklower 	 */
287*36403Ssklower 	if ( iso_netmatch(&isop->isop_laddr, &isop->isop_faddr) && sizeismtu ) {
288*36403Ssklower 		i++;
289*36403Ssklower 	} else {
290*36403Ssklower 		*size = 1<<i;
291*36403Ssklower 	}
292*36403Ssklower 	*negot = i;
293*36403Ssklower 
294*36403Ssklower 	IFDEBUG(D_CONN)
295*36403Ssklower 		printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n",
296*36403Ssklower 		ifp->if_name,	*size, *negot);
297*36403Ssklower 	ENDDEBUG
298*36403Ssklower 	IFTRACE(D_CONN)
299*36403Ssklower 		tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n",
300*36403Ssklower 		*size, *negot, 0, 0);
301*36403Ssklower 	ENDTRACE
302*36403Ssklower }
303*36403Ssklower 
304*36403Ssklower 
305*36403Ssklower /*
306*36403Ssklower  * CALLED FROM:
307*36403Ssklower  *  tp_emit()
308*36403Ssklower  * FUNCTION and ARGUMENTS:
309*36403Ssklower  *  Take a packet(m0) from tp and package it so that clnp will accept it.
310*36403Ssklower  *  This means prepending space for the clnp header and filling in a few
311*36403Ssklower  *  of the fields.
312*36403Ssklower  *  inp is the isopcb structure; datalen is the length of the data in the
313*36403Ssklower  *  mbuf string m0.
314*36403Ssklower  * RETURN VALUE:
315*36403Ssklower  *  whatever (E*) is returned form the net layer output routine.
316*36403Ssklower  */
317*36403Ssklower 
318*36403Ssklower int
319*36403Ssklower tpclnp_output(isop, m0, datalen, nochksum)
320*36403Ssklower 	struct isopcb		*isop;
321*36403Ssklower 	struct mbuf 		*m0;
322*36403Ssklower 	int 				datalen;
323*36403Ssklower 	int					nochksum;
324*36403Ssklower {
325*36403Ssklower 	IncStat(ts_tpdu_sent);
326*36403Ssklower 
327*36403Ssklower 	IFDEBUG(D_TPISO)
328*36403Ssklower 		struct tpdu *hdr = mtod(m0, struct tpdu *);
329*36403Ssklower 
330*36403Ssklower 		printf(
331*36403Ssklower "abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n",
332*36403Ssklower 			datalen,
333*36403Ssklower 			(int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum);
334*36403Ssklower 		dump_isoaddr(&isop->isop_faddr);
335*36403Ssklower 		printf("\nsrc addr:\n");
336*36403Ssklower 		dump_isoaddr(&isop->isop_laddr);
337*36403Ssklower 		dump_mbuf(m0, "at tpclnp_output");
338*36403Ssklower 	ENDDEBUG
339*36403Ssklower 
340*36403Ssklower 	return
341*36403Ssklower 		clnp_output(m0, isop, datalen, nochksum?CLNP_NO_CKSUM:0 /* flags */);
342*36403Ssklower }
343*36403Ssklower 
344*36403Ssklower /*
345*36403Ssklower  * CALLED FROM:
346*36403Ssklower  *  tp_error_emit()
347*36403Ssklower  * FUNCTION and ARGUMENTS:
348*36403Ssklower  *  This is a copy of tpclnp_output that takes the addresses
349*36403Ssklower  *  instead of a pcb.  It's used by the tp_error_emit, when we
350*36403Ssklower  *  don't have an iso_pcb with which to call the normal output rtn.
351*36403Ssklower  * RETURN VALUE:
352*36403Ssklower  *  ENOBUFS or
353*36403Ssklower  *  whatever (E*) is returned form the net layer output routine.
354*36403Ssklower  */
355*36403Ssklower 
356*36403Ssklower int
357*36403Ssklower tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
358*36403Ssklower 	struct iso_addr		*laddr, *faddr;
359*36403Ssklower 	struct mbuf 		*m0;
360*36403Ssklower 	int 				datalen;
361*36403Ssklower 	struct route 		*ro;
362*36403Ssklower 	int					nochksum;
363*36403Ssklower {
364*36403Ssklower 	struct isopcb		tmppcb;
365*36403Ssklower 	struct iso_addr		*isoa;
366*36403Ssklower 	int					err;
367*36403Ssklower 	int					flags;
368*36403Ssklower 
369*36403Ssklower 	IFDEBUG(D_TPISO)
370*36403Ssklower 		printf("tpclnp_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
371*36403Ssklower 	ENDDEBUG
372*36403Ssklower 
373*36403Ssklower 	/*
374*36403Ssklower 	 *	Fill in minimal portion of isopcb so that clnp can send the
375*36403Ssklower 	 *	packet.
376*36403Ssklower 	 */
377*36403Ssklower 	bzero((caddr_t)&tmppcb, sizeof(tmppcb));
378*36403Ssklower 	isoa = &(tmppcb.isop_laddr.siso_addr);
379*36403Ssklower 	bcopy((caddr_t)laddr, (caddr_t)isoa, sizeof (struct iso_addr));
380*36403Ssklower 	isoa = &(tmppcb.isop_faddr.siso_addr);
381*36403Ssklower 	bcopy((caddr_t)faddr, (caddr_t)isoa, sizeof (struct iso_addr));
382*36403Ssklower 
383*36403Ssklower 	IFDEBUG(D_TPISO)
384*36403Ssklower 		printf("tpclnp_output_dg  faddr: \n");
385*36403Ssklower 		dump_isoaddr(&tmppcb.isop_faddr);
386*36403Ssklower 		printf("\ntpclnp_output_dg  laddr: \n");
387*36403Ssklower 		dump_isoaddr(&tmppcb.isop_laddr);
388*36403Ssklower 		printf("\n");
389*36403Ssklower 	ENDDEBUG
390*36403Ssklower 
391*36403Ssklower 	/*
392*36403Ssklower 	 *	Do not use packet cache since this is a one shot error packet
393*36403Ssklower 	 */
394*36403Ssklower 	flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0));
395*36403Ssklower 
396*36403Ssklower 	IncStat(ts_tpdu_sent);
397*36403Ssklower 
398*36403Ssklower 	err = clnp_output(m0, &tmppcb, datalen, flags);
399*36403Ssklower 
400*36403Ssklower 	/*
401*36403Ssklower 	 *	Free route allocated by clnp (if the route was indeed allocated)
402*36403Ssklower 	 */
403*36403Ssklower 	if (tmppcb.isop_route.ro_rt)
404*36403Ssklower 		RTFREE(tmppcb.isop_route.ro_rt);
405*36403Ssklower 
406*36403Ssklower 	return(err);
407*36403Ssklower }
408*36403Ssklower 
409*36403Ssklower /*
410*36403Ssklower  * CALLED FROM:
411*36403Ssklower  * 	clnp's input routine, indirectly through the protosw.
412*36403Ssklower  * FUNCTION and ARGUMENTS:
413*36403Ssklower  * Take a packet (m) from clnp, strip off the clnp header and give it to tp
414*36403Ssklower  * No return value.
415*36403Ssklower  */
416*36403Ssklower ProtoHook
417*36403Ssklower tpclnp_input(m, faddr, laddr, clnp_len)
418*36403Ssklower 	struct mbuf *m;
419*36403Ssklower 	struct iso_addr *faddr, *laddr;
420*36403Ssklower 	int clnp_len;
421*36403Ssklower {
422*36403Ssklower 	struct sockaddr_iso src, dst;
423*36403Ssklower 	int s = splnet();
424*36403Ssklower 
425*36403Ssklower 	IncStat(ts_pkt_rcvd);
426*36403Ssklower 
427*36403Ssklower 	IFDEBUG(D_TPINPUT)
428*36403Ssklower 		printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len);
429*36403Ssklower 		dump_mbuf(m, "at tpclnp_input");
430*36403Ssklower 	ENDDEBUG
431*36403Ssklower 	/*
432*36403Ssklower 	 * CLNP gives us an mbuf chain WITH the clnp header pulled up,
433*36403Ssklower 	 * and the length of the clnp header.
434*36403Ssklower 	 * First, strip off the Clnp header. leave the mbuf there for the
435*36403Ssklower 	 * pullup that follows.
436*36403Ssklower 	 */
437*36403Ssklower 
438*36403Ssklower 	m->m_len -= clnp_len;
439*36403Ssklower 	m->m_off += clnp_len;
440*36403Ssklower 
441*36403Ssklower 	m = (struct mbuf *)tp_inputprep(m);
442*36403Ssklower 
443*36403Ssklower 	IFDEBUG(D_TPINPUT)
444*36403Ssklower 		dump_mbuf(m, "after tpclnp_input both pullups");
445*36403Ssklower 	ENDDEBUG
446*36403Ssklower 
447*36403Ssklower 	src.siso_family = dst.siso_family = AF_ISO;
448*36403Ssklower 	bcopy(faddr, &src.siso_addr, sizeof(struct iso_addr));
449*36403Ssklower 	bcopy(laddr, &dst.siso_addr, sizeof(struct iso_addr));
450*36403Ssklower 
451*36403Ssklower 	IFDEBUG(D_TPISO)
452*36403Ssklower 		printf("calling tp_input: &src 0x%x  &dst 0x%x, src addr:\n",
453*36403Ssklower 			&src, &dst);
454*36403Ssklower 		printf(" dst addr:\n");
455*36403Ssklower 		dump_isoaddr(&src);
456*36403Ssklower 		dump_isoaddr(&dst);
457*36403Ssklower 	ENDDEBUG
458*36403Ssklower 
459*36403Ssklower 	(void) tp_input(m, &src, &dst, 0, tpclnp_output_dg);
460*36403Ssklower 
461*36403Ssklower 	IFDEBUG(D_QUENCH)
462*36403Ssklower 		{
463*36403Ssklower 			if(time.tv_usec & 0x4 && time.tv_usec & 0x40) {
464*36403Ssklower 				printf("tpclnp_input: FAKING %s\n",
465*36403Ssklower 					tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2");
466*36403Ssklower 				if(tp_stat.ts_pkt_rcvd & 0x1) {
467*36403Ssklower 					tpclnp_ctlinput(PRC_QUENCH, &src);
468*36403Ssklower 				} else {
469*36403Ssklower 					tpclnp_ctlinput(PRC_QUENCH2, &src);
470*36403Ssklower 				}
471*36403Ssklower 			}
472*36403Ssklower 		}
473*36403Ssklower 	ENDDEBUG
474*36403Ssklower 
475*36403Ssklower 	splx(s);
476*36403Ssklower 	return 0;
477*36403Ssklower 
478*36403Ssklower discard:
479*36403Ssklower 	IFDEBUG(D_TPINPUT)
480*36403Ssklower 		printf("tpclnp_input DISCARD\n");
481*36403Ssklower 	ENDDEBUG
482*36403Ssklower 	IFTRACE(D_TPINPUT)
483*36403Ssklower 		tptrace(TPPTmisc, "tpclnp_input DISCARD m",  m,0,0,0);
484*36403Ssklower 	ENDTRACE
485*36403Ssklower 	m_freem(m);
486*36403Ssklower 	IncStat(ts_recv_drop);
487*36403Ssklower 	splx(s);
488*36403Ssklower 
489*36403Ssklower 	return 0;
490*36403Ssklower }
491*36403Ssklower 
492*36403Ssklower ProtoHook
493*36403Ssklower iso_rtchange()
494*36403Ssklower {
495*36403Ssklower 	return 0;
496*36403Ssklower }
497*36403Ssklower 
498*36403Ssklower /*
499*36403Ssklower  * CALLED FROM:
500*36403Ssklower  *  tpclnp_ctlinput()
501*36403Ssklower  * FUNCTION and ARGUMENTS:
502*36403Ssklower  *  find the tpcb pointer and pass it to tp_quench
503*36403Ssklower  */
504*36403Ssklower void
505*36403Ssklower tpiso_decbit(isop)
506*36403Ssklower 	struct isopcb *isop;
507*36403Ssklower {
508*36403Ssklower 	tp_quench( isop->isop_socket->so_tpcb, PRC_QUENCH2 );
509*36403Ssklower }
510*36403Ssklower /*
511*36403Ssklower  * CALLED FROM:
512*36403Ssklower  *  tpclnp_ctlinput()
513*36403Ssklower  * FUNCTION and ARGUMENTS:
514*36403Ssklower  *  find the tpcb pointer and pass it to tp_quench
515*36403Ssklower  */
516*36403Ssklower void
517*36403Ssklower tpiso_quench(isop)
518*36403Ssklower 	struct isopcb *isop;
519*36403Ssklower {
520*36403Ssklower 	tp_quench( isop->isop_socket->so_tpcb, PRC_QUENCH );
521*36403Ssklower }
522*36403Ssklower 
523*36403Ssklower /*
524*36403Ssklower  * CALLED FROM:
525*36403Ssklower  *  The network layer through the protosw table.
526*36403Ssklower  * FUNCTION and ARGUMENTS:
527*36403Ssklower  *	When clnp an ICMP-like msg this gets called.
528*36403Ssklower  *	It either returns an error status to the user or
529*36403Ssklower  *	it causes all connections on this address to be aborted
530*36403Ssklower  *	by calling the appropriate xx_notify() routine.
531*36403Ssklower  *	(cmd) is the type of ICMP error.
532*36403Ssklower  * 	(siso) is the address of the guy who sent the ER CLNPDU
533*36403Ssklower  */
534*36403Ssklower ProtoHook
535*36403Ssklower tpclnp_ctlinput(cmd, siso)
536*36403Ssklower 	int cmd;
537*36403Ssklower 	struct sockaddr_iso *siso;
538*36403Ssklower {
539*36403Ssklower 	extern u_char inetctlerrmap[];
540*36403Ssklower 	extern ProtoHook tpiso_abort();
541*36403Ssklower 	extern ProtoHook iso_rtchange();
542*36403Ssklower 	extern ProtoHook tpiso_reset();
543*36403Ssklower 
544*36403Ssklower 	IFDEBUG(D_TPINPUT)
545*36403Ssklower 		printf("tpclnp_ctlinput: cmd 0x%x addr: ", cmd);
546*36403Ssklower 		dump_isoaddr(siso);
547*36403Ssklower 		printf("\n");
548*36403Ssklower 	ENDDEBUG
549*36403Ssklower 
550*36403Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
551*36403Ssklower 		return 0;
552*36403Ssklower 	switch (cmd) {
553*36403Ssklower 
554*36403Ssklower 		case	PRC_QUENCH2:
555*36403Ssklower 			iso_pcbnotify(&tp_isopcb, &siso->siso_addr, 0, tpiso_decbit);
556*36403Ssklower 			break;
557*36403Ssklower 
558*36403Ssklower 		case	PRC_QUENCH:
559*36403Ssklower 			iso_pcbnotify(&tp_isopcb, &siso->siso_addr, 0, tpiso_quench);
560*36403Ssklower 			break;
561*36403Ssklower 
562*36403Ssklower 		case	PRC_TIMXCEED_REASS:
563*36403Ssklower 		case	PRC_ROUTEDEAD:
564*36403Ssklower 			iso_pcbnotify(&tp_isopcb, &siso->siso_addr, 0, tpiso_reset);
565*36403Ssklower 			break;
566*36403Ssklower 
567*36403Ssklower 		case	PRC_HOSTUNREACH:
568*36403Ssklower 		case	PRC_UNREACH_NET:
569*36403Ssklower 		case	PRC_IFDOWN:
570*36403Ssklower 		case	PRC_HOSTDEAD:
571*36403Ssklower 			iso_pcbnotify(&tp_isopcb, &siso->siso_addr,
572*36403Ssklower 					(int)inetctlerrmap[cmd], iso_rtchange);
573*36403Ssklower 			break;
574*36403Ssklower 
575*36403Ssklower 		default:
576*36403Ssklower 		/*
577*36403Ssklower 		case	PRC_MSGSIZE:
578*36403Ssklower 		case	PRC_UNREACH_HOST:
579*36403Ssklower 		case	PRC_UNREACH_PROTOCOL:
580*36403Ssklower 		case	PRC_UNREACH_PORT:
581*36403Ssklower 		case	PRC_UNREACH_NEEDFRAG:
582*36403Ssklower 		case	PRC_UNREACH_SRCFAIL:
583*36403Ssklower 		case	PRC_REDIRECT_NET:
584*36403Ssklower 		case	PRC_REDIRECT_HOST:
585*36403Ssklower 		case	PRC_REDIRECT_TOSNET:
586*36403Ssklower 		case	PRC_REDIRECT_TOSHOST:
587*36403Ssklower 		case	PRC_TIMXCEED_INTRANS:
588*36403Ssklower 		case	PRC_PARAMPROB:
589*36403Ssklower 		*/
590*36403Ssklower 		iso_pcbnotify(&tp_isopcb, &siso->siso_addr,
591*36403Ssklower 			(int)inetctlerrmap[cmd], tpiso_abort);
592*36403Ssklower 		break;
593*36403Ssklower 	}
594*36403Ssklower 	return 0;
595*36403Ssklower }
596*36403Ssklower 
597*36403Ssklower /*
598*36403Ssklower  * These next 2 routines are
599*36403Ssklower  * CALLED FROM:
600*36403Ssklower  *	xxx_notify() from tp_ctlinput() when
601*36403Ssklower  *  net level gets some ICMP-equiv. type event.
602*36403Ssklower  * FUNCTION and ARGUMENTS:
603*36403Ssklower  *  Cause the connection to be aborted with some sort of error
604*36403Ssklower  *  reason indicating that the network layer caused the abort.
605*36403Ssklower  *  Fakes an ER TPDU so we can go through the driver.
606*36403Ssklower  *  abort always aborts the TP connection.
607*36403Ssklower  *  reset may or may not, depending on the TP class that's in use.
608*36403Ssklower  */
609*36403Ssklower ProtoHook
610*36403Ssklower tpiso_abort(isop)
611*36403Ssklower 	struct isopcb *isop;
612*36403Ssklower {
613*36403Ssklower 	struct tp_event e;
614*36403Ssklower 
615*36403Ssklower 	IFDEBUG(D_CONN)
616*36403Ssklower 		printf("tpiso_abort 0x%x\n", isop);
617*36403Ssklower 	ENDDEBUG
618*36403Ssklower 	e.ev_number = ER_TPDU;
619*36403Ssklower 	e.ATTR(ER_TPDU).e_reason = ECONNABORTED;
620*36403Ssklower 	return  tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e);
621*36403Ssklower }
622*36403Ssklower 
623*36403Ssklower ProtoHook
624*36403Ssklower tpiso_reset(isop)
625*36403Ssklower 	struct isopcb *isop;
626*36403Ssklower {
627*36403Ssklower 	struct tp_event e;
628*36403Ssklower 
629*36403Ssklower 	e.ev_number = T_NETRESET;
630*36403Ssklower 	return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e);
631*36403Ssklower 
632*36403Ssklower }
633*36403Ssklower 
634*36403Ssklower #endif ISO
635