xref: /csrg-svn/sys/netiso/tp_iso.c (revision 44422)
136403Ssklower /***********************************************************
236403Ssklower 		Copyright IBM Corporation 1987
336403Ssklower 
436403Ssklower                       All Rights Reserved
536403Ssklower 
636403Ssklower Permission to use, copy, modify, and distribute this software and its
736403Ssklower documentation for any purpose and without fee is hereby granted,
836403Ssklower provided that the above copyright notice appear in all copies and that
936403Ssklower both that copyright notice and this permission notice appear in
1036403Ssklower supporting documentation, and that the name of IBM not be
1136403Ssklower used in advertising or publicity pertaining to distribution of the
1236403Ssklower software without specific, written prior permission.
1336403Ssklower 
1436403Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536403Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636403Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736403Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836403Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936403Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036403Ssklower SOFTWARE.
2136403Ssklower 
2236403Ssklower ******************************************************************/
2336403Ssklower 
2436403Ssklower /*
2536403Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636403Ssklower  */
2736403Ssklower /*
2836403Ssklower  * ARGO TP
2937469Ssklower  * $Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $
3037469Ssklower  * $Source: /var/src/sys/netiso/RCS/tp_iso.c,v $
31*44422Ssklower  *	@(#)tp_iso.c	7.8 (Berkeley) 06/28/90
3236403Ssklower  *
3336403Ssklower  * Here is where you find the iso-dependent code.  We've tried
3436403Ssklower  * keep all net-level and (primarily) address-family-dependent stuff
3536403Ssklower  * out of the tp source, and everthing here is reached indirectly
3636403Ssklower  * through a switch table (struct nl_protosw *) tpcb->tp_nlproto
3736403Ssklower  * (see tp_pcb.c).
3836403Ssklower  * The routines here are:
3936403Ssklower  * 		iso_getsufx: gets transport suffix out of an isopcb structure.
4036403Ssklower  * 		iso_putsufx: put transport suffix into an isopcb structure.
4136403Ssklower  *		iso_putnetaddr: put a whole net addr into an isopcb.
4236403Ssklower  *		iso_getnetaddr: get a whole net addr from an isopcb.
43*44422Ssklower  *		iso_cmpnetaddr: compare a whole net addr from an isopcb.
4436403Ssklower  *		iso_recycle_suffix: clear suffix for reuse in isopcb
4536403Ssklower  * 		tpclnp_ctlinput: handle ER CNLPdu : icmp-like stuff
4636403Ssklower  * 		tpclnp_mtu: figure out what size tpdu to use
4736403Ssklower  *		tpclnp_input: take a pkt from clnp, strip off its clnp header,
4836403Ssklower  *				give to tp
4936403Ssklower  *		tpclnp_output_dg: package a pkt for clnp given 2 addresses & some data
5036403Ssklower  *		tpclnp_output: package a pkt for clnp given an isopcb & some data
5136403Ssklower  */
5236403Ssklower 
5336403Ssklower #ifndef lint
5437469Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $";
5536403Ssklower #endif lint
5636403Ssklower 
5736403Ssklower #ifdef ISO
5836403Ssklower 
5937469Ssklower #include "param.h"
6037469Ssklower #include "socket.h"
6137469Ssklower #include "socketvar.h"
6237469Ssklower #include "domain.h"
6337469Ssklower #include "malloc.h"
6437469Ssklower #include "mbuf.h"
6537469Ssklower #include "errno.h"
6637469Ssklower #include "time.h"
6737469Ssklower #include "protosw.h"
6837469Ssklower 
6936403Ssklower #include "../net/if.h"
7036403Ssklower #include "../net/route.h"
7136403Ssklower 
7237469Ssklower #include "argo_debug.h"
7337469Ssklower #include "tp_param.h"
7437469Ssklower #include "tp_stat.h"
7537469Ssklower #include "tp_pcb.h"
7637469Ssklower #include "tp_trace.h"
7737469Ssklower #include "tp_stat.h"
7837469Ssklower #include "tp_tpdu.h"
7937469Ssklower #include "tp_clnp.h"
8039926Ssklower #include "cltp_var.h"
8136403Ssklower 
8236403Ssklower /*
8336403Ssklower  * CALLED FROM:
8436403Ssklower  * 	pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
8537469Ssklower  * FUNCTION, ARGUMENTS:
8636403Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
8736403Ssklower  */
8836403Ssklower 
8937469Ssklower iso_getsufx(isop, lenp, data_out, which)
9036403Ssklower 	struct isopcb *isop;
9137469Ssklower 	u_short *lenp;
9237469Ssklower 	caddr_t data_out;
9336403Ssklower 	int which;
9436403Ssklower {
9537469Ssklower 	register struct sockaddr_iso *addr = 0;
9637469Ssklower 
9736403Ssklower 	switch (which) {
9836403Ssklower 	case TP_LOCAL:
9937469Ssklower 		addr = isop->isop_laddr;
10037469Ssklower 		break;
10136403Ssklower 
10236403Ssklower 	case TP_FOREIGN:
10337469Ssklower 		addr = isop->isop_faddr;
10436403Ssklower 	}
10537469Ssklower 	if (addr)
10638841Ssklower 		bcopy(TSEL(addr), data_out, (*lenp = addr->siso_tlen));
10736403Ssklower }
10836403Ssklower 
10936403Ssklower /* CALLED FROM:
11036403Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
11136403Ssklower  * 	incoming CR_TPDU.
11236403Ssklower  *
11336403Ssklower  * FUNCTION, ARGUMENTS:
11436403Ssklower  * 	Put a transport suffix (found in name) into an isopcb structure (isop).
11536403Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
11636403Ssklower  */
11736403Ssklower void
11837469Ssklower iso_putsufx(isop, sufxloc, sufxlen, which)
11936403Ssklower 	struct isopcb *isop;
12037469Ssklower 	caddr_t sufxloc;
12137469Ssklower 	int sufxlen, which;
12236403Ssklower {
12337469Ssklower 	struct sockaddr_iso **dst, *backup;
12437469Ssklower 	register struct sockaddr_iso *addr;
12537469Ssklower 	struct mbuf *m;
12637469Ssklower 	int len;
12737469Ssklower 
12836403Ssklower 	switch (which) {
12937469Ssklower 	default:
13037469Ssklower 		return;
13137469Ssklower 
13236403Ssklower 	case TP_LOCAL:
13337469Ssklower 		dst = &isop->isop_laddr;
13437469Ssklower 		backup = &isop->isop_sladdr;
13536403Ssklower 		break;
13637469Ssklower 
13736403Ssklower 	case TP_FOREIGN:
13837469Ssklower 		dst = &isop->isop_faddr;
13937469Ssklower 		backup = &isop->isop_sfaddr;
14036403Ssklower 	}
14137469Ssklower 	if ((addr = *dst) == 0) {
14237469Ssklower 		addr = *dst = backup;
14337469Ssklower 		addr->siso_nlen = 0;
14438841Ssklower 		addr->siso_slen = 0;
14538841Ssklower 		addr->siso_plen = 0;
14637469Ssklower 		printf("iso_putsufx on un-initialized isopcb\n");
14737469Ssklower 	}
14837469Ssklower 	len = sufxlen + addr->siso_nlen +
14938841Ssklower 			(sizeof(*addr) - sizeof(addr->siso_data));
15037469Ssklower 	if (addr == backup) {
15138841Ssklower 		if (len > sizeof(*addr)) {
15237469Ssklower 				m = m_getclr(M_DONTWAIT, MT_SONAME);
15337469Ssklower 				if (m == 0)
15437469Ssklower 					return;
15537469Ssklower 				addr = *dst = mtod(m, struct sockaddr_iso *);
15637469Ssklower 				*addr = *backup;
15737469Ssklower 				m->m_len = len;
15837469Ssklower 		}
15938841Ssklower 	}
16037469Ssklower 	bcopy(sufxloc, TSEL(addr), sufxlen);
16138841Ssklower 	addr->siso_tlen = sufxlen;
16237469Ssklower 	addr->siso_len = len;
16336403Ssklower }
16436403Ssklower 
16536403Ssklower /*
16636403Ssklower  * CALLED FROM:
16736403Ssklower  * 	tp.trans whenever we go into REFWAIT state.
16836403Ssklower  * FUNCTION and ARGUMENT:
16936403Ssklower  *	 Called when a ref is frozen, to allow the suffix to be reused.
17036403Ssklower  * 	(isop) is the net level pcb.  This really shouldn't have to be
17136403Ssklower  * 	done in a NET level pcb but... for the internet world that just
17236403Ssklower  * 	the way it is done in BSD...
17336403Ssklower  * 	The alternative is to have the port unusable until the reference
17436403Ssklower  * 	timer goes off.
17536403Ssklower  */
17636403Ssklower void
17736403Ssklower iso_recycle_tsuffix(isop)
17836403Ssklower 	struct isopcb	*isop;
17936403Ssklower {
18038841Ssklower 	isop->isop_laddr->siso_tlen = isop->isop_faddr->siso_tlen = 0;
18136403Ssklower }
18236403Ssklower 
18336403Ssklower /*
18436403Ssklower  * CALLED FROM:
18536403Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
18636403Ssklower  * 	incoming CR_TPDU.
18736403Ssklower  *
18836403Ssklower  * FUNCTION and ARGUMENTS:
18936403Ssklower  * 	Copy a whole net addr from a struct sockaddr (name).
19036403Ssklower  * 	into an isopcb (isop).
19136403Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
19236403Ssklower  */
19336403Ssklower void
19436403Ssklower iso_putnetaddr(isop, name, which)
19536403Ssklower 	register struct isopcb	*isop;
19636403Ssklower 	struct sockaddr_iso	*name;
19736403Ssklower 	int which;
19836403Ssklower {
19937469Ssklower 	struct sockaddr_iso **sisop, *backup;
20037469Ssklower 	register struct sockaddr_iso *siso;
20137469Ssklower 
20236403Ssklower 	switch (which) {
203*44422Ssklower 	default:
204*44422Ssklower 		printf("iso_putnetaddr: should panic\n");
205*44422Ssklower 		return;
20636403Ssklower 	case TP_LOCAL:
20737469Ssklower 		sisop = &isop->isop_laddr;
20837469Ssklower 		backup = &isop->isop_sladdr;
20936403Ssklower 		break;
21036403Ssklower 	case TP_FOREIGN:
21137469Ssklower 		sisop = &isop->isop_faddr;
21237469Ssklower 		backup = &isop->isop_sfaddr;
21336403Ssklower 	}
21437469Ssklower 	siso = ((*sisop == 0) ? (*sisop = backup) : *sisop);
21537469Ssklower 	IFDEBUG(D_TPISO)
21637469Ssklower 		printf("ISO_PUTNETADDR\n");
21737469Ssklower 		dump_isoaddr(isop->isop_faddr);
21837469Ssklower 	ENDDEBUG
21937469Ssklower 	siso->siso_addr = name->siso_addr;
22036403Ssklower }
22136403Ssklower 
22236403Ssklower /*
22336403Ssklower  * CALLED FROM:
224*44422Ssklower  * 	tp_input() when a connection is being established by an
225*44422Ssklower  * 	incoming CR_TPDU, and considered for interception.
226*44422Ssklower  *
227*44422Ssklower  * FUNCTION and ARGUMENTS:
228*44422Ssklower  * 	compare a whole net addr from a struct sockaddr (name),
229*44422Ssklower  * 	with that implicitly stored in an isopcb (isop).
230*44422Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
231*44422Ssklower  */
232*44422Ssklower iso_cmpnetaddr(isop, name, which)
233*44422Ssklower 	register struct isopcb	*isop;
234*44422Ssklower 	register struct sockaddr_iso	*name;
235*44422Ssklower 	int which;
236*44422Ssklower {
237*44422Ssklower 	struct sockaddr_iso **sisop, *backup;
238*44422Ssklower 	register struct sockaddr_iso *siso;
239*44422Ssklower 
240*44422Ssklower 	switch (which) {
241*44422Ssklower 	default:
242*44422Ssklower 		printf("iso_cmpnetaddr: should panic\n");
243*44422Ssklower 		return 0;
244*44422Ssklower 	case TP_LOCAL:
245*44422Ssklower 		sisop = &isop->isop_laddr;
246*44422Ssklower 		backup = &isop->isop_sladdr;
247*44422Ssklower 		break;
248*44422Ssklower 	case TP_FOREIGN:
249*44422Ssklower 		sisop = &isop->isop_faddr;
250*44422Ssklower 		backup = &isop->isop_sfaddr;
251*44422Ssklower 	}
252*44422Ssklower 	siso = ((*sisop == 0) ? (*sisop = backup) : *sisop);
253*44422Ssklower 	IFDEBUG(D_TPISO)
254*44422Ssklower 		printf("ISO_CMPNETADDR\n");
255*44422Ssklower 		dump_isoaddr(siso);
256*44422Ssklower 	ENDDEBUG
257*44422Ssklower 	if (name->siso_tlen && bcmp(TSEL(name), TSEL(siso), name->siso_tlen))
258*44422Ssklower 		return (0);
259*44422Ssklower 	return (bcmp((caddr_t)name->siso_data,
260*44422Ssklower 			 (caddr_t)siso->siso_data, name->siso_nlen) == 0);
261*44422Ssklower }
262*44422Ssklower 
263*44422Ssklower /*
264*44422Ssklower  * CALLED FROM:
26536403Ssklower  *  pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
26636403Ssklower  * FUNCTION and ARGUMENTS:
26736403Ssklower  * 	Copy a whole net addr from an isopcb (isop) into
26836403Ssklower  * 	a struct sockaddr (name).
26936403Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
27036403Ssklower  */
27136403Ssklower 
27236403Ssklower void
27336403Ssklower iso_getnetaddr( isop, name, which)
27436403Ssklower 	struct isopcb *isop;
27537469Ssklower 	struct mbuf *name;
27636403Ssklower 	int which;
27736403Ssklower {
27837469Ssklower 	struct sockaddr_iso *siso =
27937469Ssklower 		(which == TP_LOCAL ? isop->isop_laddr : isop->isop_faddr);
28037469Ssklower 	if (siso)
28137469Ssklower 		bcopy((caddr_t)siso, mtod(name, caddr_t),
28237469Ssklower 				(unsigned)(name->m_len = siso->siso_len));
28337469Ssklower 	else
28437469Ssklower 		name->m_len = 0;
28536403Ssklower }
28636403Ssklower 
28736403Ssklower /*
28836403Ssklower  * CALLED FROM:
28936403Ssklower  *  tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
29036403Ssklower  * FUNCTION, ARGUMENTS, SIDE EFFECTS and RETURN VALUE:
29136403Ssklower  * Determine the proper maximum transmission unit, i.e., MTU, to use, given
29236403Ssklower  * a) the header size for the network protocol and the max transmission
29336403Ssklower  *	  unit on the subnet interface, determined from the information in (isop),
29436403Ssklower  * b) the max size negotiated so far (negot)
29536403Ssklower  * c) the window size used by the tp connection (found in so),
29636403Ssklower  *
29736403Ssklower  * The result is put in the integer *size in its integer form and in
29836403Ssklower  * *negot in its logarithmic form.
29936403Ssklower  *
30036403Ssklower  * The rules are:
30136403Ssklower  * a) can only negotiate down from the value found in *negot.
30236403Ssklower  * b) the MTU must be < the windowsize,
30336403Ssklower  * c) If src and dest are on the same net,
30436403Ssklower  * 	  we will negotiate the closest size larger than  MTU but really USE
30536403Ssklower  *    the actual device mtu - ll hdr sizes.
30636403Ssklower  *   otherwise we negotiate the closest size smaller than MTU - ll hdr sizes.
30736403Ssklower  */
30836403Ssklower 
30936403Ssklower void
31036403Ssklower tpclnp_mtu(so, isop, size, negot )
31136403Ssklower 	struct socket *so;
31236403Ssklower 	struct isopcb *isop;
31336403Ssklower 	int *size;
31436403Ssklower 	u_char *negot;
31536403Ssklower {
31639230Ssklower 	struct ifnet *ifp = 0;
31739230Ssklower 	struct iso_ifaddr *ia = 0;
31836403Ssklower 	register int i;
31936403Ssklower 	int windowsize = so->so_rcv.sb_hiwat;
32036403Ssklower 	int clnp_size;
32136403Ssklower 	int sizeismtu = 0;
32239230Ssklower 	register struct rtentry *rt = isop->isop_route.ro_rt;
32336403Ssklower 
32436403Ssklower 	IFDEBUG(D_CONN)
32536403Ssklower 		printf("tpclnp_mtu(0x%x,0x%x,0x%x,0x%x)\n", so, isop, size, negot);
32636403Ssklower 	ENDDEBUG
32736403Ssklower 	IFTRACE(D_CONN)
32836403Ssklower 		tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0);
32936403Ssklower 	ENDTRACE
33036403Ssklower 
33136403Ssklower 	*size = 1 << *negot;
33236403Ssklower 
33336403Ssklower 	if( *size > windowsize ) {
33436403Ssklower 		*size = windowsize;
33536403Ssklower 	}
33636403Ssklower 
33739230Ssklower 	if (rt == 0 || (rt->rt_flags & RTF_UP == 0) ||
33839230Ssklower 		(ia = (struct iso_ifaddr *)rt->rt_ifa) == 0 ||
33939230Ssklower 	    (ifp = ia->ia_ifp) == 0) {
34039230Ssklower 		IFDEBUG(D_CONN)
34139230Ssklower 			printf("tpclnp_mtu routing abort rt=0x%x ia=0x%x ifp=0x%x\n",
34239230Ssklower 					rt, ia, ifp)
34339230Ssklower 		ENDDEBUG
34436403Ssklower 		return;
34539230Ssklower 	}
34636403Ssklower 
34736403Ssklower 	/* TODO - make this indirect off the socket structure to the
34836403Ssklower 	 * network layer to get headersize
34936403Ssklower 	 */
35037469Ssklower 	if (isop->isop_laddr)
35137469Ssklower 		clnp_size = clnp_hdrsize(isop->isop_laddr->siso_addr.isoa_len);
35237469Ssklower 	else
35337469Ssklower 		clnp_size = 20;
35436403Ssklower 
35536403Ssklower 	if(*size > ifp->if_mtu - clnp_size) {
35636403Ssklower 		*size = ifp->if_mtu - clnp_size;
35736403Ssklower 		sizeismtu = 1;
35836403Ssklower 	}
35937469Ssklower 	/* have to transform size to the log2 of size */
36037469Ssklower 	for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i) <= *size)) ; i++)
36137469Ssklower 		;
36237469Ssklower 	i--;
36337469Ssklower 
36436403Ssklower 	IFTRACE(D_CONN)
36536403Ssklower 		tptrace(TPPTmisc, "GET MTU MID: tpcb size negot i \n",
36636403Ssklower 		*size, *negot, i, 0);
36736403Ssklower 	ENDTRACE
36836403Ssklower 
36939926Ssklower 	*size = 1<<i;
37036403Ssklower 	*negot = i;
37136403Ssklower 
37236403Ssklower 	IFDEBUG(D_CONN)
37336403Ssklower 		printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n",
37436403Ssklower 		ifp->if_name,	*size, *negot);
37536403Ssklower 	ENDDEBUG
37636403Ssklower 	IFTRACE(D_CONN)
37736403Ssklower 		tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n",
37836403Ssklower 		*size, *negot, 0, 0);
37936403Ssklower 	ENDTRACE
38036403Ssklower }
38136403Ssklower 
38236403Ssklower 
38336403Ssklower /*
38436403Ssklower  * CALLED FROM:
38536403Ssklower  *  tp_emit()
38636403Ssklower  * FUNCTION and ARGUMENTS:
38736403Ssklower  *  Take a packet(m0) from tp and package it so that clnp will accept it.
38836403Ssklower  *  This means prepending space for the clnp header and filling in a few
38936403Ssklower  *  of the fields.
39036403Ssklower  *  inp is the isopcb structure; datalen is the length of the data in the
39136403Ssklower  *  mbuf string m0.
39236403Ssklower  * RETURN VALUE:
39336403Ssklower  *  whatever (E*) is returned form the net layer output routine.
39436403Ssklower  */
39536403Ssklower 
39636403Ssklower int
39736403Ssklower tpclnp_output(isop, m0, datalen, nochksum)
39836403Ssklower 	struct isopcb		*isop;
39936403Ssklower 	struct mbuf 		*m0;
40036403Ssklower 	int 				datalen;
40136403Ssklower 	int					nochksum;
40236403Ssklower {
40337469Ssklower 	register struct mbuf *m = m0;
40436403Ssklower 	IncStat(ts_tpdu_sent);
40536403Ssklower 
40636403Ssklower 	IFDEBUG(D_TPISO)
40736403Ssklower 		struct tpdu *hdr = mtod(m0, struct tpdu *);
40836403Ssklower 
40936403Ssklower 		printf(
41036403Ssklower "abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n",
41136403Ssklower 			datalen,
41236403Ssklower 			(int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum);
41337469Ssklower 		dump_isoaddr(isop->isop_faddr);
41436403Ssklower 		printf("\nsrc addr:\n");
41537469Ssklower 		dump_isoaddr(isop->isop_laddr);
41636403Ssklower 		dump_mbuf(m0, "at tpclnp_output");
41736403Ssklower 	ENDDEBUG
41836403Ssklower 
41936403Ssklower 	return
42038841Ssklower 		clnp_output(m0, isop, datalen,  /* flags */nochksum ? CLNP_NO_CKSUM : 0);
42136403Ssklower }
42236403Ssklower 
42336403Ssklower /*
42436403Ssklower  * CALLED FROM:
42536403Ssklower  *  tp_error_emit()
42636403Ssklower  * FUNCTION and ARGUMENTS:
42736403Ssklower  *  This is a copy of tpclnp_output that takes the addresses
42836403Ssklower  *  instead of a pcb.  It's used by the tp_error_emit, when we
42936403Ssklower  *  don't have an iso_pcb with which to call the normal output rtn.
43036403Ssklower  * RETURN VALUE:
43136403Ssklower  *  ENOBUFS or
43236403Ssklower  *  whatever (E*) is returned form the net layer output routine.
43336403Ssklower  */
43436403Ssklower 
43536403Ssklower int
43636403Ssklower tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
43736403Ssklower 	struct iso_addr		*laddr, *faddr;
43836403Ssklower 	struct mbuf 		*m0;
43936403Ssklower 	int 				datalen;
44036403Ssklower 	struct route 		*ro;
44136403Ssklower 	int					nochksum;
44236403Ssklower {
44336403Ssklower 	struct isopcb		tmppcb;
44436403Ssklower 	int					err;
44536403Ssklower 	int					flags;
44637469Ssklower 	register struct mbuf *m = m0;
44736403Ssklower 
44836403Ssklower 	IFDEBUG(D_TPISO)
44936403Ssklower 		printf("tpclnp_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
45036403Ssklower 	ENDDEBUG
45136403Ssklower 
45236403Ssklower 	/*
45336403Ssklower 	 *	Fill in minimal portion of isopcb so that clnp can send the
45436403Ssklower 	 *	packet.
45536403Ssklower 	 */
45636403Ssklower 	bzero((caddr_t)&tmppcb, sizeof(tmppcb));
45737469Ssklower 	tmppcb.isop_laddr = &tmppcb.isop_sladdr;
45837469Ssklower 	tmppcb.isop_laddr->siso_addr = *laddr;
45937469Ssklower 	tmppcb.isop_faddr = &tmppcb.isop_sfaddr;
46037469Ssklower 	tmppcb.isop_faddr->siso_addr = *faddr;
46136403Ssklower 
46236403Ssklower 	IFDEBUG(D_TPISO)
46336403Ssklower 		printf("tpclnp_output_dg  faddr: \n");
46437469Ssklower 		dump_isoaddr(&tmppcb.isop_sfaddr);
46536403Ssklower 		printf("\ntpclnp_output_dg  laddr: \n");
46637469Ssklower 		dump_isoaddr(&tmppcb.isop_sladdr);
46736403Ssklower 		printf("\n");
46836403Ssklower 	ENDDEBUG
46936403Ssklower 
47036403Ssklower 	/*
47136403Ssklower 	 *	Do not use packet cache since this is a one shot error packet
47236403Ssklower 	 */
47336403Ssklower 	flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0));
47436403Ssklower 
47536403Ssklower 	IncStat(ts_tpdu_sent);
47636403Ssklower 
47738841Ssklower 	err = clnp_output(m0, &tmppcb, datalen,  flags);
47836403Ssklower 
47936403Ssklower 	/*
48036403Ssklower 	 *	Free route allocated by clnp (if the route was indeed allocated)
48136403Ssklower 	 */
48236403Ssklower 	if (tmppcb.isop_route.ro_rt)
48336403Ssklower 		RTFREE(tmppcb.isop_route.ro_rt);
48436403Ssklower 
48536403Ssklower 	return(err);
48636403Ssklower }
48736403Ssklower /*
48836403Ssklower  * CALLED FROM:
48936403Ssklower  * 	clnp's input routine, indirectly through the protosw.
49036403Ssklower  * FUNCTION and ARGUMENTS:
49136403Ssklower  * Take a packet (m) from clnp, strip off the clnp header and give it to tp
49236403Ssklower  * No return value.
49336403Ssklower  */
49436403Ssklower ProtoHook
49539927Ssklower tpclnp_input(m, src, dst, clnp_len, ce_bit)
49639926Ssklower 	register struct mbuf *m;
49739926Ssklower 	struct sockaddr_iso *src, *dst;
49839927Ssklower 	int clnp_len, ce_bit;
49936403Ssklower {
50036403Ssklower 	int s = splnet();
50137469Ssklower 	struct mbuf *tp_inputprep();
50239926Ssklower 	int tp_input(), cltp_input(), (*input)() = tp_input;
50336403Ssklower 
50436403Ssklower 	IncStat(ts_pkt_rcvd);
50536403Ssklower 
50636403Ssklower 	IFDEBUG(D_TPINPUT)
50736403Ssklower 		printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len);
50836403Ssklower 		dump_mbuf(m, "at tpclnp_input");
50936403Ssklower 	ENDDEBUG
51036403Ssklower 	/*
51136403Ssklower 	 * CLNP gives us an mbuf chain WITH the clnp header pulled up,
51236403Ssklower 	 * and the length of the clnp header.
51336403Ssklower 	 * First, strip off the Clnp header. leave the mbuf there for the
51436403Ssklower 	 * pullup that follows.
51536403Ssklower 	 */
51636403Ssklower 
51736403Ssklower 	m->m_len -= clnp_len;
51837469Ssklower 	m->m_data += clnp_len;
51936403Ssklower 
52037469Ssklower 	m = tp_inputprep(m);
52139926Ssklower 	if (m == 0)
52239926Ssklower 		return 0;
52339926Ssklower 	if (mtod(m, u_char *)[1] == UD_TPDU_type)
52439926Ssklower 		input = cltp_input;
52536403Ssklower 
52636403Ssklower 	IFDEBUG(D_TPINPUT)
52736403Ssklower 		dump_mbuf(m, "after tpclnp_input both pullups");
52836403Ssklower 	ENDDEBUG
52936403Ssklower 
53036403Ssklower 	IFDEBUG(D_TPISO)
53139926Ssklower 		printf("calling %sinput : src 0x%x, dst 0x%x, src addr:\n",
53239926Ssklower 			(input == tp_input ? "tp_" : "clts_"), src, dst);
53339926Ssklower 		dump_isoaddr(src);
53436403Ssklower 		printf(" dst addr:\n");
53539926Ssklower 		dump_isoaddr(dst);
53636403Ssklower 	ENDDEBUG
53736403Ssklower 
53839926Ssklower 	(void) (*input)(m, (struct sockaddr *)src, (struct sockaddr *)dst,
53939927Ssklower 				0, tpclnp_output_dg, ce_bit);
54036403Ssklower 
54136403Ssklower 	IFDEBUG(D_QUENCH)
54236403Ssklower 		{
54336403Ssklower 			if(time.tv_usec & 0x4 && time.tv_usec & 0x40) {
54436403Ssklower 				printf("tpclnp_input: FAKING %s\n",
54536403Ssklower 					tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2");
54636403Ssklower 				if(tp_stat.ts_pkt_rcvd & 0x1) {
54736403Ssklower 					tpclnp_ctlinput(PRC_QUENCH, &src);
54836403Ssklower 				} else {
54936403Ssklower 					tpclnp_ctlinput(PRC_QUENCH2, &src);
55036403Ssklower 				}
55136403Ssklower 			}
55236403Ssklower 		}
55336403Ssklower 	ENDDEBUG
55436403Ssklower 
55536403Ssklower 	splx(s);
55636403Ssklower 	return 0;
55736403Ssklower }
55836403Ssklower 
55936403Ssklower ProtoHook
56036403Ssklower iso_rtchange()
56136403Ssklower {
56236403Ssklower 	return 0;
56336403Ssklower }
56436403Ssklower 
56536403Ssklower /*
56636403Ssklower  * CALLED FROM:
56736403Ssklower  *  tpclnp_ctlinput()
56836403Ssklower  * FUNCTION and ARGUMENTS:
56936403Ssklower  *  find the tpcb pointer and pass it to tp_quench
57036403Ssklower  */
57136403Ssklower void
57236403Ssklower tpiso_decbit(isop)
57336403Ssklower 	struct isopcb *isop;
57436403Ssklower {
57537469Ssklower 	tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH2);
57636403Ssklower }
57736403Ssklower /*
57836403Ssklower  * CALLED FROM:
57936403Ssklower  *  tpclnp_ctlinput()
58036403Ssklower  * FUNCTION and ARGUMENTS:
58136403Ssklower  *  find the tpcb pointer and pass it to tp_quench
58236403Ssklower  */
58336403Ssklower void
58436403Ssklower tpiso_quench(isop)
58536403Ssklower 	struct isopcb *isop;
58636403Ssklower {
58737469Ssklower 	tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH);
58836403Ssklower }
58936403Ssklower 
59036403Ssklower /*
59136403Ssklower  * CALLED FROM:
59236403Ssklower  *  The network layer through the protosw table.
59336403Ssklower  * FUNCTION and ARGUMENTS:
59436403Ssklower  *	When clnp an ICMP-like msg this gets called.
59536403Ssklower  *	It either returns an error status to the user or
59636403Ssklower  *	it causes all connections on this address to be aborted
59736403Ssklower  *	by calling the appropriate xx_notify() routine.
59836403Ssklower  *	(cmd) is the type of ICMP error.
59936403Ssklower  * 	(siso) is the address of the guy who sent the ER CLNPDU
60036403Ssklower  */
60136403Ssklower ProtoHook
60236403Ssklower tpclnp_ctlinput(cmd, siso)
60336403Ssklower 	int cmd;
60436403Ssklower 	struct sockaddr_iso *siso;
60536403Ssklower {
60636403Ssklower 	extern u_char inetctlerrmap[];
60736403Ssklower 	extern ProtoHook tpiso_abort();
60836403Ssklower 	extern ProtoHook iso_rtchange();
60936403Ssklower 	extern ProtoHook tpiso_reset();
61037469Ssklower 	void iso_pcbnotify();
61136403Ssklower 
61236403Ssklower 	IFDEBUG(D_TPINPUT)
61339926Ssklower 		printf("tpclnp_ctlinput1: cmd 0x%x addr: \n", cmd);
61439926Ssklower 		dump_isoaddr(siso);
61536403Ssklower 	ENDDEBUG
61636403Ssklower 
61736403Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
61836403Ssklower 		return 0;
61939926Ssklower 	if (siso->siso_family != AF_ISO)
62039926Ssklower 		return 0;
62136403Ssklower 	switch (cmd) {
62236403Ssklower 
62336403Ssklower 		case	PRC_QUENCH2:
62439926Ssklower 			iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_decbit);
62536403Ssklower 			break;
62636403Ssklower 
62736403Ssklower 		case	PRC_QUENCH:
62839926Ssklower 			iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_quench);
62936403Ssklower 			break;
63036403Ssklower 
63136403Ssklower 		case	PRC_TIMXCEED_REASS:
63236403Ssklower 		case	PRC_ROUTEDEAD:
63339926Ssklower 			iso_pcbnotify(&tp_isopcb, siso, 0, tpiso_reset);
63436403Ssklower 			break;
63536403Ssklower 
63636403Ssklower 		case	PRC_HOSTUNREACH:
63736403Ssklower 		case	PRC_UNREACH_NET:
63836403Ssklower 		case	PRC_IFDOWN:
63936403Ssklower 		case	PRC_HOSTDEAD:
64039926Ssklower 			iso_pcbnotify(&tp_isopcb, siso,
64136403Ssklower 					(int)inetctlerrmap[cmd], iso_rtchange);
64236403Ssklower 			break;
64336403Ssklower 
64436403Ssklower 		default:
64536403Ssklower 		/*
64636403Ssklower 		case	PRC_MSGSIZE:
64736403Ssklower 		case	PRC_UNREACH_HOST:
64836403Ssklower 		case	PRC_UNREACH_PROTOCOL:
64936403Ssklower 		case	PRC_UNREACH_PORT:
65036403Ssklower 		case	PRC_UNREACH_NEEDFRAG:
65136403Ssklower 		case	PRC_UNREACH_SRCFAIL:
65236403Ssklower 		case	PRC_REDIRECT_NET:
65336403Ssklower 		case	PRC_REDIRECT_HOST:
65436403Ssklower 		case	PRC_REDIRECT_TOSNET:
65536403Ssklower 		case	PRC_REDIRECT_TOSHOST:
65636403Ssklower 		case	PRC_TIMXCEED_INTRANS:
65736403Ssklower 		case	PRC_PARAMPROB:
65836403Ssklower 		*/
65939926Ssklower 		iso_pcbnotify(&tp_isopcb, siso, (int)inetctlerrmap[cmd], tpiso_abort);
66036403Ssklower 		break;
66136403Ssklower 	}
66236403Ssklower 	return 0;
66336403Ssklower }
66439926Ssklower /*
66539926Ssklower  * XXX - Variant which is called by clnp_er.c with an isoaddr rather
66639926Ssklower  * than a sockaddr_iso.
66739926Ssklower  */
66836403Ssklower 
66939926Ssklower static struct sockaddr_iso siso = {sizeof(siso), AF_ISO};
67039926Ssklower tpclnp_ctlinput1(cmd, isoa)
67139926Ssklower 	int cmd;
67239926Ssklower 	struct iso_addr *isoa;
67339926Ssklower {
67439926Ssklower 	bzero((caddr_t)&siso.siso_addr, sizeof(siso.siso_addr));
67539926Ssklower 	bcopy((caddr_t)isoa, (caddr_t)&siso.siso_addr, isoa->isoa_len);
67639926Ssklower 	tpclnp_ctlinput(cmd, &siso);
67739926Ssklower }
67839926Ssklower 
67936403Ssklower /*
68036403Ssklower  * These next 2 routines are
68136403Ssklower  * CALLED FROM:
68236403Ssklower  *	xxx_notify() from tp_ctlinput() when
68336403Ssklower  *  net level gets some ICMP-equiv. type event.
68436403Ssklower  * FUNCTION and ARGUMENTS:
68536403Ssklower  *  Cause the connection to be aborted with some sort of error
68636403Ssklower  *  reason indicating that the network layer caused the abort.
68736403Ssklower  *  Fakes an ER TPDU so we can go through the driver.
68836403Ssklower  *  abort always aborts the TP connection.
68936403Ssklower  *  reset may or may not, depending on the TP class that's in use.
69036403Ssklower  */
69136403Ssklower ProtoHook
69236403Ssklower tpiso_abort(isop)
69336403Ssklower 	struct isopcb *isop;
69436403Ssklower {
69536403Ssklower 	struct tp_event e;
69636403Ssklower 
69736403Ssklower 	IFDEBUG(D_CONN)
69836403Ssklower 		printf("tpiso_abort 0x%x\n", isop);
69936403Ssklower 	ENDDEBUG
70036403Ssklower 	e.ev_number = ER_TPDU;
70136403Ssklower 	e.ATTR(ER_TPDU).e_reason = ECONNABORTED;
70236403Ssklower 	return  tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e);
70336403Ssklower }
70436403Ssklower 
70536403Ssklower ProtoHook
70636403Ssklower tpiso_reset(isop)
70736403Ssklower 	struct isopcb *isop;
70836403Ssklower {
70936403Ssklower 	struct tp_event e;
71036403Ssklower 
71136403Ssklower 	e.ev_number = T_NETRESET;
71236403Ssklower 	return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e);
71336403Ssklower 
71436403Ssklower }
71536403Ssklower 
71636403Ssklower #endif ISO
717