xref: /csrg-svn/sys/netiso/tp_iso.c (revision 49268)
1*49268Sbostic /*-
2*49268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
3*49268Sbostic  * All rights reserved.
4*49268Sbostic  *
5*49268Sbostic  * %sccs.include.redist.c%
6*49268Sbostic  *
7*49268Sbostic  *	@(#)tp_iso.c	7.11 (Berkeley) 05/06/91
8*49268Sbostic  */
9*49268Sbostic 
1036403Ssklower /***********************************************************
1136403Ssklower 		Copyright IBM Corporation 1987
1236403Ssklower 
1336403Ssklower                       All Rights Reserved
1436403Ssklower 
1536403Ssklower Permission to use, copy, modify, and distribute this software and its
1636403Ssklower documentation for any purpose and without fee is hereby granted,
1736403Ssklower provided that the above copyright notice appear in all copies and that
1836403Ssklower both that copyright notice and this permission notice appear in
1936403Ssklower supporting documentation, and that the name of IBM not be
2036403Ssklower used in advertising or publicity pertaining to distribution of the
2136403Ssklower software without specific, written prior permission.
2236403Ssklower 
2336403Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436403Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536403Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636403Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736403Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836403Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936403Ssklower SOFTWARE.
3036403Ssklower 
3136403Ssklower ******************************************************************/
3236403Ssklower 
3336403Ssklower /*
3436403Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536403Ssklower  */
3636403Ssklower /*
3736403Ssklower  * ARGO TP
3837469Ssklower  * $Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $
3937469Ssklower  * $Source: /var/src/sys/netiso/RCS/tp_iso.c,v $
4036403Ssklower  *
4136403Ssklower  * Here is where you find the iso-dependent code.  We've tried
4236403Ssklower  * keep all net-level and (primarily) address-family-dependent stuff
4336403Ssklower  * out of the tp source, and everthing here is reached indirectly
4436403Ssklower  * through a switch table (struct nl_protosw *) tpcb->tp_nlproto
4536403Ssklower  * (see tp_pcb.c).
4636403Ssklower  * The routines here are:
4736403Ssklower  * 		iso_getsufx: gets transport suffix out of an isopcb structure.
4836403Ssklower  * 		iso_putsufx: put transport suffix into an isopcb structure.
4936403Ssklower  *		iso_putnetaddr: put a whole net addr into an isopcb.
5036403Ssklower  *		iso_getnetaddr: get a whole net addr from an isopcb.
5144422Ssklower  *		iso_cmpnetaddr: compare a whole net addr from an isopcb.
5236403Ssklower  *		iso_recycle_suffix: clear suffix for reuse in isopcb
5336403Ssklower  * 		tpclnp_ctlinput: handle ER CNLPdu : icmp-like stuff
5436403Ssklower  * 		tpclnp_mtu: figure out what size tpdu to use
5536403Ssklower  *		tpclnp_input: take a pkt from clnp, strip off its clnp header,
5636403Ssklower  *				give to tp
5736403Ssklower  *		tpclnp_output_dg: package a pkt for clnp given 2 addresses & some data
5836403Ssklower  *		tpclnp_output: package a pkt for clnp given an isopcb & some data
5936403Ssklower  */
6036403Ssklower 
6136403Ssklower #ifdef ISO
6236403Ssklower 
6337469Ssklower #include "param.h"
6437469Ssklower #include "socket.h"
6537469Ssklower #include "socketvar.h"
6637469Ssklower #include "domain.h"
6737469Ssklower #include "malloc.h"
6837469Ssklower #include "mbuf.h"
6937469Ssklower #include "errno.h"
7037469Ssklower #include "time.h"
7137469Ssklower #include "protosw.h"
7237469Ssklower 
7336403Ssklower #include "../net/if.h"
7436403Ssklower #include "../net/route.h"
7536403Ssklower 
7637469Ssklower #include "argo_debug.h"
7737469Ssklower #include "tp_param.h"
7837469Ssklower #include "tp_stat.h"
7937469Ssklower #include "tp_pcb.h"
8037469Ssklower #include "tp_trace.h"
8137469Ssklower #include "tp_stat.h"
8237469Ssklower #include "tp_tpdu.h"
8337469Ssklower #include "tp_clnp.h"
8439926Ssklower #include "cltp_var.h"
8536403Ssklower 
8636403Ssklower /*
8736403Ssklower  * CALLED FROM:
8836403Ssklower  * 	pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
8937469Ssklower  * FUNCTION, ARGUMENTS:
9036403Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
9136403Ssklower  */
9236403Ssklower 
9337469Ssklower iso_getsufx(isop, lenp, data_out, which)
9436403Ssklower 	struct isopcb *isop;
9537469Ssklower 	u_short *lenp;
9637469Ssklower 	caddr_t data_out;
9736403Ssklower 	int which;
9836403Ssklower {
9937469Ssklower 	register struct sockaddr_iso *addr = 0;
10037469Ssklower 
10136403Ssklower 	switch (which) {
10236403Ssklower 	case TP_LOCAL:
10337469Ssklower 		addr = isop->isop_laddr;
10437469Ssklower 		break;
10536403Ssklower 
10636403Ssklower 	case TP_FOREIGN:
10737469Ssklower 		addr = isop->isop_faddr;
10836403Ssklower 	}
10937469Ssklower 	if (addr)
11038841Ssklower 		bcopy(TSEL(addr), data_out, (*lenp = addr->siso_tlen));
11136403Ssklower }
11236403Ssklower 
11336403Ssklower /* CALLED FROM:
11436403Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
11536403Ssklower  * 	incoming CR_TPDU.
11636403Ssklower  *
11736403Ssklower  * FUNCTION, ARGUMENTS:
11836403Ssklower  * 	Put a transport suffix (found in name) into an isopcb structure (isop).
11936403Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
12036403Ssklower  */
12136403Ssklower void
12237469Ssklower iso_putsufx(isop, sufxloc, sufxlen, which)
12336403Ssklower 	struct isopcb *isop;
12437469Ssklower 	caddr_t sufxloc;
12537469Ssklower 	int sufxlen, which;
12636403Ssklower {
12737469Ssklower 	struct sockaddr_iso **dst, *backup;
12837469Ssklower 	register struct sockaddr_iso *addr;
12937469Ssklower 	struct mbuf *m;
13037469Ssklower 	int len;
13137469Ssklower 
13236403Ssklower 	switch (which) {
13337469Ssklower 	default:
13437469Ssklower 		return;
13537469Ssklower 
13636403Ssklower 	case TP_LOCAL:
13737469Ssklower 		dst = &isop->isop_laddr;
13837469Ssklower 		backup = &isop->isop_sladdr;
13936403Ssklower 		break;
14037469Ssklower 
14136403Ssklower 	case TP_FOREIGN:
14237469Ssklower 		dst = &isop->isop_faddr;
14337469Ssklower 		backup = &isop->isop_sfaddr;
14436403Ssklower 	}
14537469Ssklower 	if ((addr = *dst) == 0) {
14637469Ssklower 		addr = *dst = backup;
14737469Ssklower 		addr->siso_nlen = 0;
14838841Ssklower 		addr->siso_slen = 0;
14938841Ssklower 		addr->siso_plen = 0;
15037469Ssklower 		printf("iso_putsufx on un-initialized isopcb\n");
15137469Ssklower 	}
15237469Ssklower 	len = sufxlen + addr->siso_nlen +
15338841Ssklower 			(sizeof(*addr) - sizeof(addr->siso_data));
15437469Ssklower 	if (addr == backup) {
15538841Ssklower 		if (len > sizeof(*addr)) {
15637469Ssklower 				m = m_getclr(M_DONTWAIT, MT_SONAME);
15737469Ssklower 				if (m == 0)
15837469Ssklower 					return;
15937469Ssklower 				addr = *dst = mtod(m, struct sockaddr_iso *);
16037469Ssklower 				*addr = *backup;
16137469Ssklower 				m->m_len = len;
16237469Ssklower 		}
16338841Ssklower 	}
16437469Ssklower 	bcopy(sufxloc, TSEL(addr), sufxlen);
16538841Ssklower 	addr->siso_tlen = sufxlen;
16637469Ssklower 	addr->siso_len = len;
16736403Ssklower }
16836403Ssklower 
16936403Ssklower /*
17036403Ssklower  * CALLED FROM:
17136403Ssklower  * 	tp.trans whenever we go into REFWAIT state.
17236403Ssklower  * FUNCTION and ARGUMENT:
17336403Ssklower  *	 Called when a ref is frozen, to allow the suffix to be reused.
17436403Ssklower  * 	(isop) is the net level pcb.  This really shouldn't have to be
17536403Ssklower  * 	done in a NET level pcb but... for the internet world that just
17636403Ssklower  * 	the way it is done in BSD...
17736403Ssklower  * 	The alternative is to have the port unusable until the reference
17836403Ssklower  * 	timer goes off.
17936403Ssklower  */
18036403Ssklower void
18136403Ssklower iso_recycle_tsuffix(isop)
18236403Ssklower 	struct isopcb	*isop;
18336403Ssklower {
18438841Ssklower 	isop->isop_laddr->siso_tlen = isop->isop_faddr->siso_tlen = 0;
18536403Ssklower }
18636403Ssklower 
18736403Ssklower /*
18836403Ssklower  * CALLED FROM:
18936403Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
19036403Ssklower  * 	incoming CR_TPDU.
19136403Ssklower  *
19236403Ssklower  * FUNCTION and ARGUMENTS:
19336403Ssklower  * 	Copy a whole net addr from a struct sockaddr (name).
19436403Ssklower  * 	into an isopcb (isop).
19536403Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
19636403Ssklower  */
19736403Ssklower void
19836403Ssklower iso_putnetaddr(isop, name, which)
19936403Ssklower 	register struct isopcb	*isop;
20036403Ssklower 	struct sockaddr_iso	*name;
20136403Ssklower 	int which;
20236403Ssklower {
20337469Ssklower 	struct sockaddr_iso **sisop, *backup;
20437469Ssklower 	register struct sockaddr_iso *siso;
20537469Ssklower 
20636403Ssklower 	switch (which) {
20744422Ssklower 	default:
20844422Ssklower 		printf("iso_putnetaddr: should panic\n");
20944422Ssklower 		return;
21036403Ssklower 	case TP_LOCAL:
21137469Ssklower 		sisop = &isop->isop_laddr;
21237469Ssklower 		backup = &isop->isop_sladdr;
21336403Ssklower 		break;
21436403Ssklower 	case TP_FOREIGN:
21537469Ssklower 		sisop = &isop->isop_faddr;
21637469Ssklower 		backup = &isop->isop_sfaddr;
21736403Ssklower 	}
21837469Ssklower 	siso = ((*sisop == 0) ? (*sisop = backup) : *sisop);
21937469Ssklower 	IFDEBUG(D_TPISO)
22037469Ssklower 		printf("ISO_PUTNETADDR\n");
22137469Ssklower 		dump_isoaddr(isop->isop_faddr);
22237469Ssklower 	ENDDEBUG
22337469Ssklower 	siso->siso_addr = name->siso_addr;
22436403Ssklower }
22536403Ssklower 
22636403Ssklower /*
22736403Ssklower  * CALLED FROM:
22844422Ssklower  * 	tp_input() when a connection is being established by an
22944422Ssklower  * 	incoming CR_TPDU, and considered for interception.
23044422Ssklower  *
23144422Ssklower  * FUNCTION and ARGUMENTS:
23244422Ssklower  * 	compare a whole net addr from a struct sockaddr (name),
23344422Ssklower  * 	with that implicitly stored in an isopcb (isop).
23444422Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
23544422Ssklower  */
23644422Ssklower iso_cmpnetaddr(isop, name, which)
23744422Ssklower 	register struct isopcb	*isop;
23844422Ssklower 	register struct sockaddr_iso	*name;
23944422Ssklower 	int which;
24044422Ssklower {
24144422Ssklower 	struct sockaddr_iso **sisop, *backup;
24244422Ssklower 	register struct sockaddr_iso *siso;
24344422Ssklower 
24444422Ssklower 	switch (which) {
24544422Ssklower 	default:
24644422Ssklower 		printf("iso_cmpnetaddr: should panic\n");
24744422Ssklower 		return 0;
24844422Ssklower 	case TP_LOCAL:
24944422Ssklower 		sisop = &isop->isop_laddr;
25044422Ssklower 		backup = &isop->isop_sladdr;
25144422Ssklower 		break;
25244422Ssklower 	case TP_FOREIGN:
25344422Ssklower 		sisop = &isop->isop_faddr;
25444422Ssklower 		backup = &isop->isop_sfaddr;
25544422Ssklower 	}
25644422Ssklower 	siso = ((*sisop == 0) ? (*sisop = backup) : *sisop);
25744422Ssklower 	IFDEBUG(D_TPISO)
25844422Ssklower 		printf("ISO_CMPNETADDR\n");
25944422Ssklower 		dump_isoaddr(siso);
26044422Ssklower 	ENDDEBUG
26144422Ssklower 	if (name->siso_tlen && bcmp(TSEL(name), TSEL(siso), name->siso_tlen))
26244422Ssklower 		return (0);
26344422Ssklower 	return (bcmp((caddr_t)name->siso_data,
26444422Ssklower 			 (caddr_t)siso->siso_data, name->siso_nlen) == 0);
26544422Ssklower }
26644422Ssklower 
26744422Ssklower /*
26844422Ssklower  * CALLED FROM:
26936403Ssklower  *  pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
27036403Ssklower  * FUNCTION and ARGUMENTS:
27136403Ssklower  * 	Copy a whole net addr from an isopcb (isop) into
27236403Ssklower  * 	a struct sockaddr (name).
27336403Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
27436403Ssklower  */
27536403Ssklower 
27636403Ssklower void
27736403Ssklower iso_getnetaddr( isop, name, which)
27836403Ssklower 	struct isopcb *isop;
27937469Ssklower 	struct mbuf *name;
28036403Ssklower 	int which;
28136403Ssklower {
28237469Ssklower 	struct sockaddr_iso *siso =
28337469Ssklower 		(which == TP_LOCAL ? isop->isop_laddr : isop->isop_faddr);
28437469Ssklower 	if (siso)
28537469Ssklower 		bcopy((caddr_t)siso, mtod(name, caddr_t),
28637469Ssklower 				(unsigned)(name->m_len = siso->siso_len));
28737469Ssklower 	else
28837469Ssklower 		name->m_len = 0;
28936403Ssklower }
29036403Ssklower 
29136403Ssklower /*
29236403Ssklower  * CALLED FROM:
29336403Ssklower  *  tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
29436403Ssklower  * FUNCTION, ARGUMENTS, SIDE EFFECTS and RETURN VALUE:
29536403Ssklower  * Determine the proper maximum transmission unit, i.e., MTU, to use, given
29636403Ssklower  * a) the header size for the network protocol and the max transmission
29736403Ssklower  *	  unit on the subnet interface, determined from the information in (isop),
29836403Ssklower  * b) the max size negotiated so far (negot)
29936403Ssklower  * c) the window size used by the tp connection (found in so),
30036403Ssklower  *
30136403Ssklower  * The result is put in the integer *size in its integer form and in
30236403Ssklower  * *negot in its logarithmic form.
30336403Ssklower  *
30436403Ssklower  * The rules are:
30536403Ssklower  * a) can only negotiate down from the value found in *negot.
30636403Ssklower  * b) the MTU must be < the windowsize,
30736403Ssklower  * c) If src and dest are on the same net,
30836403Ssklower  * 	  we will negotiate the closest size larger than  MTU but really USE
30936403Ssklower  *    the actual device mtu - ll hdr sizes.
31036403Ssklower  *   otherwise we negotiate the closest size smaller than MTU - ll hdr sizes.
31136403Ssklower  */
31236403Ssklower 
31336403Ssklower void
31436403Ssklower tpclnp_mtu(so, isop, size, negot )
31536403Ssklower 	struct socket *so;
31636403Ssklower 	struct isopcb *isop;
31736403Ssklower 	int *size;
31836403Ssklower 	u_char *negot;
31936403Ssklower {
32039230Ssklower 	struct ifnet *ifp = 0;
32139230Ssklower 	struct iso_ifaddr *ia = 0;
32236403Ssklower 	register int i;
32336403Ssklower 	int windowsize = so->so_rcv.sb_hiwat;
32448738Ssklower 	int clnp_size, mtu;
32536403Ssklower 	int sizeismtu = 0;
32639230Ssklower 	register struct rtentry *rt = isop->isop_route.ro_rt;
32736403Ssklower 
32836403Ssklower 	IFDEBUG(D_CONN)
32936403Ssklower 		printf("tpclnp_mtu(0x%x,0x%x,0x%x,0x%x)\n", so, isop, size, negot);
33036403Ssklower 	ENDDEBUG
33136403Ssklower 	IFTRACE(D_CONN)
33236403Ssklower 		tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0);
33336403Ssklower 	ENDTRACE
33436403Ssklower 
33536403Ssklower 	*size = 1 << *negot;
33636403Ssklower 
33736403Ssklower 	if( *size > windowsize ) {
33836403Ssklower 		*size = windowsize;
33936403Ssklower 	}
34036403Ssklower 
34139230Ssklower 	if (rt == 0 || (rt->rt_flags & RTF_UP == 0) ||
34239230Ssklower 		(ia = (struct iso_ifaddr *)rt->rt_ifa) == 0 ||
34339230Ssklower 	    (ifp = ia->ia_ifp) == 0) {
34439230Ssklower 		IFDEBUG(D_CONN)
34539230Ssklower 			printf("tpclnp_mtu routing abort rt=0x%x ia=0x%x ifp=0x%x\n",
34639230Ssklower 					rt, ia, ifp)
34739230Ssklower 		ENDDEBUG
34836403Ssklower 		return;
34939230Ssklower 	}
35036403Ssklower 
35148738Ssklower 
35248738Ssklower 
35336403Ssklower 	/* TODO - make this indirect off the socket structure to the
35436403Ssklower 	 * network layer to get headersize
35536403Ssklower 	 */
35648738Ssklower 	clnp_size = sizeof(struct clnp_fixed) + sizeof(struct clnp_segment) +
35748738Ssklower 			2 * sizeof(struct iso_addr);
35848738Ssklower 	mtu = SN_MTU(ifp, rt) - clnp_size;
35948738Ssklower 	if(*size > mtu) {
36048738Ssklower 		*size = mtu;
36136403Ssklower 		sizeismtu = 1;
36236403Ssklower 	}
36337469Ssklower 	/* have to transform size to the log2 of size */
36447279Ssklower 	for(i=TP_MIN_TPDUSIZE; (i<=TP_MAX_TPDUSIZE && ((1<<i) <= *size)) ; i++)
36537469Ssklower 		;
36637469Ssklower 	i--;
36737469Ssklower 
36836403Ssklower 	IFTRACE(D_CONN)
36936403Ssklower 		tptrace(TPPTmisc, "GET MTU MID: tpcb size negot i \n",
37036403Ssklower 		*size, *negot, i, 0);
37136403Ssklower 	ENDTRACE
37236403Ssklower 
37339926Ssklower 	*size = 1<<i;
37436403Ssklower 	*negot = i;
37536403Ssklower 
37636403Ssklower 	IFDEBUG(D_CONN)
37736403Ssklower 		printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n",
37836403Ssklower 		ifp->if_name,	*size, *negot);
37936403Ssklower 	ENDDEBUG
38036403Ssklower 	IFTRACE(D_CONN)
38136403Ssklower 		tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n",
38236403Ssklower 		*size, *negot, 0, 0);
38336403Ssklower 	ENDTRACE
38436403Ssklower }
38536403Ssklower 
38636403Ssklower 
38736403Ssklower /*
38836403Ssklower  * CALLED FROM:
38936403Ssklower  *  tp_emit()
39036403Ssklower  * FUNCTION and ARGUMENTS:
39136403Ssklower  *  Take a packet(m0) from tp and package it so that clnp will accept it.
39236403Ssklower  *  This means prepending space for the clnp header and filling in a few
39336403Ssklower  *  of the fields.
39436403Ssklower  *  inp is the isopcb structure; datalen is the length of the data in the
39536403Ssklower  *  mbuf string m0.
39636403Ssklower  * RETURN VALUE:
39736403Ssklower  *  whatever (E*) is returned form the net layer output routine.
39836403Ssklower  */
39936403Ssklower 
40036403Ssklower int
40136403Ssklower tpclnp_output(isop, m0, datalen, nochksum)
40236403Ssklower 	struct isopcb		*isop;
40336403Ssklower 	struct mbuf 		*m0;
40436403Ssklower 	int 				datalen;
40536403Ssklower 	int					nochksum;
40636403Ssklower {
40737469Ssklower 	register struct mbuf *m = m0;
40836403Ssklower 	IncStat(ts_tpdu_sent);
40936403Ssklower 
41036403Ssklower 	IFDEBUG(D_TPISO)
41136403Ssklower 		struct tpdu *hdr = mtod(m0, struct tpdu *);
41236403Ssklower 
41336403Ssklower 		printf(
41436403Ssklower "abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n",
41536403Ssklower 			datalen,
41636403Ssklower 			(int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum);
41737469Ssklower 		dump_isoaddr(isop->isop_faddr);
41836403Ssklower 		printf("\nsrc addr:\n");
41937469Ssklower 		dump_isoaddr(isop->isop_laddr);
42036403Ssklower 		dump_mbuf(m0, "at tpclnp_output");
42136403Ssklower 	ENDDEBUG
42236403Ssklower 
42336403Ssklower 	return
42438841Ssklower 		clnp_output(m0, isop, datalen,  /* flags */nochksum ? CLNP_NO_CKSUM : 0);
42536403Ssklower }
42636403Ssklower 
42736403Ssklower /*
42836403Ssklower  * CALLED FROM:
42936403Ssklower  *  tp_error_emit()
43036403Ssklower  * FUNCTION and ARGUMENTS:
43136403Ssklower  *  This is a copy of tpclnp_output that takes the addresses
43236403Ssklower  *  instead of a pcb.  It's used by the tp_error_emit, when we
43336403Ssklower  *  don't have an iso_pcb with which to call the normal output rtn.
43436403Ssklower  * RETURN VALUE:
43536403Ssklower  *  ENOBUFS or
43636403Ssklower  *  whatever (E*) is returned form the net layer output routine.
43736403Ssklower  */
43836403Ssklower 
43936403Ssklower int
44036403Ssklower tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
44136403Ssklower 	struct iso_addr		*laddr, *faddr;
44236403Ssklower 	struct mbuf 		*m0;
44336403Ssklower 	int 				datalen;
44436403Ssklower 	struct route 		*ro;
44536403Ssklower 	int					nochksum;
44636403Ssklower {
44736403Ssklower 	struct isopcb		tmppcb;
44836403Ssklower 	int					err;
44936403Ssklower 	int					flags;
45037469Ssklower 	register struct mbuf *m = m0;
45136403Ssklower 
45236403Ssklower 	IFDEBUG(D_TPISO)
45336403Ssklower 		printf("tpclnp_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
45436403Ssklower 	ENDDEBUG
45536403Ssklower 
45636403Ssklower 	/*
45736403Ssklower 	 *	Fill in minimal portion of isopcb so that clnp can send the
45836403Ssklower 	 *	packet.
45936403Ssklower 	 */
46036403Ssklower 	bzero((caddr_t)&tmppcb, sizeof(tmppcb));
46137469Ssklower 	tmppcb.isop_laddr = &tmppcb.isop_sladdr;
46237469Ssklower 	tmppcb.isop_laddr->siso_addr = *laddr;
46337469Ssklower 	tmppcb.isop_faddr = &tmppcb.isop_sfaddr;
46437469Ssklower 	tmppcb.isop_faddr->siso_addr = *faddr;
46536403Ssklower 
46636403Ssklower 	IFDEBUG(D_TPISO)
46736403Ssklower 		printf("tpclnp_output_dg  faddr: \n");
46837469Ssklower 		dump_isoaddr(&tmppcb.isop_sfaddr);
46936403Ssklower 		printf("\ntpclnp_output_dg  laddr: \n");
47037469Ssklower 		dump_isoaddr(&tmppcb.isop_sladdr);
47136403Ssklower 		printf("\n");
47236403Ssklower 	ENDDEBUG
47336403Ssklower 
47436403Ssklower 	/*
47536403Ssklower 	 *	Do not use packet cache since this is a one shot error packet
47636403Ssklower 	 */
47736403Ssklower 	flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0));
47836403Ssklower 
47936403Ssklower 	IncStat(ts_tpdu_sent);
48036403Ssklower 
48138841Ssklower 	err = clnp_output(m0, &tmppcb, datalen,  flags);
48236403Ssklower 
48336403Ssklower 	/*
48436403Ssklower 	 *	Free route allocated by clnp (if the route was indeed allocated)
48536403Ssklower 	 */
48636403Ssklower 	if (tmppcb.isop_route.ro_rt)
48736403Ssklower 		RTFREE(tmppcb.isop_route.ro_rt);
48836403Ssklower 
48936403Ssklower 	return(err);
49036403Ssklower }
49136403Ssklower /*
49236403Ssklower  * CALLED FROM:
49336403Ssklower  * 	clnp's input routine, indirectly through the protosw.
49436403Ssklower  * FUNCTION and ARGUMENTS:
49536403Ssklower  * Take a packet (m) from clnp, strip off the clnp header and give it to tp
49636403Ssklower  * No return value.
49736403Ssklower  */
49836403Ssklower ProtoHook
49939927Ssklower tpclnp_input(m, src, dst, clnp_len, ce_bit)
50039926Ssklower 	register struct mbuf *m;
50139926Ssklower 	struct sockaddr_iso *src, *dst;
50239927Ssklower 	int clnp_len, ce_bit;
50336403Ssklower {
50436403Ssklower 	int s = splnet();
50537469Ssklower 	struct mbuf *tp_inputprep();
50639926Ssklower 	int tp_input(), cltp_input(), (*input)() = tp_input;
50736403Ssklower 
50836403Ssklower 	IncStat(ts_pkt_rcvd);
50936403Ssklower 
51036403Ssklower 	IFDEBUG(D_TPINPUT)
51136403Ssklower 		printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len);
51236403Ssklower 		dump_mbuf(m, "at tpclnp_input");
51336403Ssklower 	ENDDEBUG
51436403Ssklower 	/*
51536403Ssklower 	 * CLNP gives us an mbuf chain WITH the clnp header pulled up,
51636403Ssklower 	 * and the length of the clnp header.
51736403Ssklower 	 * First, strip off the Clnp header. leave the mbuf there for the
51836403Ssklower 	 * pullup that follows.
51936403Ssklower 	 */
52036403Ssklower 
52136403Ssklower 	m->m_len -= clnp_len;
52237469Ssklower 	m->m_data += clnp_len;
52336403Ssklower 
52437469Ssklower 	m = tp_inputprep(m);
52539926Ssklower 	if (m == 0)
52639926Ssklower 		return 0;
52739926Ssklower 	if (mtod(m, u_char *)[1] == UD_TPDU_type)
52839926Ssklower 		input = cltp_input;
52936403Ssklower 
53036403Ssklower 	IFDEBUG(D_TPINPUT)
53136403Ssklower 		dump_mbuf(m, "after tpclnp_input both pullups");
53236403Ssklower 	ENDDEBUG
53336403Ssklower 
53436403Ssklower 	IFDEBUG(D_TPISO)
53539926Ssklower 		printf("calling %sinput : src 0x%x, dst 0x%x, src addr:\n",
53639926Ssklower 			(input == tp_input ? "tp_" : "clts_"), src, dst);
53739926Ssklower 		dump_isoaddr(src);
53836403Ssklower 		printf(" dst addr:\n");
53939926Ssklower 		dump_isoaddr(dst);
54036403Ssklower 	ENDDEBUG
54136403Ssklower 
54239926Ssklower 	(void) (*input)(m, (struct sockaddr *)src, (struct sockaddr *)dst,
54339927Ssklower 				0, tpclnp_output_dg, ce_bit);
54436403Ssklower 
54536403Ssklower 	IFDEBUG(D_QUENCH)
54636403Ssklower 		{
54736403Ssklower 			if(time.tv_usec & 0x4 && time.tv_usec & 0x40) {
54836403Ssklower 				printf("tpclnp_input: FAKING %s\n",
54936403Ssklower 					tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2");
55036403Ssklower 				if(tp_stat.ts_pkt_rcvd & 0x1) {
55136403Ssklower 					tpclnp_ctlinput(PRC_QUENCH, &src);
55236403Ssklower 				} else {
55336403Ssklower 					tpclnp_ctlinput(PRC_QUENCH2, &src);
55436403Ssklower 				}
55536403Ssklower 			}
55636403Ssklower 		}
55736403Ssklower 	ENDDEBUG
55836403Ssklower 
55936403Ssklower 	splx(s);
56036403Ssklower 	return 0;
56136403Ssklower }
56236403Ssklower 
56336403Ssklower ProtoHook
56436403Ssklower iso_rtchange()
56536403Ssklower {
56636403Ssklower 	return 0;
56736403Ssklower }
56836403Ssklower 
56936403Ssklower /*
57036403Ssklower  * CALLED FROM:
57136403Ssklower  *  tpclnp_ctlinput()
57236403Ssklower  * FUNCTION and ARGUMENTS:
57336403Ssklower  *  find the tpcb pointer and pass it to tp_quench
57436403Ssklower  */
57536403Ssklower void
57636403Ssklower tpiso_decbit(isop)
57736403Ssklower 	struct isopcb *isop;
57836403Ssklower {
57937469Ssklower 	tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH2);
58036403Ssklower }
58136403Ssklower /*
58236403Ssklower  * CALLED FROM:
58336403Ssklower  *  tpclnp_ctlinput()
58436403Ssklower  * FUNCTION and ARGUMENTS:
58536403Ssklower  *  find the tpcb pointer and pass it to tp_quench
58636403Ssklower  */
58736403Ssklower void
58836403Ssklower tpiso_quench(isop)
58936403Ssklower 	struct isopcb *isop;
59036403Ssklower {
59137469Ssklower 	tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH);
59236403Ssklower }
59336403Ssklower 
59436403Ssklower /*
59536403Ssklower  * CALLED FROM:
59636403Ssklower  *  The network layer through the protosw table.
59736403Ssklower  * FUNCTION and ARGUMENTS:
59836403Ssklower  *	When clnp an ICMP-like msg this gets called.
59936403Ssklower  *	It either returns an error status to the user or
60036403Ssklower  *	it causes all connections on this address to be aborted
60136403Ssklower  *	by calling the appropriate xx_notify() routine.
60236403Ssklower  *	(cmd) is the type of ICMP error.
60336403Ssklower  * 	(siso) is the address of the guy who sent the ER CLNPDU
60436403Ssklower  */
60536403Ssklower ProtoHook
60636403Ssklower tpclnp_ctlinput(cmd, siso)
60736403Ssklower 	int cmd;
60836403Ssklower 	struct sockaddr_iso *siso;
60936403Ssklower {
61036403Ssklower 	extern u_char inetctlerrmap[];
61136403Ssklower 	extern ProtoHook tpiso_abort();
61236403Ssklower 	extern ProtoHook iso_rtchange();
61336403Ssklower 	extern ProtoHook tpiso_reset();
61437469Ssklower 	void iso_pcbnotify();
61536403Ssklower 
61636403Ssklower 	IFDEBUG(D_TPINPUT)
61739926Ssklower 		printf("tpclnp_ctlinput1: cmd 0x%x addr: \n", cmd);
61839926Ssklower 		dump_isoaddr(siso);
61936403Ssklower 	ENDDEBUG
62036403Ssklower 
62136403Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
62236403Ssklower 		return 0;
62339926Ssklower 	if (siso->siso_family != AF_ISO)
62439926Ssklower 		return 0;
62536403Ssklower 	switch (cmd) {
62636403Ssklower 
62736403Ssklower 		case	PRC_QUENCH2:
62839926Ssklower 			iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_decbit);
62936403Ssklower 			break;
63036403Ssklower 
63136403Ssklower 		case	PRC_QUENCH:
63239926Ssklower 			iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_quench);
63336403Ssklower 			break;
63436403Ssklower 
63536403Ssklower 		case	PRC_TIMXCEED_REASS:
63636403Ssklower 		case	PRC_ROUTEDEAD:
63739926Ssklower 			iso_pcbnotify(&tp_isopcb, siso, 0, tpiso_reset);
63836403Ssklower 			break;
63936403Ssklower 
64036403Ssklower 		case	PRC_HOSTUNREACH:
64136403Ssklower 		case	PRC_UNREACH_NET:
64236403Ssklower 		case	PRC_IFDOWN:
64336403Ssklower 		case	PRC_HOSTDEAD:
64439926Ssklower 			iso_pcbnotify(&tp_isopcb, siso,
64536403Ssklower 					(int)inetctlerrmap[cmd], iso_rtchange);
64636403Ssklower 			break;
64736403Ssklower 
64836403Ssklower 		default:
64936403Ssklower 		/*
65036403Ssklower 		case	PRC_MSGSIZE:
65136403Ssklower 		case	PRC_UNREACH_HOST:
65236403Ssklower 		case	PRC_UNREACH_PROTOCOL:
65336403Ssklower 		case	PRC_UNREACH_PORT:
65436403Ssklower 		case	PRC_UNREACH_NEEDFRAG:
65536403Ssklower 		case	PRC_UNREACH_SRCFAIL:
65636403Ssklower 		case	PRC_REDIRECT_NET:
65736403Ssklower 		case	PRC_REDIRECT_HOST:
65836403Ssklower 		case	PRC_REDIRECT_TOSNET:
65936403Ssklower 		case	PRC_REDIRECT_TOSHOST:
66036403Ssklower 		case	PRC_TIMXCEED_INTRANS:
66136403Ssklower 		case	PRC_PARAMPROB:
66236403Ssklower 		*/
66339926Ssklower 		iso_pcbnotify(&tp_isopcb, siso, (int)inetctlerrmap[cmd], tpiso_abort);
66436403Ssklower 		break;
66536403Ssklower 	}
66636403Ssklower 	return 0;
66736403Ssklower }
66839926Ssklower /*
66939926Ssklower  * XXX - Variant which is called by clnp_er.c with an isoaddr rather
67039926Ssklower  * than a sockaddr_iso.
67139926Ssklower  */
67236403Ssklower 
67339926Ssklower static struct sockaddr_iso siso = {sizeof(siso), AF_ISO};
67439926Ssklower tpclnp_ctlinput1(cmd, isoa)
67539926Ssklower 	int cmd;
67639926Ssklower 	struct iso_addr *isoa;
67739926Ssklower {
67839926Ssklower 	bzero((caddr_t)&siso.siso_addr, sizeof(siso.siso_addr));
67939926Ssklower 	bcopy((caddr_t)isoa, (caddr_t)&siso.siso_addr, isoa->isoa_len);
68039926Ssklower 	tpclnp_ctlinput(cmd, &siso);
68139926Ssklower }
68239926Ssklower 
68336403Ssklower /*
68436403Ssklower  * These next 2 routines are
68536403Ssklower  * CALLED FROM:
68636403Ssklower  *	xxx_notify() from tp_ctlinput() when
68736403Ssklower  *  net level gets some ICMP-equiv. type event.
68836403Ssklower  * FUNCTION and ARGUMENTS:
68936403Ssklower  *  Cause the connection to be aborted with some sort of error
69036403Ssklower  *  reason indicating that the network layer caused the abort.
69136403Ssklower  *  Fakes an ER TPDU so we can go through the driver.
69236403Ssklower  *  abort always aborts the TP connection.
69336403Ssklower  *  reset may or may not, depending on the TP class that's in use.
69436403Ssklower  */
69536403Ssklower ProtoHook
69636403Ssklower tpiso_abort(isop)
69736403Ssklower 	struct isopcb *isop;
69836403Ssklower {
69936403Ssklower 	struct tp_event e;
70036403Ssklower 
70136403Ssklower 	IFDEBUG(D_CONN)
70236403Ssklower 		printf("tpiso_abort 0x%x\n", isop);
70336403Ssklower 	ENDDEBUG
70436403Ssklower 	e.ev_number = ER_TPDU;
70536403Ssklower 	e.ATTR(ER_TPDU).e_reason = ECONNABORTED;
70636403Ssklower 	return  tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e);
70736403Ssklower }
70836403Ssklower 
70936403Ssklower ProtoHook
71036403Ssklower tpiso_reset(isop)
71136403Ssklower 	struct isopcb *isop;
71236403Ssklower {
71336403Ssklower 	struct tp_event e;
71436403Ssklower 
71536403Ssklower 	e.ev_number = T_NETRESET;
71636403Ssklower 	return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e);
71736403Ssklower 
71836403Ssklower }
71936403Ssklower 
72036403Ssklower #endif ISO
721