xref: /csrg-svn/sys/netiso/tp_iso.c (revision 39927)
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*39927Ssklower  *	@(#)tp_iso.c	7.6 (Berkeley) 01/16/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.
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"
7939926Ssklower #include "cltp_var.h"
8036403Ssklower 
8136403Ssklower /*
8236403Ssklower  * CALLED FROM:
8336403Ssklower  * 	pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
8437469Ssklower  * FUNCTION, ARGUMENTS:
8536403Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
8636403Ssklower  */
8736403Ssklower 
8837469Ssklower iso_getsufx(isop, lenp, data_out, which)
8936403Ssklower 	struct isopcb *isop;
9037469Ssklower 	u_short *lenp;
9137469Ssklower 	caddr_t data_out;
9236403Ssklower 	int which;
9336403Ssklower {
9437469Ssklower 	register struct sockaddr_iso *addr = 0;
9537469Ssklower 
9636403Ssklower 	switch (which) {
9736403Ssklower 	case TP_LOCAL:
9837469Ssklower 		addr = isop->isop_laddr;
9937469Ssklower 		break;
10036403Ssklower 
10136403Ssklower 	case TP_FOREIGN:
10237469Ssklower 		addr = isop->isop_faddr;
10336403Ssklower 	}
10437469Ssklower 	if (addr)
10538841Ssklower 		bcopy(TSEL(addr), data_out, (*lenp = addr->siso_tlen));
10636403Ssklower }
10736403Ssklower 
10836403Ssklower /* CALLED FROM:
10936403Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
11036403Ssklower  * 	incoming CR_TPDU.
11136403Ssklower  *
11236403Ssklower  * FUNCTION, ARGUMENTS:
11336403Ssklower  * 	Put a transport suffix (found in name) into an isopcb structure (isop).
11436403Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
11536403Ssklower  */
11636403Ssklower void
11737469Ssklower iso_putsufx(isop, sufxloc, sufxlen, which)
11836403Ssklower 	struct isopcb *isop;
11937469Ssklower 	caddr_t sufxloc;
12037469Ssklower 	int sufxlen, which;
12136403Ssklower {
12237469Ssklower 	struct sockaddr_iso **dst, *backup;
12337469Ssklower 	register struct sockaddr_iso *addr;
12437469Ssklower 	struct mbuf *m;
12537469Ssklower 	int len;
12637469Ssklower 
12736403Ssklower 	switch (which) {
12837469Ssklower 	default:
12937469Ssklower 		return;
13037469Ssklower 
13136403Ssklower 	case TP_LOCAL:
13237469Ssklower 		dst = &isop->isop_laddr;
13337469Ssklower 		backup = &isop->isop_sladdr;
13436403Ssklower 		break;
13537469Ssklower 
13636403Ssklower 	case TP_FOREIGN:
13737469Ssklower 		dst = &isop->isop_faddr;
13837469Ssklower 		backup = &isop->isop_sfaddr;
13936403Ssklower 	}
14037469Ssklower 	if ((addr = *dst) == 0) {
14137469Ssklower 		addr = *dst = backup;
14237469Ssklower 		addr->siso_nlen = 0;
14338841Ssklower 		addr->siso_slen = 0;
14438841Ssklower 		addr->siso_plen = 0;
14537469Ssklower 		printf("iso_putsufx on un-initialized isopcb\n");
14637469Ssklower 	}
14737469Ssklower 	len = sufxlen + addr->siso_nlen +
14838841Ssklower 			(sizeof(*addr) - sizeof(addr->siso_data));
14937469Ssklower 	if (addr == backup) {
15038841Ssklower 		if (len > sizeof(*addr)) {
15137469Ssklower 				m = m_getclr(M_DONTWAIT, MT_SONAME);
15237469Ssklower 				if (m == 0)
15337469Ssklower 					return;
15437469Ssklower 				addr = *dst = mtod(m, struct sockaddr_iso *);
15537469Ssklower 				*addr = *backup;
15637469Ssklower 				m->m_len = len;
15737469Ssklower 		}
15838841Ssklower 	}
15937469Ssklower 	bcopy(sufxloc, TSEL(addr), sufxlen);
16038841Ssklower 	addr->siso_tlen = sufxlen;
16137469Ssklower 	addr->siso_len = len;
16236403Ssklower }
16336403Ssklower 
16436403Ssklower /*
16536403Ssklower  * CALLED FROM:
16636403Ssklower  * 	tp.trans whenever we go into REFWAIT state.
16736403Ssklower  * FUNCTION and ARGUMENT:
16836403Ssklower  *	 Called when a ref is frozen, to allow the suffix to be reused.
16936403Ssklower  * 	(isop) is the net level pcb.  This really shouldn't have to be
17036403Ssklower  * 	done in a NET level pcb but... for the internet world that just
17136403Ssklower  * 	the way it is done in BSD...
17236403Ssklower  * 	The alternative is to have the port unusable until the reference
17336403Ssklower  * 	timer goes off.
17436403Ssklower  */
17536403Ssklower void
17636403Ssklower iso_recycle_tsuffix(isop)
17736403Ssklower 	struct isopcb	*isop;
17836403Ssklower {
17938841Ssklower 	isop->isop_laddr->siso_tlen = isop->isop_faddr->siso_tlen = 0;
18036403Ssklower }
18136403Ssklower 
18236403Ssklower /*
18336403Ssklower  * CALLED FROM:
18436403Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
18536403Ssklower  * 	incoming CR_TPDU.
18636403Ssklower  *
18736403Ssklower  * FUNCTION and ARGUMENTS:
18836403Ssklower  * 	Copy a whole net addr from a struct sockaddr (name).
18936403Ssklower  * 	into an isopcb (isop).
19036403Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
19136403Ssklower  */
19236403Ssklower void
19336403Ssklower iso_putnetaddr(isop, name, which)
19436403Ssklower 	register struct isopcb	*isop;
19536403Ssklower 	struct sockaddr_iso	*name;
19636403Ssklower 	int which;
19736403Ssklower {
19837469Ssklower 	struct sockaddr_iso **sisop, *backup;
19937469Ssklower 	register struct sockaddr_iso *siso;
20037469Ssklower 
20136403Ssklower 	switch (which) {
20236403Ssklower 	case TP_LOCAL:
20337469Ssklower 		sisop = &isop->isop_laddr;
20437469Ssklower 		backup = &isop->isop_sladdr;
20536403Ssklower 		break;
20636403Ssklower 	case TP_FOREIGN:
20737469Ssklower 		sisop = &isop->isop_faddr;
20837469Ssklower 		backup = &isop->isop_sfaddr;
20936403Ssklower 	}
21037469Ssklower 	siso = ((*sisop == 0) ? (*sisop = backup) : *sisop);
21137469Ssklower 	IFDEBUG(D_TPISO)
21237469Ssklower 		printf("ISO_PUTNETADDR\n");
21337469Ssklower 		dump_isoaddr(isop->isop_faddr);
21437469Ssklower 	ENDDEBUG
21537469Ssklower 	siso->siso_addr = name->siso_addr;
21636403Ssklower }
21736403Ssklower 
21836403Ssklower /*
21936403Ssklower  * CALLED FROM:
22036403Ssklower  *  pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
22136403Ssklower  * FUNCTION and ARGUMENTS:
22236403Ssklower  * 	Copy a whole net addr from an isopcb (isop) into
22336403Ssklower  * 	a struct sockaddr (name).
22436403Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
22536403Ssklower  */
22636403Ssklower 
22736403Ssklower void
22836403Ssklower iso_getnetaddr( isop, name, which)
22936403Ssklower 	struct isopcb *isop;
23037469Ssklower 	struct mbuf *name;
23136403Ssklower 	int which;
23236403Ssklower {
23337469Ssklower 	struct sockaddr_iso *siso =
23437469Ssklower 		(which == TP_LOCAL ? isop->isop_laddr : isop->isop_faddr);
23537469Ssklower 	if (siso)
23637469Ssklower 		bcopy((caddr_t)siso, mtod(name, caddr_t),
23737469Ssklower 				(unsigned)(name->m_len = siso->siso_len));
23837469Ssklower 	else
23937469Ssklower 		name->m_len = 0;
24036403Ssklower }
24136403Ssklower 
24236403Ssklower /*
24336403Ssklower  * CALLED FROM:
24436403Ssklower  *  tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
24536403Ssklower  * FUNCTION, ARGUMENTS, SIDE EFFECTS and RETURN VALUE:
24636403Ssklower  * Determine the proper maximum transmission unit, i.e., MTU, to use, given
24736403Ssklower  * a) the header size for the network protocol and the max transmission
24836403Ssklower  *	  unit on the subnet interface, determined from the information in (isop),
24936403Ssklower  * b) the max size negotiated so far (negot)
25036403Ssklower  * c) the window size used by the tp connection (found in so),
25136403Ssklower  *
25236403Ssklower  * The result is put in the integer *size in its integer form and in
25336403Ssklower  * *negot in its logarithmic form.
25436403Ssklower  *
25536403Ssklower  * The rules are:
25636403Ssklower  * a) can only negotiate down from the value found in *negot.
25736403Ssklower  * b) the MTU must be < the windowsize,
25836403Ssklower  * c) If src and dest are on the same net,
25936403Ssklower  * 	  we will negotiate the closest size larger than  MTU but really USE
26036403Ssklower  *    the actual device mtu - ll hdr sizes.
26136403Ssklower  *   otherwise we negotiate the closest size smaller than MTU - ll hdr sizes.
26236403Ssklower  */
26336403Ssklower 
26436403Ssklower void
26536403Ssklower tpclnp_mtu(so, isop, size, negot )
26636403Ssklower 	struct socket *so;
26736403Ssklower 	struct isopcb *isop;
26836403Ssklower 	int *size;
26936403Ssklower 	u_char *negot;
27036403Ssklower {
27139230Ssklower 	struct ifnet *ifp = 0;
27239230Ssklower 	struct iso_ifaddr *ia = 0;
27336403Ssklower 	register int i;
27436403Ssklower 	int windowsize = so->so_rcv.sb_hiwat;
27536403Ssklower 	int clnp_size;
27636403Ssklower 	int sizeismtu = 0;
27739230Ssklower 	register struct rtentry *rt = isop->isop_route.ro_rt;
27836403Ssklower 
27936403Ssklower 	IFDEBUG(D_CONN)
28036403Ssklower 		printf("tpclnp_mtu(0x%x,0x%x,0x%x,0x%x)\n", so, isop, size, negot);
28136403Ssklower 	ENDDEBUG
28236403Ssklower 	IFTRACE(D_CONN)
28336403Ssklower 		tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0);
28436403Ssklower 	ENDTRACE
28536403Ssklower 
28636403Ssklower 	*size = 1 << *negot;
28736403Ssklower 
28836403Ssklower 	if( *size > windowsize ) {
28936403Ssklower 		*size = windowsize;
29036403Ssklower 	}
29136403Ssklower 
29239230Ssklower 	if (rt == 0 || (rt->rt_flags & RTF_UP == 0) ||
29339230Ssklower 		(ia = (struct iso_ifaddr *)rt->rt_ifa) == 0 ||
29439230Ssklower 	    (ifp = ia->ia_ifp) == 0) {
29539230Ssklower 		IFDEBUG(D_CONN)
29639230Ssklower 			printf("tpclnp_mtu routing abort rt=0x%x ia=0x%x ifp=0x%x\n",
29739230Ssklower 					rt, ia, ifp)
29839230Ssklower 		ENDDEBUG
29936403Ssklower 		return;
30039230Ssklower 	}
30136403Ssklower 
30236403Ssklower 	/* TODO - make this indirect off the socket structure to the
30336403Ssklower 	 * network layer to get headersize
30436403Ssklower 	 */
30537469Ssklower 	if (isop->isop_laddr)
30637469Ssklower 		clnp_size = clnp_hdrsize(isop->isop_laddr->siso_addr.isoa_len);
30737469Ssklower 	else
30837469Ssklower 		clnp_size = 20;
30936403Ssklower 
31036403Ssklower 	if(*size > ifp->if_mtu - clnp_size) {
31136403Ssklower 		*size = ifp->if_mtu - clnp_size;
31236403Ssklower 		sizeismtu = 1;
31336403Ssklower 	}
31437469Ssklower 	/* have to transform size to the log2 of size */
31537469Ssklower 	for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i) <= *size)) ; i++)
31637469Ssklower 		;
31737469Ssklower 	i--;
31837469Ssklower 
31936403Ssklower 	IFTRACE(D_CONN)
32036403Ssklower 		tptrace(TPPTmisc, "GET MTU MID: tpcb size negot i \n",
32136403Ssklower 		*size, *negot, i, 0);
32236403Ssklower 	ENDTRACE
32336403Ssklower 
32439926Ssklower 	*size = 1<<i;
32536403Ssklower 	*negot = i;
32636403Ssklower 
32736403Ssklower 	IFDEBUG(D_CONN)
32836403Ssklower 		printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n",
32936403Ssklower 		ifp->if_name,	*size, *negot);
33036403Ssklower 	ENDDEBUG
33136403Ssklower 	IFTRACE(D_CONN)
33236403Ssklower 		tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n",
33336403Ssklower 		*size, *negot, 0, 0);
33436403Ssklower 	ENDTRACE
33536403Ssklower }
33636403Ssklower 
33736403Ssklower 
33836403Ssklower /*
33936403Ssklower  * CALLED FROM:
34036403Ssklower  *  tp_emit()
34136403Ssklower  * FUNCTION and ARGUMENTS:
34236403Ssklower  *  Take a packet(m0) from tp and package it so that clnp will accept it.
34336403Ssklower  *  This means prepending space for the clnp header and filling in a few
34436403Ssklower  *  of the fields.
34536403Ssklower  *  inp is the isopcb structure; datalen is the length of the data in the
34636403Ssklower  *  mbuf string m0.
34736403Ssklower  * RETURN VALUE:
34836403Ssklower  *  whatever (E*) is returned form the net layer output routine.
34936403Ssklower  */
35036403Ssklower 
35136403Ssklower int
35236403Ssklower tpclnp_output(isop, m0, datalen, nochksum)
35336403Ssklower 	struct isopcb		*isop;
35436403Ssklower 	struct mbuf 		*m0;
35536403Ssklower 	int 				datalen;
35636403Ssklower 	int					nochksum;
35736403Ssklower {
35837469Ssklower 	register struct mbuf *m = m0;
35936403Ssklower 	IncStat(ts_tpdu_sent);
36036403Ssklower 
36136403Ssklower 	IFDEBUG(D_TPISO)
36236403Ssklower 		struct tpdu *hdr = mtod(m0, struct tpdu *);
36336403Ssklower 
36436403Ssklower 		printf(
36536403Ssklower "abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n",
36636403Ssklower 			datalen,
36736403Ssklower 			(int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum);
36837469Ssklower 		dump_isoaddr(isop->isop_faddr);
36936403Ssklower 		printf("\nsrc addr:\n");
37037469Ssklower 		dump_isoaddr(isop->isop_laddr);
37136403Ssklower 		dump_mbuf(m0, "at tpclnp_output");
37236403Ssklower 	ENDDEBUG
37336403Ssklower 
37436403Ssklower 	return
37538841Ssklower 		clnp_output(m0, isop, datalen,  /* flags */nochksum ? CLNP_NO_CKSUM : 0);
37636403Ssklower }
37736403Ssklower 
37836403Ssklower /*
37936403Ssklower  * CALLED FROM:
38036403Ssklower  *  tp_error_emit()
38136403Ssklower  * FUNCTION and ARGUMENTS:
38236403Ssklower  *  This is a copy of tpclnp_output that takes the addresses
38336403Ssklower  *  instead of a pcb.  It's used by the tp_error_emit, when we
38436403Ssklower  *  don't have an iso_pcb with which to call the normal output rtn.
38536403Ssklower  * RETURN VALUE:
38636403Ssklower  *  ENOBUFS or
38736403Ssklower  *  whatever (E*) is returned form the net layer output routine.
38836403Ssklower  */
38936403Ssklower 
39036403Ssklower int
39136403Ssklower tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
39236403Ssklower 	struct iso_addr		*laddr, *faddr;
39336403Ssklower 	struct mbuf 		*m0;
39436403Ssklower 	int 				datalen;
39536403Ssklower 	struct route 		*ro;
39636403Ssklower 	int					nochksum;
39736403Ssklower {
39836403Ssklower 	struct isopcb		tmppcb;
39936403Ssklower 	int					err;
40036403Ssklower 	int					flags;
40137469Ssklower 	register struct mbuf *m = m0;
40236403Ssklower 
40336403Ssklower 	IFDEBUG(D_TPISO)
40436403Ssklower 		printf("tpclnp_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
40536403Ssklower 	ENDDEBUG
40636403Ssklower 
40736403Ssklower 	/*
40836403Ssklower 	 *	Fill in minimal portion of isopcb so that clnp can send the
40936403Ssklower 	 *	packet.
41036403Ssklower 	 */
41136403Ssklower 	bzero((caddr_t)&tmppcb, sizeof(tmppcb));
41237469Ssklower 	tmppcb.isop_laddr = &tmppcb.isop_sladdr;
41337469Ssklower 	tmppcb.isop_laddr->siso_addr = *laddr;
41437469Ssklower 	tmppcb.isop_faddr = &tmppcb.isop_sfaddr;
41537469Ssklower 	tmppcb.isop_faddr->siso_addr = *faddr;
41636403Ssklower 
41736403Ssklower 	IFDEBUG(D_TPISO)
41836403Ssklower 		printf("tpclnp_output_dg  faddr: \n");
41937469Ssklower 		dump_isoaddr(&tmppcb.isop_sfaddr);
42036403Ssklower 		printf("\ntpclnp_output_dg  laddr: \n");
42137469Ssklower 		dump_isoaddr(&tmppcb.isop_sladdr);
42236403Ssklower 		printf("\n");
42336403Ssklower 	ENDDEBUG
42436403Ssklower 
42536403Ssklower 	/*
42636403Ssklower 	 *	Do not use packet cache since this is a one shot error packet
42736403Ssklower 	 */
42836403Ssklower 	flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0));
42936403Ssklower 
43036403Ssklower 	IncStat(ts_tpdu_sent);
43136403Ssklower 
43238841Ssklower 	err = clnp_output(m0, &tmppcb, datalen,  flags);
43336403Ssklower 
43436403Ssklower 	/*
43536403Ssklower 	 *	Free route allocated by clnp (if the route was indeed allocated)
43636403Ssklower 	 */
43736403Ssklower 	if (tmppcb.isop_route.ro_rt)
43836403Ssklower 		RTFREE(tmppcb.isop_route.ro_rt);
43936403Ssklower 
44036403Ssklower 	return(err);
44136403Ssklower }
44236403Ssklower /*
44336403Ssklower  * CALLED FROM:
44436403Ssklower  * 	clnp's input routine, indirectly through the protosw.
44536403Ssklower  * FUNCTION and ARGUMENTS:
44636403Ssklower  * Take a packet (m) from clnp, strip off the clnp header and give it to tp
44736403Ssklower  * No return value.
44836403Ssklower  */
44936403Ssklower ProtoHook
450*39927Ssklower tpclnp_input(m, src, dst, clnp_len, ce_bit)
45139926Ssklower 	register struct mbuf *m;
45239926Ssklower 	struct sockaddr_iso *src, *dst;
453*39927Ssklower 	int clnp_len, ce_bit;
45436403Ssklower {
45536403Ssklower 	int s = splnet();
45637469Ssklower 	struct mbuf *tp_inputprep();
45739926Ssklower 	int tp_input(), cltp_input(), (*input)() = tp_input;
45836403Ssklower 
45936403Ssklower 	IncStat(ts_pkt_rcvd);
46036403Ssklower 
46136403Ssklower 	IFDEBUG(D_TPINPUT)
46236403Ssklower 		printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len);
46336403Ssklower 		dump_mbuf(m, "at tpclnp_input");
46436403Ssklower 	ENDDEBUG
46536403Ssklower 	/*
46636403Ssklower 	 * CLNP gives us an mbuf chain WITH the clnp header pulled up,
46736403Ssklower 	 * and the length of the clnp header.
46836403Ssklower 	 * First, strip off the Clnp header. leave the mbuf there for the
46936403Ssklower 	 * pullup that follows.
47036403Ssklower 	 */
47136403Ssklower 
47236403Ssklower 	m->m_len -= clnp_len;
47337469Ssklower 	m->m_data += clnp_len;
47436403Ssklower 
47537469Ssklower 	m = tp_inputprep(m);
47639926Ssklower 	if (m == 0)
47739926Ssklower 		return 0;
47839926Ssklower 	if (mtod(m, u_char *)[1] == UD_TPDU_type)
47939926Ssklower 		input = cltp_input;
48036403Ssklower 
48136403Ssklower 	IFDEBUG(D_TPINPUT)
48236403Ssklower 		dump_mbuf(m, "after tpclnp_input both pullups");
48336403Ssklower 	ENDDEBUG
48436403Ssklower 
48536403Ssklower 	IFDEBUG(D_TPISO)
48639926Ssklower 		printf("calling %sinput : src 0x%x, dst 0x%x, src addr:\n",
48739926Ssklower 			(input == tp_input ? "tp_" : "clts_"), src, dst);
48839926Ssklower 		dump_isoaddr(src);
48936403Ssklower 		printf(" dst addr:\n");
49039926Ssklower 		dump_isoaddr(dst);
49136403Ssklower 	ENDDEBUG
49236403Ssklower 
49339926Ssklower 	(void) (*input)(m, (struct sockaddr *)src, (struct sockaddr *)dst,
494*39927Ssklower 				0, tpclnp_output_dg, ce_bit);
49536403Ssklower 
49636403Ssklower 	IFDEBUG(D_QUENCH)
49736403Ssklower 		{
49836403Ssklower 			if(time.tv_usec & 0x4 && time.tv_usec & 0x40) {
49936403Ssklower 				printf("tpclnp_input: FAKING %s\n",
50036403Ssklower 					tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2");
50136403Ssklower 				if(tp_stat.ts_pkt_rcvd & 0x1) {
50236403Ssklower 					tpclnp_ctlinput(PRC_QUENCH, &src);
50336403Ssklower 				} else {
50436403Ssklower 					tpclnp_ctlinput(PRC_QUENCH2, &src);
50536403Ssklower 				}
50636403Ssklower 			}
50736403Ssklower 		}
50836403Ssklower 	ENDDEBUG
50936403Ssklower 
51036403Ssklower 	splx(s);
51136403Ssklower 	return 0;
51236403Ssklower }
51336403Ssklower 
51436403Ssklower ProtoHook
51536403Ssklower iso_rtchange()
51636403Ssklower {
51736403Ssklower 	return 0;
51836403Ssklower }
51936403Ssklower 
52036403Ssklower /*
52136403Ssklower  * CALLED FROM:
52236403Ssklower  *  tpclnp_ctlinput()
52336403Ssklower  * FUNCTION and ARGUMENTS:
52436403Ssklower  *  find the tpcb pointer and pass it to tp_quench
52536403Ssklower  */
52636403Ssklower void
52736403Ssklower tpiso_decbit(isop)
52836403Ssklower 	struct isopcb *isop;
52936403Ssklower {
53037469Ssklower 	tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH2);
53136403Ssklower }
53236403Ssklower /*
53336403Ssklower  * CALLED FROM:
53436403Ssklower  *  tpclnp_ctlinput()
53536403Ssklower  * FUNCTION and ARGUMENTS:
53636403Ssklower  *  find the tpcb pointer and pass it to tp_quench
53736403Ssklower  */
53836403Ssklower void
53936403Ssklower tpiso_quench(isop)
54036403Ssklower 	struct isopcb *isop;
54136403Ssklower {
54237469Ssklower 	tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH);
54336403Ssklower }
54436403Ssklower 
54536403Ssklower /*
54636403Ssklower  * CALLED FROM:
54736403Ssklower  *  The network layer through the protosw table.
54836403Ssklower  * FUNCTION and ARGUMENTS:
54936403Ssklower  *	When clnp an ICMP-like msg this gets called.
55036403Ssklower  *	It either returns an error status to the user or
55136403Ssklower  *	it causes all connections on this address to be aborted
55236403Ssklower  *	by calling the appropriate xx_notify() routine.
55336403Ssklower  *	(cmd) is the type of ICMP error.
55436403Ssklower  * 	(siso) is the address of the guy who sent the ER CLNPDU
55536403Ssklower  */
55636403Ssklower ProtoHook
55736403Ssklower tpclnp_ctlinput(cmd, siso)
55836403Ssklower 	int cmd;
55936403Ssklower 	struct sockaddr_iso *siso;
56036403Ssklower {
56136403Ssklower 	extern u_char inetctlerrmap[];
56236403Ssklower 	extern ProtoHook tpiso_abort();
56336403Ssklower 	extern ProtoHook iso_rtchange();
56436403Ssklower 	extern ProtoHook tpiso_reset();
56537469Ssklower 	void iso_pcbnotify();
56636403Ssklower 
56736403Ssklower 	IFDEBUG(D_TPINPUT)
56839926Ssklower 		printf("tpclnp_ctlinput1: cmd 0x%x addr: \n", cmd);
56939926Ssklower 		dump_isoaddr(siso);
57036403Ssklower 	ENDDEBUG
57136403Ssklower 
57236403Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
57336403Ssklower 		return 0;
57439926Ssklower 	if (siso->siso_family != AF_ISO)
57539926Ssklower 		return 0;
57636403Ssklower 	switch (cmd) {
57736403Ssklower 
57836403Ssklower 		case	PRC_QUENCH2:
57939926Ssklower 			iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_decbit);
58036403Ssklower 			break;
58136403Ssklower 
58236403Ssklower 		case	PRC_QUENCH:
58339926Ssklower 			iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_quench);
58436403Ssklower 			break;
58536403Ssklower 
58636403Ssklower 		case	PRC_TIMXCEED_REASS:
58736403Ssklower 		case	PRC_ROUTEDEAD:
58839926Ssklower 			iso_pcbnotify(&tp_isopcb, siso, 0, tpiso_reset);
58936403Ssklower 			break;
59036403Ssklower 
59136403Ssklower 		case	PRC_HOSTUNREACH:
59236403Ssklower 		case	PRC_UNREACH_NET:
59336403Ssklower 		case	PRC_IFDOWN:
59436403Ssklower 		case	PRC_HOSTDEAD:
59539926Ssklower 			iso_pcbnotify(&tp_isopcb, siso,
59636403Ssklower 					(int)inetctlerrmap[cmd], iso_rtchange);
59736403Ssklower 			break;
59836403Ssklower 
59936403Ssklower 		default:
60036403Ssklower 		/*
60136403Ssklower 		case	PRC_MSGSIZE:
60236403Ssklower 		case	PRC_UNREACH_HOST:
60336403Ssklower 		case	PRC_UNREACH_PROTOCOL:
60436403Ssklower 		case	PRC_UNREACH_PORT:
60536403Ssklower 		case	PRC_UNREACH_NEEDFRAG:
60636403Ssklower 		case	PRC_UNREACH_SRCFAIL:
60736403Ssklower 		case	PRC_REDIRECT_NET:
60836403Ssklower 		case	PRC_REDIRECT_HOST:
60936403Ssklower 		case	PRC_REDIRECT_TOSNET:
61036403Ssklower 		case	PRC_REDIRECT_TOSHOST:
61136403Ssklower 		case	PRC_TIMXCEED_INTRANS:
61236403Ssklower 		case	PRC_PARAMPROB:
61336403Ssklower 		*/
61439926Ssklower 		iso_pcbnotify(&tp_isopcb, siso, (int)inetctlerrmap[cmd], tpiso_abort);
61536403Ssklower 		break;
61636403Ssklower 	}
61736403Ssklower 	return 0;
61836403Ssklower }
61939926Ssklower /*
62039926Ssklower  * XXX - Variant which is called by clnp_er.c with an isoaddr rather
62139926Ssklower  * than a sockaddr_iso.
62239926Ssklower  */
62336403Ssklower 
62439926Ssklower static struct sockaddr_iso siso = {sizeof(siso), AF_ISO};
62539926Ssklower tpclnp_ctlinput1(cmd, isoa)
62639926Ssklower 	int cmd;
62739926Ssklower 	struct iso_addr *isoa;
62839926Ssklower {
62939926Ssklower 	bzero((caddr_t)&siso.siso_addr, sizeof(siso.siso_addr));
63039926Ssklower 	bcopy((caddr_t)isoa, (caddr_t)&siso.siso_addr, isoa->isoa_len);
63139926Ssklower 	tpclnp_ctlinput(cmd, &siso);
63239926Ssklower }
63339926Ssklower 
63436403Ssklower /*
63536403Ssklower  * These next 2 routines are
63636403Ssklower  * CALLED FROM:
63736403Ssklower  *	xxx_notify() from tp_ctlinput() when
63836403Ssklower  *  net level gets some ICMP-equiv. type event.
63936403Ssklower  * FUNCTION and ARGUMENTS:
64036403Ssklower  *  Cause the connection to be aborted with some sort of error
64136403Ssklower  *  reason indicating that the network layer caused the abort.
64236403Ssklower  *  Fakes an ER TPDU so we can go through the driver.
64336403Ssklower  *  abort always aborts the TP connection.
64436403Ssklower  *  reset may or may not, depending on the TP class that's in use.
64536403Ssklower  */
64636403Ssklower ProtoHook
64736403Ssklower tpiso_abort(isop)
64836403Ssklower 	struct isopcb *isop;
64936403Ssklower {
65036403Ssklower 	struct tp_event e;
65136403Ssklower 
65236403Ssklower 	IFDEBUG(D_CONN)
65336403Ssklower 		printf("tpiso_abort 0x%x\n", isop);
65436403Ssklower 	ENDDEBUG
65536403Ssklower 	e.ev_number = ER_TPDU;
65636403Ssklower 	e.ATTR(ER_TPDU).e_reason = ECONNABORTED;
65736403Ssklower 	return  tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e);
65836403Ssklower }
65936403Ssklower 
66036403Ssklower ProtoHook
66136403Ssklower tpiso_reset(isop)
66236403Ssklower 	struct isopcb *isop;
66336403Ssklower {
66436403Ssklower 	struct tp_event e;
66536403Ssklower 
66636403Ssklower 	e.ev_number = T_NETRESET;
66736403Ssklower 	return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e);
66836403Ssklower 
66936403Ssklower }
67036403Ssklower 
67139926Ssklower #include "cltp_usrreq.c"
67236403Ssklower #endif ISO
673