xref: /csrg-svn/sys/netiso/tp_iso.c (revision 39230)
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*39230Ssklower  *	@(#)tp_iso.c	7.4 (Berkeley) 09/26/89
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.
4336403Ssklower  *		iso_recycle_suffix: clear suffix for reuse in isopcb
4436403Ssklower  * 		tpclnp_ctlinput: handle ER CNLPdu : icmp-like stuff
4536403Ssklower  * 		tpclnp_mtu: figure out what size tpdu to use
4636403Ssklower  *		tpclnp_input: take a pkt from clnp, strip off its clnp header,
4736403Ssklower  *				give to tp
4836403Ssklower  *		tpclnp_output_dg: package a pkt for clnp given 2 addresses & some data
4936403Ssklower  *		tpclnp_output: package a pkt for clnp given an isopcb & some data
5036403Ssklower  */
5136403Ssklower 
5236403Ssklower #ifndef lint
5337469Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $";
5436403Ssklower #endif lint
5536403Ssklower 
5636403Ssklower #ifdef ISO
5736403Ssklower 
5837469Ssklower #include "param.h"
5937469Ssklower #include "socket.h"
6037469Ssklower #include "socketvar.h"
6137469Ssklower #include "domain.h"
6237469Ssklower #include "malloc.h"
6337469Ssklower #include "mbuf.h"
6437469Ssklower #include "errno.h"
6537469Ssklower #include "time.h"
6637469Ssklower #include "protosw.h"
6737469Ssklower 
6836403Ssklower #include "../net/if.h"
6936403Ssklower #include "../net/route.h"
7036403Ssklower 
7137469Ssklower #include "argo_debug.h"
7237469Ssklower #include "tp_param.h"
7337469Ssklower #include "tp_stat.h"
7437469Ssklower #include "tp_pcb.h"
7537469Ssklower #include "tp_trace.h"
7637469Ssklower #include "tp_stat.h"
7737469Ssklower #include "tp_tpdu.h"
7837469Ssklower #include "tp_clnp.h"
7936403Ssklower 
8036403Ssklower /*
8136403Ssklower  * CALLED FROM:
8236403Ssklower  * 	pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
8337469Ssklower  * FUNCTION, ARGUMENTS:
8436403Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
8536403Ssklower  */
8636403Ssklower 
8737469Ssklower iso_getsufx(isop, lenp, data_out, which)
8836403Ssklower 	struct isopcb *isop;
8937469Ssklower 	u_short *lenp;
9037469Ssklower 	caddr_t data_out;
9136403Ssklower 	int which;
9236403Ssklower {
9337469Ssklower 	register struct sockaddr_iso *addr = 0;
9437469Ssklower 
9536403Ssklower 	switch (which) {
9636403Ssklower 	case TP_LOCAL:
9737469Ssklower 		addr = isop->isop_laddr;
9837469Ssklower 		break;
9936403Ssklower 
10036403Ssklower 	case TP_FOREIGN:
10137469Ssklower 		addr = isop->isop_faddr;
10236403Ssklower 	}
10337469Ssklower 	if (addr)
10438841Ssklower 		bcopy(TSEL(addr), data_out, (*lenp = addr->siso_tlen));
10536403Ssklower }
10636403Ssklower 
10736403Ssklower /* CALLED FROM:
10836403Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
10936403Ssklower  * 	incoming CR_TPDU.
11036403Ssklower  *
11136403Ssklower  * FUNCTION, ARGUMENTS:
11236403Ssklower  * 	Put a transport suffix (found in name) into an isopcb structure (isop).
11336403Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
11436403Ssklower  */
11536403Ssklower void
11637469Ssklower iso_putsufx(isop, sufxloc, sufxlen, which)
11736403Ssklower 	struct isopcb *isop;
11837469Ssklower 	caddr_t sufxloc;
11937469Ssklower 	int sufxlen, which;
12036403Ssklower {
12137469Ssklower 	struct sockaddr_iso **dst, *backup;
12237469Ssklower 	register struct sockaddr_iso *addr;
12337469Ssklower 	struct mbuf *m;
12437469Ssklower 	int len;
12537469Ssklower 
12636403Ssklower 	switch (which) {
12737469Ssklower 	default:
12837469Ssklower 		return;
12937469Ssklower 
13036403Ssklower 	case TP_LOCAL:
13137469Ssklower 		dst = &isop->isop_laddr;
13237469Ssklower 		backup = &isop->isop_sladdr;
13336403Ssklower 		break;
13437469Ssklower 
13536403Ssklower 	case TP_FOREIGN:
13637469Ssklower 		dst = &isop->isop_faddr;
13737469Ssklower 		backup = &isop->isop_sfaddr;
13836403Ssklower 	}
13937469Ssklower 	if ((addr = *dst) == 0) {
14037469Ssklower 		addr = *dst = backup;
14137469Ssklower 		addr->siso_nlen = 0;
14238841Ssklower 		addr->siso_slen = 0;
14338841Ssklower 		addr->siso_plen = 0;
14437469Ssklower 		printf("iso_putsufx on un-initialized isopcb\n");
14537469Ssklower 	}
14637469Ssklower 	len = sufxlen + addr->siso_nlen +
14738841Ssklower 			(sizeof(*addr) - sizeof(addr->siso_data));
14837469Ssklower 	if (addr == backup) {
14938841Ssklower 		if (len > sizeof(*addr)) {
15037469Ssklower 				m = m_getclr(M_DONTWAIT, MT_SONAME);
15137469Ssklower 				if (m == 0)
15237469Ssklower 					return;
15337469Ssklower 				addr = *dst = mtod(m, struct sockaddr_iso *);
15437469Ssklower 				*addr = *backup;
15537469Ssklower 				m->m_len = len;
15637469Ssklower 		}
15738841Ssklower 	}
15837469Ssklower 	bcopy(sufxloc, TSEL(addr), sufxlen);
15938841Ssklower 	addr->siso_tlen = sufxlen;
16037469Ssklower 	addr->siso_len = len;
16136403Ssklower }
16236403Ssklower 
16336403Ssklower /*
16436403Ssklower  * CALLED FROM:
16536403Ssklower  * 	tp.trans whenever we go into REFWAIT state.
16636403Ssklower  * FUNCTION and ARGUMENT:
16736403Ssklower  *	 Called when a ref is frozen, to allow the suffix to be reused.
16836403Ssklower  * 	(isop) is the net level pcb.  This really shouldn't have to be
16936403Ssklower  * 	done in a NET level pcb but... for the internet world that just
17036403Ssklower  * 	the way it is done in BSD...
17136403Ssklower  * 	The alternative is to have the port unusable until the reference
17236403Ssklower  * 	timer goes off.
17336403Ssklower  */
17436403Ssklower void
17536403Ssklower iso_recycle_tsuffix(isop)
17636403Ssklower 	struct isopcb	*isop;
17736403Ssklower {
17838841Ssklower 	isop->isop_laddr->siso_tlen = isop->isop_faddr->siso_tlen = 0;
17936403Ssklower }
18036403Ssklower 
18136403Ssklower /*
18236403Ssklower  * CALLED FROM:
18336403Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
18436403Ssklower  * 	incoming CR_TPDU.
18536403Ssklower  *
18636403Ssklower  * FUNCTION and ARGUMENTS:
18736403Ssklower  * 	Copy a whole net addr from a struct sockaddr (name).
18836403Ssklower  * 	into an isopcb (isop).
18936403Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
19036403Ssklower  */
19136403Ssklower void
19236403Ssklower iso_putnetaddr(isop, name, which)
19336403Ssklower 	register struct isopcb	*isop;
19436403Ssklower 	struct sockaddr_iso	*name;
19536403Ssklower 	int which;
19636403Ssklower {
19737469Ssklower 	struct sockaddr_iso **sisop, *backup;
19837469Ssklower 	register struct sockaddr_iso *siso;
19937469Ssklower 
20036403Ssklower 	switch (which) {
20136403Ssklower 	case TP_LOCAL:
20237469Ssklower 		sisop = &isop->isop_laddr;
20337469Ssklower 		backup = &isop->isop_sladdr;
20436403Ssklower 		break;
20536403Ssklower 	case TP_FOREIGN:
20637469Ssklower 		sisop = &isop->isop_faddr;
20737469Ssklower 		backup = &isop->isop_sfaddr;
20836403Ssklower 	}
20937469Ssklower 	siso = ((*sisop == 0) ? (*sisop = backup) : *sisop);
21037469Ssklower 	IFDEBUG(D_TPISO)
21137469Ssklower 		printf("ISO_PUTNETADDR\n");
21237469Ssklower 		dump_isoaddr(isop->isop_faddr);
21337469Ssklower 	ENDDEBUG
21437469Ssklower 	siso->siso_addr = name->siso_addr;
21536403Ssklower }
21636403Ssklower 
21736403Ssklower /*
21836403Ssklower  * CALLED FROM:
21936403Ssklower  *  pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
22036403Ssklower  * FUNCTION and ARGUMENTS:
22136403Ssklower  * 	Copy a whole net addr from an isopcb (isop) into
22236403Ssklower  * 	a struct sockaddr (name).
22336403Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
22436403Ssklower  */
22536403Ssklower 
22636403Ssklower void
22736403Ssklower iso_getnetaddr( isop, name, which)
22836403Ssklower 	struct isopcb *isop;
22937469Ssklower 	struct mbuf *name;
23036403Ssklower 	int which;
23136403Ssklower {
23237469Ssklower 	struct sockaddr_iso *siso =
23337469Ssklower 		(which == TP_LOCAL ? isop->isop_laddr : isop->isop_faddr);
23437469Ssklower 	if (siso)
23537469Ssklower 		bcopy((caddr_t)siso, mtod(name, caddr_t),
23637469Ssklower 				(unsigned)(name->m_len = siso->siso_len));
23737469Ssklower 	else
23837469Ssklower 		name->m_len = 0;
23936403Ssklower }
24036403Ssklower 
24136403Ssklower /*
24236403Ssklower  * CALLED FROM:
24336403Ssklower  *  tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
24436403Ssklower  * FUNCTION, ARGUMENTS, SIDE EFFECTS and RETURN VALUE:
24536403Ssklower  * Determine the proper maximum transmission unit, i.e., MTU, to use, given
24636403Ssklower  * a) the header size for the network protocol and the max transmission
24736403Ssklower  *	  unit on the subnet interface, determined from the information in (isop),
24836403Ssklower  * b) the max size negotiated so far (negot)
24936403Ssklower  * c) the window size used by the tp connection (found in so),
25036403Ssklower  *
25136403Ssklower  * The result is put in the integer *size in its integer form and in
25236403Ssklower  * *negot in its logarithmic form.
25336403Ssklower  *
25436403Ssklower  * The rules are:
25536403Ssklower  * a) can only negotiate down from the value found in *negot.
25636403Ssklower  * b) the MTU must be < the windowsize,
25736403Ssklower  * c) If src and dest are on the same net,
25836403Ssklower  * 	  we will negotiate the closest size larger than  MTU but really USE
25936403Ssklower  *    the actual device mtu - ll hdr sizes.
26036403Ssklower  *   otherwise we negotiate the closest size smaller than MTU - ll hdr sizes.
26136403Ssklower  */
26236403Ssklower 
26336403Ssklower void
26436403Ssklower tpclnp_mtu(so, isop, size, negot )
26536403Ssklower 	struct socket *so;
26636403Ssklower 	struct isopcb *isop;
26736403Ssklower 	int *size;
26836403Ssklower 	u_char *negot;
26936403Ssklower {
270*39230Ssklower 	struct ifnet *ifp = 0;
271*39230Ssklower 	struct iso_ifaddr *ia = 0;
27236403Ssklower 	register int i;
27336403Ssklower 	int windowsize = so->so_rcv.sb_hiwat;
27436403Ssklower 	int clnp_size;
27536403Ssklower 	int sizeismtu = 0;
276*39230Ssklower 	register struct rtentry *rt = isop->isop_route.ro_rt;
27736403Ssklower 
27836403Ssklower 	IFDEBUG(D_CONN)
27936403Ssklower 		printf("tpclnp_mtu(0x%x,0x%x,0x%x,0x%x)\n", so, isop, size, negot);
28036403Ssklower 	ENDDEBUG
28136403Ssklower 	IFTRACE(D_CONN)
28236403Ssklower 		tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0);
28336403Ssklower 	ENDTRACE
28436403Ssklower 
28536403Ssklower 	*size = 1 << *negot;
28636403Ssklower 
28736403Ssklower 	if( *size > windowsize ) {
28836403Ssklower 		*size = windowsize;
28936403Ssklower 	}
29036403Ssklower 
291*39230Ssklower 	if (rt == 0 || (rt->rt_flags & RTF_UP == 0) ||
292*39230Ssklower 		(ia = (struct iso_ifaddr *)rt->rt_ifa) == 0 ||
293*39230Ssklower 	    (ifp = ia->ia_ifp) == 0) {
294*39230Ssklower 		IFDEBUG(D_CONN)
295*39230Ssklower 			printf("tpclnp_mtu routing abort rt=0x%x ia=0x%x ifp=0x%x\n",
296*39230Ssklower 					rt, ia, ifp)
297*39230Ssklower 		ENDDEBUG
29836403Ssklower 		return;
299*39230Ssklower 	}
30036403Ssklower 
30136403Ssklower 	/* TODO - make this indirect off the socket structure to the
30236403Ssklower 	 * network layer to get headersize
30336403Ssklower 	 */
30437469Ssklower 	if (isop->isop_laddr)
30537469Ssklower 		clnp_size = clnp_hdrsize(isop->isop_laddr->siso_addr.isoa_len);
30637469Ssklower 	else
30737469Ssklower 		clnp_size = 20;
30836403Ssklower 
30936403Ssklower 	if(*size > ifp->if_mtu - clnp_size) {
31036403Ssklower 		*size = ifp->if_mtu - clnp_size;
31136403Ssklower 		sizeismtu = 1;
31236403Ssklower 	}
31337469Ssklower 	/* have to transform size to the log2 of size */
31437469Ssklower 	for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i) <= *size)) ; i++)
31537469Ssklower 		;
31637469Ssklower 	i--;
31737469Ssklower 
31836403Ssklower 	IFTRACE(D_CONN)
31936403Ssklower 		tptrace(TPPTmisc, "GET MTU MID: tpcb size negot i \n",
32036403Ssklower 		*size, *negot, i, 0);
32136403Ssklower 	ENDTRACE
32236403Ssklower 
32336403Ssklower 	/* are we on the same LAN? if so, negotiate one tpdu size larger,
32436403Ssklower 	 * and actually send the real mtu size
32536403Ssklower 	 */
32637469Ssklower 	if (iso_localifa(isop->isop_faddr)) {
32736403Ssklower 		i++;
32836403Ssklower 	} else {
32936403Ssklower 		*size = 1<<i;
33036403Ssklower 	}
33136403Ssklower 	*negot = i;
33236403Ssklower 
33336403Ssklower 	IFDEBUG(D_CONN)
33436403Ssklower 		printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n",
33536403Ssklower 		ifp->if_name,	*size, *negot);
33636403Ssklower 	ENDDEBUG
33736403Ssklower 	IFTRACE(D_CONN)
33836403Ssklower 		tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n",
33936403Ssklower 		*size, *negot, 0, 0);
34036403Ssklower 	ENDTRACE
34136403Ssklower }
34236403Ssklower 
34336403Ssklower 
34436403Ssklower /*
34536403Ssklower  * CALLED FROM:
34636403Ssklower  *  tp_emit()
34736403Ssklower  * FUNCTION and ARGUMENTS:
34836403Ssklower  *  Take a packet(m0) from tp and package it so that clnp will accept it.
34936403Ssklower  *  This means prepending space for the clnp header and filling in a few
35036403Ssklower  *  of the fields.
35136403Ssklower  *  inp is the isopcb structure; datalen is the length of the data in the
35236403Ssklower  *  mbuf string m0.
35336403Ssklower  * RETURN VALUE:
35436403Ssklower  *  whatever (E*) is returned form the net layer output routine.
35536403Ssklower  */
35636403Ssklower 
35736403Ssklower int
35836403Ssklower tpclnp_output(isop, m0, datalen, nochksum)
35936403Ssklower 	struct isopcb		*isop;
36036403Ssklower 	struct mbuf 		*m0;
36136403Ssklower 	int 				datalen;
36236403Ssklower 	int					nochksum;
36336403Ssklower {
36437469Ssklower 	register struct mbuf *m = m0;
36536403Ssklower 	IncStat(ts_tpdu_sent);
36636403Ssklower 
36736403Ssklower 	IFDEBUG(D_TPISO)
36836403Ssklower 		struct tpdu *hdr = mtod(m0, struct tpdu *);
36936403Ssklower 
37036403Ssklower 		printf(
37136403Ssklower "abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n",
37236403Ssklower 			datalen,
37336403Ssklower 			(int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum);
37437469Ssklower 		dump_isoaddr(isop->isop_faddr);
37536403Ssklower 		printf("\nsrc addr:\n");
37637469Ssklower 		dump_isoaddr(isop->isop_laddr);
37736403Ssklower 		dump_mbuf(m0, "at tpclnp_output");
37836403Ssklower 	ENDDEBUG
37936403Ssklower 
38036403Ssklower 	return
38138841Ssklower 		clnp_output(m0, isop, datalen,  /* flags */nochksum ? CLNP_NO_CKSUM : 0);
38236403Ssklower }
38336403Ssklower 
38436403Ssklower /*
38536403Ssklower  * CALLED FROM:
38636403Ssklower  *  tp_error_emit()
38736403Ssklower  * FUNCTION and ARGUMENTS:
38836403Ssklower  *  This is a copy of tpclnp_output that takes the addresses
38936403Ssklower  *  instead of a pcb.  It's used by the tp_error_emit, when we
39036403Ssklower  *  don't have an iso_pcb with which to call the normal output rtn.
39136403Ssklower  * RETURN VALUE:
39236403Ssklower  *  ENOBUFS or
39336403Ssklower  *  whatever (E*) is returned form the net layer output routine.
39436403Ssklower  */
39536403Ssklower 
39636403Ssklower int
39736403Ssklower tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
39836403Ssklower 	struct iso_addr		*laddr, *faddr;
39936403Ssklower 	struct mbuf 		*m0;
40036403Ssklower 	int 				datalen;
40136403Ssklower 	struct route 		*ro;
40236403Ssklower 	int					nochksum;
40336403Ssklower {
40436403Ssklower 	struct isopcb		tmppcb;
40536403Ssklower 	int					err;
40636403Ssklower 	int					flags;
40737469Ssklower 	register struct mbuf *m = m0;
40836403Ssklower 
40936403Ssklower 	IFDEBUG(D_TPISO)
41036403Ssklower 		printf("tpclnp_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
41136403Ssklower 	ENDDEBUG
41236403Ssklower 
41336403Ssklower 	/*
41436403Ssklower 	 *	Fill in minimal portion of isopcb so that clnp can send the
41536403Ssklower 	 *	packet.
41636403Ssklower 	 */
41736403Ssklower 	bzero((caddr_t)&tmppcb, sizeof(tmppcb));
41837469Ssklower 	tmppcb.isop_laddr = &tmppcb.isop_sladdr;
41937469Ssklower 	tmppcb.isop_laddr->siso_addr = *laddr;
42037469Ssklower 	tmppcb.isop_faddr = &tmppcb.isop_sfaddr;
42137469Ssklower 	tmppcb.isop_faddr->siso_addr = *faddr;
42236403Ssklower 
42336403Ssklower 	IFDEBUG(D_TPISO)
42436403Ssklower 		printf("tpclnp_output_dg  faddr: \n");
42537469Ssklower 		dump_isoaddr(&tmppcb.isop_sfaddr);
42636403Ssklower 		printf("\ntpclnp_output_dg  laddr: \n");
42737469Ssklower 		dump_isoaddr(&tmppcb.isop_sladdr);
42836403Ssklower 		printf("\n");
42936403Ssklower 	ENDDEBUG
43036403Ssklower 
43136403Ssklower 	/*
43236403Ssklower 	 *	Do not use packet cache since this is a one shot error packet
43336403Ssklower 	 */
43436403Ssklower 	flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0));
43536403Ssklower 
43636403Ssklower 	IncStat(ts_tpdu_sent);
43736403Ssklower 
43838841Ssklower 	err = clnp_output(m0, &tmppcb, datalen,  flags);
43936403Ssklower 
44036403Ssklower 	/*
44136403Ssklower 	 *	Free route allocated by clnp (if the route was indeed allocated)
44236403Ssklower 	 */
44336403Ssklower 	if (tmppcb.isop_route.ro_rt)
44436403Ssklower 		RTFREE(tmppcb.isop_route.ro_rt);
44536403Ssklower 
44636403Ssklower 	return(err);
44736403Ssklower }
44837469Ssklower extern struct sockaddr_iso blank_siso;
44936403Ssklower /*
45036403Ssklower  * CALLED FROM:
45136403Ssklower  * 	clnp's input routine, indirectly through the protosw.
45236403Ssklower  * FUNCTION and ARGUMENTS:
45336403Ssklower  * Take a packet (m) from clnp, strip off the clnp header and give it to tp
45436403Ssklower  * No return value.
45536403Ssklower  */
45636403Ssklower ProtoHook
45736403Ssklower tpclnp_input(m, faddr, laddr, clnp_len)
45836403Ssklower 	struct mbuf *m;
45936403Ssklower 	struct iso_addr *faddr, *laddr;
46036403Ssklower 	int clnp_len;
46136403Ssklower {
46236403Ssklower 	struct sockaddr_iso src, dst;
46336403Ssklower 	int s = splnet();
46437469Ssklower 	struct mbuf *tp_inputprep();
46536403Ssklower 
46636403Ssklower 	IncStat(ts_pkt_rcvd);
46736403Ssklower 
46836403Ssklower 	IFDEBUG(D_TPINPUT)
46936403Ssklower 		printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len);
47036403Ssklower 		dump_mbuf(m, "at tpclnp_input");
47136403Ssklower 	ENDDEBUG
47236403Ssklower 	/*
47336403Ssklower 	 * CLNP gives us an mbuf chain WITH the clnp header pulled up,
47436403Ssklower 	 * and the length of the clnp header.
47536403Ssklower 	 * First, strip off the Clnp header. leave the mbuf there for the
47636403Ssklower 	 * pullup that follows.
47736403Ssklower 	 */
47836403Ssklower 
47936403Ssklower 	m->m_len -= clnp_len;
48037469Ssklower 	m->m_data += clnp_len;
48136403Ssklower 
48237469Ssklower 	m = tp_inputprep(m);
48336403Ssklower 
48436403Ssklower 	IFDEBUG(D_TPINPUT)
48536403Ssklower 		dump_mbuf(m, "after tpclnp_input both pullups");
48636403Ssklower 	ENDDEBUG
48736403Ssklower 
48837469Ssklower 	src = blank_siso; dst = blank_siso;
48937469Ssklower 	bcopy((caddr_t)faddr, (caddr_t)&src.siso_addr, 1 + faddr->isoa_len);
49037469Ssklower 	bcopy((caddr_t)laddr, (caddr_t)&dst.siso_addr, 1 + laddr->isoa_len);
49136403Ssklower 
49236403Ssklower 	IFDEBUG(D_TPISO)
49336403Ssklower 		printf("calling tp_input: &src 0x%x  &dst 0x%x, src addr:\n",
49436403Ssklower 			&src, &dst);
49536403Ssklower 		printf(" dst addr:\n");
49636403Ssklower 		dump_isoaddr(&src);
49736403Ssklower 		dump_isoaddr(&dst);
49836403Ssklower 	ENDDEBUG
49936403Ssklower 
50037469Ssklower 	(void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst,
50137469Ssklower 				0, tpclnp_output_dg);
50236403Ssklower 
50336403Ssklower 	IFDEBUG(D_QUENCH)
50436403Ssklower 		{
50536403Ssklower 			if(time.tv_usec & 0x4 && time.tv_usec & 0x40) {
50636403Ssklower 				printf("tpclnp_input: FAKING %s\n",
50736403Ssklower 					tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2");
50836403Ssklower 				if(tp_stat.ts_pkt_rcvd & 0x1) {
50936403Ssklower 					tpclnp_ctlinput(PRC_QUENCH, &src);
51036403Ssklower 				} else {
51136403Ssklower 					tpclnp_ctlinput(PRC_QUENCH2, &src);
51236403Ssklower 				}
51336403Ssklower 			}
51436403Ssklower 		}
51536403Ssklower 	ENDDEBUG
51636403Ssklower 
51736403Ssklower 	splx(s);
51836403Ssklower 	return 0;
51936403Ssklower }
52036403Ssklower 
52136403Ssklower ProtoHook
52236403Ssklower iso_rtchange()
52336403Ssklower {
52436403Ssklower 	return 0;
52536403Ssklower }
52636403Ssklower 
52736403Ssklower /*
52836403Ssklower  * CALLED FROM:
52936403Ssklower  *  tpclnp_ctlinput()
53036403Ssklower  * FUNCTION and ARGUMENTS:
53136403Ssklower  *  find the tpcb pointer and pass it to tp_quench
53236403Ssklower  */
53336403Ssklower void
53436403Ssklower tpiso_decbit(isop)
53536403Ssklower 	struct isopcb *isop;
53636403Ssklower {
53737469Ssklower 	tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH2);
53836403Ssklower }
53936403Ssklower /*
54036403Ssklower  * CALLED FROM:
54136403Ssklower  *  tpclnp_ctlinput()
54236403Ssklower  * FUNCTION and ARGUMENTS:
54336403Ssklower  *  find the tpcb pointer and pass it to tp_quench
54436403Ssklower  */
54536403Ssklower void
54636403Ssklower tpiso_quench(isop)
54736403Ssklower 	struct isopcb *isop;
54836403Ssklower {
54937469Ssklower 	tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH);
55036403Ssklower }
55136403Ssklower 
55236403Ssklower /*
55336403Ssklower  * CALLED FROM:
55436403Ssklower  *  The network layer through the protosw table.
55536403Ssklower  * FUNCTION and ARGUMENTS:
55636403Ssklower  *	When clnp an ICMP-like msg this gets called.
55736403Ssklower  *	It either returns an error status to the user or
55836403Ssklower  *	it causes all connections on this address to be aborted
55936403Ssklower  *	by calling the appropriate xx_notify() routine.
56036403Ssklower  *	(cmd) is the type of ICMP error.
56136403Ssklower  * 	(siso) is the address of the guy who sent the ER CLNPDU
56236403Ssklower  */
56336403Ssklower ProtoHook
56436403Ssklower tpclnp_ctlinput(cmd, siso)
56536403Ssklower 	int cmd;
56636403Ssklower 	struct sockaddr_iso *siso;
56736403Ssklower {
56837469Ssklower 	return tpclnp_ctlinput1(cmd, &siso->siso_addr);
56937469Ssklower }
57037469Ssklower 
57137469Ssklower /*
57237469Ssklower  *	Entry to ctlinput with argument of an iso_addr rather than a sockaddr
57337469Ssklower  */
57437469Ssklower ProtoHook
57537469Ssklower tpclnp_ctlinput1(cmd, isoa)
57637469Ssklower 	int cmd;
57737469Ssklower 	struct iso_addr	*isoa;
57837469Ssklower {
57936403Ssklower 	extern u_char inetctlerrmap[];
58036403Ssklower 	extern ProtoHook tpiso_abort();
58136403Ssklower 	extern ProtoHook iso_rtchange();
58236403Ssklower 	extern ProtoHook tpiso_reset();
58337469Ssklower 	void iso_pcbnotify();
58436403Ssklower 
58536403Ssklower 	IFDEBUG(D_TPINPUT)
58637469Ssklower 		printf("tpclnp_ctlinput1: cmd 0x%x addr: %s\n", cmd,
58737469Ssklower 			clnp_iso_addrp(isoa));
58836403Ssklower 	ENDDEBUG
58936403Ssklower 
59036403Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
59136403Ssklower 		return 0;
59236403Ssklower 	switch (cmd) {
59336403Ssklower 
59436403Ssklower 		case	PRC_QUENCH2:
59537469Ssklower 			iso_pcbnotify(&tp_isopcb, isoa, 0, (int (*)())tpiso_decbit);
59636403Ssklower 			break;
59736403Ssklower 
59836403Ssklower 		case	PRC_QUENCH:
59937469Ssklower 			iso_pcbnotify(&tp_isopcb, isoa, 0, (int (*)())tpiso_quench);
60036403Ssklower 			break;
60136403Ssklower 
60236403Ssklower 		case	PRC_TIMXCEED_REASS:
60336403Ssklower 		case	PRC_ROUTEDEAD:
60437469Ssklower 			iso_pcbnotify(&tp_isopcb, isoa, 0, tpiso_reset);
60536403Ssklower 			break;
60636403Ssklower 
60736403Ssklower 		case	PRC_HOSTUNREACH:
60836403Ssklower 		case	PRC_UNREACH_NET:
60936403Ssklower 		case	PRC_IFDOWN:
61036403Ssklower 		case	PRC_HOSTDEAD:
61137469Ssklower 			iso_pcbnotify(&tp_isopcb, isoa,
61236403Ssklower 					(int)inetctlerrmap[cmd], iso_rtchange);
61336403Ssklower 			break;
61436403Ssklower 
61536403Ssklower 		default:
61636403Ssklower 		/*
61736403Ssklower 		case	PRC_MSGSIZE:
61836403Ssklower 		case	PRC_UNREACH_HOST:
61936403Ssklower 		case	PRC_UNREACH_PROTOCOL:
62036403Ssklower 		case	PRC_UNREACH_PORT:
62136403Ssklower 		case	PRC_UNREACH_NEEDFRAG:
62236403Ssklower 		case	PRC_UNREACH_SRCFAIL:
62336403Ssklower 		case	PRC_REDIRECT_NET:
62436403Ssklower 		case	PRC_REDIRECT_HOST:
62536403Ssklower 		case	PRC_REDIRECT_TOSNET:
62636403Ssklower 		case	PRC_REDIRECT_TOSHOST:
62736403Ssklower 		case	PRC_TIMXCEED_INTRANS:
62836403Ssklower 		case	PRC_PARAMPROB:
62936403Ssklower 		*/
63037469Ssklower 		iso_pcbnotify(&tp_isopcb, isoa, (int)inetctlerrmap[cmd], tpiso_abort);
63136403Ssklower 		break;
63236403Ssklower 	}
63336403Ssklower 	return 0;
63436403Ssklower }
63536403Ssklower 
63636403Ssklower /*
63736403Ssklower  * These next 2 routines are
63836403Ssklower  * CALLED FROM:
63936403Ssklower  *	xxx_notify() from tp_ctlinput() when
64036403Ssklower  *  net level gets some ICMP-equiv. type event.
64136403Ssklower  * FUNCTION and ARGUMENTS:
64236403Ssklower  *  Cause the connection to be aborted with some sort of error
64336403Ssklower  *  reason indicating that the network layer caused the abort.
64436403Ssklower  *  Fakes an ER TPDU so we can go through the driver.
64536403Ssklower  *  abort always aborts the TP connection.
64636403Ssklower  *  reset may or may not, depending on the TP class that's in use.
64736403Ssklower  */
64836403Ssklower ProtoHook
64936403Ssklower tpiso_abort(isop)
65036403Ssklower 	struct isopcb *isop;
65136403Ssklower {
65236403Ssklower 	struct tp_event e;
65336403Ssklower 
65436403Ssklower 	IFDEBUG(D_CONN)
65536403Ssklower 		printf("tpiso_abort 0x%x\n", isop);
65636403Ssklower 	ENDDEBUG
65736403Ssklower 	e.ev_number = ER_TPDU;
65836403Ssklower 	e.ATTR(ER_TPDU).e_reason = ECONNABORTED;
65936403Ssklower 	return  tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e);
66036403Ssklower }
66136403Ssklower 
66236403Ssklower ProtoHook
66336403Ssklower tpiso_reset(isop)
66436403Ssklower 	struct isopcb *isop;
66536403Ssklower {
66636403Ssklower 	struct tp_event e;
66736403Ssklower 
66836403Ssklower 	e.ev_number = T_NETRESET;
66936403Ssklower 	return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e);
67036403Ssklower 
67136403Ssklower }
67236403Ssklower 
67336403Ssklower #endif ISO
674