xref: /csrg-svn/sys/netiso/tp_iso.c (revision 56533)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*56533Sbostic  *	@(#)tp_iso.c	7.14 (Berkeley) 10/11/92
849268Sbostic  */
949268Sbostic 
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 
63*56533Sbostic #include <sys/param.h>
64*56533Sbostic #include <sys/socket.h>
65*56533Sbostic #include <sys/socketvar.h>
66*56533Sbostic #include <sys/domain.h>
67*56533Sbostic #include <sys/malloc.h>
68*56533Sbostic #include <sys/mbuf.h>
69*56533Sbostic #include <sys/errno.h>
70*56533Sbostic #include <sys/time.h>
71*56533Sbostic #include <sys/protosw.h>
7237469Ssklower 
73*56533Sbostic #include <net/if.h>
74*56533Sbostic #include <net/route.h>
7536403Ssklower 
76*56533Sbostic #include <netiso/argo_debug.h>
77*56533Sbostic #include <netiso/tp_param.h>
78*56533Sbostic #include <netiso/tp_stat.h>
79*56533Sbostic #include <netiso/tp_pcb.h>
80*56533Sbostic #include <netiso/tp_trace.h>
81*56533Sbostic #include <netiso/tp_stat.h>
82*56533Sbostic #include <netiso/tp_tpdu.h>
83*56533Sbostic #include <netiso/tp_clnp.h>
84*56533Sbostic #include <netiso/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 /*
29151246Ssklower  * NAME: 	tpclnp_mtu()
29251246Ssklower  *
29336403Ssklower  * CALLED FROM:
29451246Ssklower  *  tp_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
29536403Ssklower  *
29651246Ssklower  * FUNCTION, ARGUMENTS, and RETURN VALUE:
29751246Ssklower  *
29851246Ssklower  * Perform subnetwork dependent part of determining MTU information.
29951246Ssklower  * It appears that setting a double pointer to the rtentry associated with
30051246Ssklower  * the destination, and returning the header size for the network protocol
30151246Ssklower  * suffices.
30236403Ssklower  *
30351246Ssklower  * SIDE EFFECTS:
30451246Ssklower  * Sets tp_routep pointer in pcb.
30551246Ssklower  *
30651246Ssklower  * NOTES:
30736403Ssklower  */
30851246Ssklower tpclnp_mtu(tpcb)
30951246Ssklower register struct tp_pcb *tpcb;
31036403Ssklower {
31151246Ssklower 	struct isopcb			*isop = (struct isopcb *)tpcb->tp_npcb;
31236403Ssklower 
31336403Ssklower 	IFDEBUG(D_CONN)
31451246Ssklower 		printf("tpclnp_mtu(tpcb)\n", tpcb);
31536403Ssklower 	ENDDEBUG
31651246Ssklower 	tpcb->tp_routep = &(isop->isop_route.ro_rt);
31751246Ssklower 	if (tpcb->tp_netservice == ISO_CONS)
31851246Ssklower 		return 0;
31951246Ssklower 	else
32051246Ssklower 		return (sizeof(struct clnp_fixed) + sizeof(struct clnp_segment) +
32151246Ssklower 			2 * sizeof(struct iso_addr));
32236403Ssklower 
32336403Ssklower }
32436403Ssklower 
32536403Ssklower /*
32636403Ssklower  * CALLED FROM:
32736403Ssklower  *  tp_emit()
32836403Ssklower  * FUNCTION and ARGUMENTS:
32936403Ssklower  *  Take a packet(m0) from tp and package it so that clnp will accept it.
33036403Ssklower  *  This means prepending space for the clnp header and filling in a few
33136403Ssklower  *  of the fields.
33251246Ssklower  *  isop is the isopcb structure; datalen is the length of the data in the
33336403Ssklower  *  mbuf string m0.
33436403Ssklower  * RETURN VALUE:
33536403Ssklower  *  whatever (E*) is returned form the net layer output routine.
33636403Ssklower  */
33736403Ssklower 
33836403Ssklower int
33936403Ssklower tpclnp_output(isop, m0, datalen, nochksum)
34036403Ssklower 	struct isopcb		*isop;
34136403Ssklower 	struct mbuf 		*m0;
34236403Ssklower 	int 				datalen;
34336403Ssklower 	int					nochksum;
34436403Ssklower {
34537469Ssklower 	register struct mbuf *m = m0;
34636403Ssklower 	IncStat(ts_tpdu_sent);
34736403Ssklower 
34836403Ssklower 	IFDEBUG(D_TPISO)
34936403Ssklower 		struct tpdu *hdr = mtod(m0, struct tpdu *);
35036403Ssklower 
35136403Ssklower 		printf(
35236403Ssklower "abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n",
35336403Ssklower 			datalen,
35436403Ssklower 			(int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum);
35537469Ssklower 		dump_isoaddr(isop->isop_faddr);
35636403Ssklower 		printf("\nsrc addr:\n");
35737469Ssklower 		dump_isoaddr(isop->isop_laddr);
35836403Ssklower 		dump_mbuf(m0, "at tpclnp_output");
35936403Ssklower 	ENDDEBUG
36036403Ssklower 
36136403Ssklower 	return
36238841Ssklower 		clnp_output(m0, isop, datalen,  /* flags */nochksum ? CLNP_NO_CKSUM : 0);
36336403Ssklower }
36436403Ssklower 
36536403Ssklower /*
36636403Ssklower  * CALLED FROM:
36736403Ssklower  *  tp_error_emit()
36836403Ssklower  * FUNCTION and ARGUMENTS:
36936403Ssklower  *  This is a copy of tpclnp_output that takes the addresses
37036403Ssklower  *  instead of a pcb.  It's used by the tp_error_emit, when we
37136403Ssklower  *  don't have an iso_pcb with which to call the normal output rtn.
37236403Ssklower  * RETURN VALUE:
37336403Ssklower  *  ENOBUFS or
37436403Ssklower  *  whatever (E*) is returned form the net layer output routine.
37536403Ssklower  */
37636403Ssklower 
37736403Ssklower int
37836403Ssklower tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
37936403Ssklower 	struct iso_addr		*laddr, *faddr;
38036403Ssklower 	struct mbuf 		*m0;
38136403Ssklower 	int 				datalen;
38236403Ssklower 	struct route 		*ro;
38336403Ssklower 	int					nochksum;
38436403Ssklower {
38536403Ssklower 	struct isopcb		tmppcb;
38636403Ssklower 	int					err;
38736403Ssklower 	int					flags;
38837469Ssklower 	register struct mbuf *m = m0;
38936403Ssklower 
39036403Ssklower 	IFDEBUG(D_TPISO)
39136403Ssklower 		printf("tpclnp_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
39236403Ssklower 	ENDDEBUG
39336403Ssklower 
39436403Ssklower 	/*
39536403Ssklower 	 *	Fill in minimal portion of isopcb so that clnp can send the
39636403Ssklower 	 *	packet.
39736403Ssklower 	 */
39836403Ssklower 	bzero((caddr_t)&tmppcb, sizeof(tmppcb));
39937469Ssklower 	tmppcb.isop_laddr = &tmppcb.isop_sladdr;
40037469Ssklower 	tmppcb.isop_laddr->siso_addr = *laddr;
40137469Ssklower 	tmppcb.isop_faddr = &tmppcb.isop_sfaddr;
40237469Ssklower 	tmppcb.isop_faddr->siso_addr = *faddr;
40336403Ssklower 
40436403Ssklower 	IFDEBUG(D_TPISO)
40536403Ssklower 		printf("tpclnp_output_dg  faddr: \n");
40637469Ssklower 		dump_isoaddr(&tmppcb.isop_sfaddr);
40736403Ssklower 		printf("\ntpclnp_output_dg  laddr: \n");
40837469Ssklower 		dump_isoaddr(&tmppcb.isop_sladdr);
40936403Ssklower 		printf("\n");
41036403Ssklower 	ENDDEBUG
41136403Ssklower 
41236403Ssklower 	/*
41336403Ssklower 	 *	Do not use packet cache since this is a one shot error packet
41436403Ssklower 	 */
41536403Ssklower 	flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0));
41636403Ssklower 
41736403Ssklower 	IncStat(ts_tpdu_sent);
41836403Ssklower 
41938841Ssklower 	err = clnp_output(m0, &tmppcb, datalen,  flags);
42036403Ssklower 
42136403Ssklower 	/*
42236403Ssklower 	 *	Free route allocated by clnp (if the route was indeed allocated)
42336403Ssklower 	 */
42436403Ssklower 	if (tmppcb.isop_route.ro_rt)
42536403Ssklower 		RTFREE(tmppcb.isop_route.ro_rt);
42636403Ssklower 
42736403Ssklower 	return(err);
42836403Ssklower }
42936403Ssklower /*
43036403Ssklower  * CALLED FROM:
43136403Ssklower  * 	clnp's input routine, indirectly through the protosw.
43236403Ssklower  * FUNCTION and ARGUMENTS:
43336403Ssklower  * Take a packet (m) from clnp, strip off the clnp header and give it to tp
43436403Ssklower  * No return value.
43536403Ssklower  */
43636403Ssklower ProtoHook
43739927Ssklower tpclnp_input(m, src, dst, clnp_len, ce_bit)
43839926Ssklower 	register struct mbuf *m;
43939926Ssklower 	struct sockaddr_iso *src, *dst;
44039927Ssklower 	int clnp_len, ce_bit;
44136403Ssklower {
44236403Ssklower 	int s = splnet();
44337469Ssklower 	struct mbuf *tp_inputprep();
44439926Ssklower 	int tp_input(), cltp_input(), (*input)() = tp_input;
44536403Ssklower 
44636403Ssklower 	IncStat(ts_pkt_rcvd);
44736403Ssklower 
44836403Ssklower 	IFDEBUG(D_TPINPUT)
44936403Ssklower 		printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len);
45036403Ssklower 		dump_mbuf(m, "at tpclnp_input");
45136403Ssklower 	ENDDEBUG
45236403Ssklower 	/*
45336403Ssklower 	 * CLNP gives us an mbuf chain WITH the clnp header pulled up,
45436403Ssklower 	 * and the length of the clnp header.
45536403Ssklower 	 * First, strip off the Clnp header. leave the mbuf there for the
45636403Ssklower 	 * pullup that follows.
45736403Ssklower 	 */
45836403Ssklower 
45936403Ssklower 	m->m_len -= clnp_len;
46037469Ssklower 	m->m_data += clnp_len;
46136403Ssklower 
46237469Ssklower 	m = tp_inputprep(m);
46339926Ssklower 	if (m == 0)
46439926Ssklower 		return 0;
46539926Ssklower 	if (mtod(m, u_char *)[1] == UD_TPDU_type)
46639926Ssklower 		input = cltp_input;
46736403Ssklower 
46836403Ssklower 	IFDEBUG(D_TPINPUT)
46936403Ssklower 		dump_mbuf(m, "after tpclnp_input both pullups");
47036403Ssklower 	ENDDEBUG
47136403Ssklower 
47236403Ssklower 	IFDEBUG(D_TPISO)
47339926Ssklower 		printf("calling %sinput : src 0x%x, dst 0x%x, src addr:\n",
47439926Ssklower 			(input == tp_input ? "tp_" : "clts_"), src, dst);
47539926Ssklower 		dump_isoaddr(src);
47636403Ssklower 		printf(" dst addr:\n");
47739926Ssklower 		dump_isoaddr(dst);
47836403Ssklower 	ENDDEBUG
47936403Ssklower 
48039926Ssklower 	(void) (*input)(m, (struct sockaddr *)src, (struct sockaddr *)dst,
48139927Ssklower 				0, tpclnp_output_dg, ce_bit);
48236403Ssklower 
48336403Ssklower 	IFDEBUG(D_QUENCH)
48436403Ssklower 		{
48536403Ssklower 			if(time.tv_usec & 0x4 && time.tv_usec & 0x40) {
48636403Ssklower 				printf("tpclnp_input: FAKING %s\n",
48736403Ssklower 					tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2");
48836403Ssklower 				if(tp_stat.ts_pkt_rcvd & 0x1) {
48936403Ssklower 					tpclnp_ctlinput(PRC_QUENCH, &src);
49036403Ssklower 				} else {
49136403Ssklower 					tpclnp_ctlinput(PRC_QUENCH2, &src);
49236403Ssklower 				}
49336403Ssklower 			}
49436403Ssklower 		}
49536403Ssklower 	ENDDEBUG
49636403Ssklower 
49736403Ssklower 	splx(s);
49836403Ssklower 	return 0;
49936403Ssklower }
50036403Ssklower 
50136403Ssklower ProtoHook
50236403Ssklower iso_rtchange()
50336403Ssklower {
50436403Ssklower 	return 0;
50536403Ssklower }
50636403Ssklower 
50736403Ssklower /*
50836403Ssklower  * CALLED FROM:
50936403Ssklower  *  tpclnp_ctlinput()
51036403Ssklower  * FUNCTION and ARGUMENTS:
51136403Ssklower  *  find the tpcb pointer and pass it to tp_quench
51236403Ssklower  */
51336403Ssklower void
51436403Ssklower tpiso_decbit(isop)
51536403Ssklower 	struct isopcb *isop;
51636403Ssklower {
51750435Ssklower 	tp_quench((struct tp_pcb *)isop->isop_socket->so_pcb, PRC_QUENCH2);
51836403Ssklower }
51936403Ssklower /*
52036403Ssklower  * CALLED FROM:
52136403Ssklower  *  tpclnp_ctlinput()
52236403Ssklower  * FUNCTION and ARGUMENTS:
52336403Ssklower  *  find the tpcb pointer and pass it to tp_quench
52436403Ssklower  */
52536403Ssklower void
52636403Ssklower tpiso_quench(isop)
52736403Ssklower 	struct isopcb *isop;
52836403Ssklower {
52950435Ssklower 	tp_quench((struct tp_pcb *)isop->isop_socket->so_pcb, PRC_QUENCH);
53036403Ssklower }
53136403Ssklower 
53236403Ssklower /*
53336403Ssklower  * CALLED FROM:
53436403Ssklower  *  The network layer through the protosw table.
53536403Ssklower  * FUNCTION and ARGUMENTS:
53636403Ssklower  *	When clnp an ICMP-like msg this gets called.
53736403Ssklower  *	It either returns an error status to the user or
53836403Ssklower  *	it causes all connections on this address to be aborted
53936403Ssklower  *	by calling the appropriate xx_notify() routine.
54036403Ssklower  *	(cmd) is the type of ICMP error.
54136403Ssklower  * 	(siso) is the address of the guy who sent the ER CLNPDU
54236403Ssklower  */
54336403Ssklower ProtoHook
54436403Ssklower tpclnp_ctlinput(cmd, siso)
54536403Ssklower 	int cmd;
54636403Ssklower 	struct sockaddr_iso *siso;
54736403Ssklower {
54836403Ssklower 	extern u_char inetctlerrmap[];
54936403Ssklower 	extern ProtoHook tpiso_abort();
55036403Ssklower 	extern ProtoHook iso_rtchange();
55136403Ssklower 	extern ProtoHook tpiso_reset();
55237469Ssklower 	void iso_pcbnotify();
55336403Ssklower 
55436403Ssklower 	IFDEBUG(D_TPINPUT)
55539926Ssklower 		printf("tpclnp_ctlinput1: cmd 0x%x addr: \n", cmd);
55639926Ssklower 		dump_isoaddr(siso);
55736403Ssklower 	ENDDEBUG
55836403Ssklower 
55936403Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
56036403Ssklower 		return 0;
56139926Ssklower 	if (siso->siso_family != AF_ISO)
56239926Ssklower 		return 0;
56336403Ssklower 	switch (cmd) {
56436403Ssklower 
56536403Ssklower 		case	PRC_QUENCH2:
56639926Ssklower 			iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_decbit);
56736403Ssklower 			break;
56836403Ssklower 
56936403Ssklower 		case	PRC_QUENCH:
57039926Ssklower 			iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_quench);
57136403Ssklower 			break;
57236403Ssklower 
57336403Ssklower 		case	PRC_TIMXCEED_REASS:
57436403Ssklower 		case	PRC_ROUTEDEAD:
57539926Ssklower 			iso_pcbnotify(&tp_isopcb, siso, 0, tpiso_reset);
57636403Ssklower 			break;
57736403Ssklower 
57836403Ssklower 		case	PRC_HOSTUNREACH:
57936403Ssklower 		case	PRC_UNREACH_NET:
58036403Ssklower 		case	PRC_IFDOWN:
58136403Ssklower 		case	PRC_HOSTDEAD:
58239926Ssklower 			iso_pcbnotify(&tp_isopcb, siso,
58336403Ssklower 					(int)inetctlerrmap[cmd], iso_rtchange);
58436403Ssklower 			break;
58536403Ssklower 
58636403Ssklower 		default:
58736403Ssklower 		/*
58836403Ssklower 		case	PRC_MSGSIZE:
58936403Ssklower 		case	PRC_UNREACH_HOST:
59036403Ssklower 		case	PRC_UNREACH_PROTOCOL:
59136403Ssklower 		case	PRC_UNREACH_PORT:
59236403Ssklower 		case	PRC_UNREACH_NEEDFRAG:
59336403Ssklower 		case	PRC_UNREACH_SRCFAIL:
59436403Ssklower 		case	PRC_REDIRECT_NET:
59536403Ssklower 		case	PRC_REDIRECT_HOST:
59636403Ssklower 		case	PRC_REDIRECT_TOSNET:
59736403Ssklower 		case	PRC_REDIRECT_TOSHOST:
59836403Ssklower 		case	PRC_TIMXCEED_INTRANS:
59936403Ssklower 		case	PRC_PARAMPROB:
60036403Ssklower 		*/
60139926Ssklower 		iso_pcbnotify(&tp_isopcb, siso, (int)inetctlerrmap[cmd], tpiso_abort);
60236403Ssklower 		break;
60336403Ssklower 	}
60436403Ssklower 	return 0;
60536403Ssklower }
60639926Ssklower /*
60739926Ssklower  * XXX - Variant which is called by clnp_er.c with an isoaddr rather
60839926Ssklower  * than a sockaddr_iso.
60939926Ssklower  */
61036403Ssklower 
61139926Ssklower static struct sockaddr_iso siso = {sizeof(siso), AF_ISO};
61239926Ssklower tpclnp_ctlinput1(cmd, isoa)
61339926Ssklower 	int cmd;
61439926Ssklower 	struct iso_addr *isoa;
61539926Ssklower {
61639926Ssklower 	bzero((caddr_t)&siso.siso_addr, sizeof(siso.siso_addr));
61739926Ssklower 	bcopy((caddr_t)isoa, (caddr_t)&siso.siso_addr, isoa->isoa_len);
61839926Ssklower 	tpclnp_ctlinput(cmd, &siso);
61939926Ssklower }
62039926Ssklower 
62136403Ssklower /*
62236403Ssklower  * These next 2 routines are
62336403Ssklower  * CALLED FROM:
62436403Ssklower  *	xxx_notify() from tp_ctlinput() when
62536403Ssklower  *  net level gets some ICMP-equiv. type event.
62636403Ssklower  * FUNCTION and ARGUMENTS:
62736403Ssklower  *  Cause the connection to be aborted with some sort of error
62836403Ssklower  *  reason indicating that the network layer caused the abort.
62936403Ssklower  *  Fakes an ER TPDU so we can go through the driver.
63036403Ssklower  *  abort always aborts the TP connection.
63136403Ssklower  *  reset may or may not, depending on the TP class that's in use.
63236403Ssklower  */
63336403Ssklower ProtoHook
63436403Ssklower tpiso_abort(isop)
63536403Ssklower 	struct isopcb *isop;
63636403Ssklower {
63736403Ssklower 	struct tp_event e;
63836403Ssklower 
63936403Ssklower 	IFDEBUG(D_CONN)
64036403Ssklower 		printf("tpiso_abort 0x%x\n", isop);
64136403Ssklower 	ENDDEBUG
64236403Ssklower 	e.ev_number = ER_TPDU;
64336403Ssklower 	e.ATTR(ER_TPDU).e_reason = ECONNABORTED;
64450435Ssklower 	return  tp_driver((struct tp_pcb *)isop->isop_socket->so_pcb, &e);
64536403Ssklower }
64636403Ssklower 
64736403Ssklower ProtoHook
64836403Ssklower tpiso_reset(isop)
64936403Ssklower 	struct isopcb *isop;
65036403Ssklower {
65136403Ssklower 	struct tp_event e;
65236403Ssklower 
65336403Ssklower 	e.ev_number = T_NETRESET;
65450435Ssklower 	return tp_driver((struct tp_pcb *)isop->isop_socket->so_pcb, &e);
65536403Ssklower 
65636403Ssklower }
65736403Ssklower 
65836403Ssklower #endif ISO
659