xref: /csrg-svn/sys/netiso/tp_iso.c (revision 37469)
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
29*37469Ssklower  * $Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $
30*37469Ssklower  * $Source: /var/src/sys/netiso/RCS/tp_iso.c,v $
3136403Ssklower  *
3236403Ssklower  * Here is where you find the iso-dependent code.  We've tried
3336403Ssklower  * keep all net-level and (primarily) address-family-dependent stuff
3436403Ssklower  * out of the tp source, and everthing here is reached indirectly
3536403Ssklower  * through a switch table (struct nl_protosw *) tpcb->tp_nlproto
3636403Ssklower  * (see tp_pcb.c).
3736403Ssklower  * The routines here are:
3836403Ssklower  * 		iso_getsufx: gets transport suffix out of an isopcb structure.
3936403Ssklower  * 		iso_putsufx: put transport suffix into an isopcb structure.
4036403Ssklower  *		iso_putnetaddr: put a whole net addr into an isopcb.
4136403Ssklower  *		iso_getnetaddr: get a whole net addr from an isopcb.
4236403Ssklower  *		iso_recycle_suffix: clear suffix for reuse in isopcb
4336403Ssklower  * 		tpclnp_ctlinput: handle ER CNLPdu : icmp-like stuff
4436403Ssklower  * 		tpclnp_mtu: figure out what size tpdu to use
4536403Ssklower  *		tpclnp_input: take a pkt from clnp, strip off its clnp header,
4636403Ssklower  *				give to tp
4736403Ssklower  *		tpclnp_output_dg: package a pkt for clnp given 2 addresses & some data
4836403Ssklower  *		tpclnp_output: package a pkt for clnp given an isopcb & some data
4936403Ssklower  */
5036403Ssklower 
5136403Ssklower #ifndef lint
52*37469Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $";
5336403Ssklower #endif lint
5436403Ssklower 
5536403Ssklower #ifdef ISO
5636403Ssklower 
57*37469Ssklower #include "param.h"
58*37469Ssklower #include "socket.h"
59*37469Ssklower #include "socketvar.h"
60*37469Ssklower #include "domain.h"
61*37469Ssklower #include "malloc.h"
62*37469Ssklower #include "mbuf.h"
63*37469Ssklower #include "errno.h"
64*37469Ssklower #include "time.h"
65*37469Ssklower #include "protosw.h"
66*37469Ssklower 
6736403Ssklower #include "../net/if.h"
6836403Ssklower #include "../net/route.h"
6936403Ssklower 
70*37469Ssklower #include "argo_debug.h"
71*37469Ssklower #include "tp_param.h"
72*37469Ssklower #include "tp_stat.h"
73*37469Ssklower #include "tp_pcb.h"
74*37469Ssklower #include "tp_trace.h"
75*37469Ssklower #include "tp_stat.h"
76*37469Ssklower #include "tp_tpdu.h"
77*37469Ssklower #include "tp_clnp.h"
7836403Ssklower 
7936403Ssklower /*
8036403Ssklower  * CALLED FROM:
8136403Ssklower  * 	pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
82*37469Ssklower  * FUNCTION, ARGUMENTS:
8336403Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
8436403Ssklower  */
8536403Ssklower 
86*37469Ssklower iso_getsufx(isop, lenp, data_out, which)
8736403Ssklower 	struct isopcb *isop;
88*37469Ssklower 	u_short *lenp;
89*37469Ssklower 	caddr_t data_out;
9036403Ssklower 	int which;
9136403Ssklower {
92*37469Ssklower 	register struct sockaddr_iso *addr = 0;
93*37469Ssklower 
9436403Ssklower 	switch (which) {
9536403Ssklower 	case TP_LOCAL:
96*37469Ssklower 		addr = isop->isop_laddr;
97*37469Ssklower 		break;
9836403Ssklower 
9936403Ssklower 	case TP_FOREIGN:
100*37469Ssklower 		addr = isop->isop_faddr;
10136403Ssklower 	}
102*37469Ssklower 	if (addr)
103*37469Ssklower 		bcopy(TSEL(addr), data_out, (*lenp = addr->siso_tsuffixlen));
10436403Ssklower }
10536403Ssklower 
10636403Ssklower /* CALLED FROM:
10736403Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
10836403Ssklower  * 	incoming CR_TPDU.
10936403Ssklower  *
11036403Ssklower  * FUNCTION, ARGUMENTS:
11136403Ssklower  * 	Put a transport suffix (found in name) into an isopcb structure (isop).
11236403Ssklower  * 	The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
11336403Ssklower  */
11436403Ssklower void
115*37469Ssklower iso_putsufx(isop, sufxloc, sufxlen, which)
11636403Ssklower 	struct isopcb *isop;
117*37469Ssklower 	caddr_t sufxloc;
118*37469Ssklower 	int sufxlen, which;
11936403Ssklower {
120*37469Ssklower 	struct sockaddr_iso **dst, *backup;
121*37469Ssklower 	register struct sockaddr_iso *addr;
122*37469Ssklower 	struct mbuf *m;
123*37469Ssklower 	int len;
124*37469Ssklower 
12536403Ssklower 	switch (which) {
126*37469Ssklower 	default:
127*37469Ssklower 		return;
128*37469Ssklower 
12936403Ssklower 	case TP_LOCAL:
130*37469Ssklower 		dst = &isop->isop_laddr;
131*37469Ssklower 		backup = &isop->isop_sladdr;
13236403Ssklower 		break;
133*37469Ssklower 
13436403Ssklower 	case TP_FOREIGN:
135*37469Ssklower 		dst = &isop->isop_faddr;
136*37469Ssklower 		backup = &isop->isop_sfaddr;
13736403Ssklower 	}
138*37469Ssklower 	if ((addr = *dst) == 0) {
139*37469Ssklower 		addr = *dst = backup;
140*37469Ssklower 		addr->siso_nlen = 0;
141*37469Ssklower 		addr->siso_ssuffixlen = 0;
142*37469Ssklower 		printf("iso_putsufx on un-initialized isopcb\n");
143*37469Ssklower 	}
144*37469Ssklower 	len = sufxlen + addr->siso_nlen +
145*37469Ssklower 			(sizeof(struct sockaddr_iso) - sizeof(struct iso_addr));
146*37469Ssklower 	if (addr == backup) {
147*37469Ssklower 		if (len > sizeof(isop->isop_sladdr)) {
148*37469Ssklower 				m = m_getclr(M_DONTWAIT, MT_SONAME);
149*37469Ssklower 				if (m == 0)
150*37469Ssklower 					return;
151*37469Ssklower 				addr = *dst = mtod(m, struct sockaddr_iso *);
152*37469Ssklower 				*addr = *backup;
153*37469Ssklower 				m->m_len = len;
154*37469Ssklower 		}
155*37469Ssklower 	} else
156*37469Ssklower 		dtom(addr)->m_len = len;
157*37469Ssklower 	bcopy(sufxloc, TSEL(addr), sufxlen);
158*37469Ssklower 	addr->siso_tsuffixlen = sufxlen;
159*37469Ssklower 	addr->siso_len = len;
16036403Ssklower }
16136403Ssklower 
16236403Ssklower /*
16336403Ssklower  * CALLED FROM:
16436403Ssklower  * 	tp.trans whenever we go into REFWAIT state.
16536403Ssklower  * FUNCTION and ARGUMENT:
16636403Ssklower  *	 Called when a ref is frozen, to allow the suffix to be reused.
16736403Ssklower  * 	(isop) is the net level pcb.  This really shouldn't have to be
16836403Ssklower  * 	done in a NET level pcb but... for the internet world that just
16936403Ssklower  * 	the way it is done in BSD...
17036403Ssklower  * 	The alternative is to have the port unusable until the reference
17136403Ssklower  * 	timer goes off.
17236403Ssklower  */
17336403Ssklower void
17436403Ssklower iso_recycle_tsuffix(isop)
17536403Ssklower 	struct isopcb	*isop;
17636403Ssklower {
177*37469Ssklower 	isop->isop_laddr->siso_tsuffixlen = isop->isop_faddr->siso_tsuffixlen = 0;
17836403Ssklower }
17936403Ssklower 
18036403Ssklower /*
18136403Ssklower  * CALLED FROM:
18236403Ssklower  * 	tp_newsocket(); i.e., when a connection is being established by an
18336403Ssklower  * 	incoming CR_TPDU.
18436403Ssklower  *
18536403Ssklower  * FUNCTION and ARGUMENTS:
18636403Ssklower  * 	Copy a whole net addr from a struct sockaddr (name).
18736403Ssklower  * 	into an isopcb (isop).
18836403Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN
18936403Ssklower  */
19036403Ssklower void
19136403Ssklower iso_putnetaddr(isop, name, which)
19236403Ssklower 	register struct isopcb	*isop;
19336403Ssklower 	struct sockaddr_iso	*name;
19436403Ssklower 	int which;
19536403Ssklower {
196*37469Ssklower 	struct sockaddr_iso **sisop, *backup;
197*37469Ssklower 	register struct sockaddr_iso *siso;
198*37469Ssklower 
19936403Ssklower 	switch (which) {
20036403Ssklower 	case TP_LOCAL:
201*37469Ssklower 		sisop = &isop->isop_laddr;
202*37469Ssklower 		backup = &isop->isop_sladdr;
20336403Ssklower 		break;
20436403Ssklower 	case TP_FOREIGN:
205*37469Ssklower 		sisop = &isop->isop_faddr;
206*37469Ssklower 		backup = &isop->isop_sfaddr;
20736403Ssklower 	}
208*37469Ssklower 	siso = ((*sisop == 0) ? (*sisop = backup) : *sisop);
209*37469Ssklower 	IFDEBUG(D_TPISO)
210*37469Ssklower 		printf("ISO_PUTNETADDR\n");
211*37469Ssklower 		dump_isoaddr(isop->isop_faddr);
212*37469Ssklower 	ENDDEBUG
213*37469Ssklower 	siso->siso_addr = name->siso_addr;
21436403Ssklower }
21536403Ssklower 
21636403Ssklower /*
21736403Ssklower  * CALLED FROM:
21836403Ssklower  *  pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
21936403Ssklower  * FUNCTION and ARGUMENTS:
22036403Ssklower  * 	Copy a whole net addr from an isopcb (isop) into
22136403Ssklower  * 	a struct sockaddr (name).
22236403Ssklower  * 	The argument (which) takes values TP_LOCAL or TP_FOREIGN.
22336403Ssklower  */
22436403Ssklower 
22536403Ssklower void
22636403Ssklower iso_getnetaddr( isop, name, which)
22736403Ssklower 	struct isopcb *isop;
228*37469Ssklower 	struct mbuf *name;
22936403Ssklower 	int which;
23036403Ssklower {
231*37469Ssklower 	struct sockaddr_iso *siso =
232*37469Ssklower 		(which == TP_LOCAL ? isop->isop_laddr : isop->isop_faddr);
233*37469Ssklower 	if (siso)
234*37469Ssklower 		bcopy((caddr_t)siso, mtod(name, caddr_t),
235*37469Ssklower 				(unsigned)(name->m_len = siso->siso_len));
236*37469Ssklower 	else
237*37469Ssklower 		name->m_len = 0;
23836403Ssklower }
23936403Ssklower 
24036403Ssklower /*
24136403Ssklower  * CALLED FROM:
24236403Ssklower  *  tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
24336403Ssklower  * FUNCTION, ARGUMENTS, SIDE EFFECTS and RETURN VALUE:
24436403Ssklower  * Determine the proper maximum transmission unit, i.e., MTU, to use, given
24536403Ssklower  * a) the header size for the network protocol and the max transmission
24636403Ssklower  *	  unit on the subnet interface, determined from the information in (isop),
24736403Ssklower  * b) the max size negotiated so far (negot)
24836403Ssklower  * c) the window size used by the tp connection (found in so),
24936403Ssklower  *
25036403Ssklower  * The result is put in the integer *size in its integer form and in
25136403Ssklower  * *negot in its logarithmic form.
25236403Ssklower  *
25336403Ssklower  * The rules are:
25436403Ssklower  * a) can only negotiate down from the value found in *negot.
25536403Ssklower  * b) the MTU must be < the windowsize,
25636403Ssklower  * c) If src and dest are on the same net,
25736403Ssklower  * 	  we will negotiate the closest size larger than  MTU but really USE
25836403Ssklower  *    the actual device mtu - ll hdr sizes.
25936403Ssklower  *   otherwise we negotiate the closest size smaller than MTU - ll hdr sizes.
26036403Ssklower  */
26136403Ssklower 
26236403Ssklower void
26336403Ssklower tpclnp_mtu(so, isop, size, negot )
26436403Ssklower 	struct socket *so;
26536403Ssklower 	struct isopcb *isop;
26636403Ssklower 	int *size;
26736403Ssklower 	u_char *negot;
26836403Ssklower {
26936403Ssklower 	struct ifnet *ifp;
270*37469Ssklower 	struct iso_ifaddr *ia;
27136403Ssklower 	register int i;
27236403Ssklower 	int windowsize = so->so_rcv.sb_hiwat;
27336403Ssklower 	int clnp_size;
27436403Ssklower 	int sizeismtu = 0;
27536403Ssklower 
276*37469Ssklower 	struct iso_ifaddr	*iso_routeifa();
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*37469Ssklower 	if  (((ia = iso_routeifa(isop->isop_faddr)) == 0)
292*37469Ssklower 	      || (ifp = ia->ia_ifp) == 0)
29336403Ssklower 		return;
29436403Ssklower 
29536403Ssklower 	/* TODO - make this indirect off the socket structure to the
29636403Ssklower 	 * network layer to get headersize
29736403Ssklower 	 */
298*37469Ssklower 	if (isop->isop_laddr)
299*37469Ssklower 		clnp_size = clnp_hdrsize(isop->isop_laddr->siso_addr.isoa_len);
300*37469Ssklower 	else
301*37469Ssklower 		clnp_size = 20;
30236403Ssklower 
30336403Ssklower 	if(*size > ifp->if_mtu - clnp_size) {
30436403Ssklower 		*size = ifp->if_mtu - clnp_size;
30536403Ssklower 		sizeismtu = 1;
30636403Ssklower 	}
307*37469Ssklower 	/* have to transform size to the log2 of size */
308*37469Ssklower 	for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i) <= *size)) ; i++)
309*37469Ssklower 		;
310*37469Ssklower 	i--;
311*37469Ssklower 
31236403Ssklower 	IFTRACE(D_CONN)
31336403Ssklower 		tptrace(TPPTmisc, "GET MTU MID: tpcb size negot i \n",
31436403Ssklower 		*size, *negot, i, 0);
31536403Ssklower 	ENDTRACE
31636403Ssklower 
31736403Ssklower 	/* are we on the same LAN? if so, negotiate one tpdu size larger,
31836403Ssklower 	 * and actually send the real mtu size
31936403Ssklower 	 */
320*37469Ssklower 	if (iso_localifa(isop->isop_faddr)) {
32136403Ssklower 		i++;
32236403Ssklower 	} else {
32336403Ssklower 		*size = 1<<i;
32436403Ssklower 	}
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 {
358*37469Ssklower 	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);
368*37469Ssklower 		dump_isoaddr(isop->isop_faddr);
36936403Ssklower 		printf("\nsrc addr:\n");
370*37469Ssklower 		dump_isoaddr(isop->isop_laddr);
37136403Ssklower 		dump_mbuf(m0, "at tpclnp_output");
37236403Ssklower 	ENDDEBUG
373*37469Ssklower 	if ((m->m_flags & M_PKTHDR) == 0) {
374*37469Ssklower 		IFDEBUG(D_TPISO)
375*37469Ssklower 		printf("tpclnp_output: non headered mbuf");
376*37469Ssklower 		ENDDEBUG
377*37469Ssklower 		MGETHDR(m, M_DONTWAIT, MT_DATA);
378*37469Ssklower 		if (m == 0) {
379*37469Ssklower 			m_freem(m0);
380*37469Ssklower 			return ENOBUFS;
381*37469Ssklower 		}
382*37469Ssklower 		m->m_next = m0;
383*37469Ssklower 		m->m_len = 0;
384*37469Ssklower 		m->m_pkthdr.len = datalen;
385*37469Ssklower 		m0 = m;
386*37469Ssklower 	}
38736403Ssklower 
38836403Ssklower 	return
389*37469Ssklower 		clnp_output(m0, isop, /* flags */nochksum ? CLNP_NO_CKSUM : 0);
39036403Ssklower }
39136403Ssklower 
39236403Ssklower /*
39336403Ssklower  * CALLED FROM:
39436403Ssklower  *  tp_error_emit()
39536403Ssklower  * FUNCTION and ARGUMENTS:
39636403Ssklower  *  This is a copy of tpclnp_output that takes the addresses
39736403Ssklower  *  instead of a pcb.  It's used by the tp_error_emit, when we
39836403Ssklower  *  don't have an iso_pcb with which to call the normal output rtn.
39936403Ssklower  * RETURN VALUE:
40036403Ssklower  *  ENOBUFS or
40136403Ssklower  *  whatever (E*) is returned form the net layer output routine.
40236403Ssklower  */
40336403Ssklower 
40436403Ssklower int
40536403Ssklower tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
40636403Ssklower 	struct iso_addr		*laddr, *faddr;
40736403Ssklower 	struct mbuf 		*m0;
40836403Ssklower 	int 				datalen;
40936403Ssklower 	struct route 		*ro;
41036403Ssklower 	int					nochksum;
41136403Ssklower {
41236403Ssklower 	struct isopcb		tmppcb;
41336403Ssklower 	int					err;
41436403Ssklower 	int					flags;
415*37469Ssklower 	register struct mbuf *m = m0;
41636403Ssklower 
41736403Ssklower 	IFDEBUG(D_TPISO)
41836403Ssklower 		printf("tpclnp_output_dg  datalen 0x%x m0 0x%x\n", datalen, m0);
41936403Ssklower 	ENDDEBUG
42036403Ssklower 
42136403Ssklower 	/*
42236403Ssklower 	 *	Fill in minimal portion of isopcb so that clnp can send the
42336403Ssklower 	 *	packet.
42436403Ssklower 	 */
42536403Ssklower 	bzero((caddr_t)&tmppcb, sizeof(tmppcb));
426*37469Ssklower 	tmppcb.isop_laddr = &tmppcb.isop_sladdr;
427*37469Ssklower 	tmppcb.isop_laddr->siso_addr = *laddr;
428*37469Ssklower 	tmppcb.isop_faddr = &tmppcb.isop_sfaddr;
429*37469Ssklower 	tmppcb.isop_faddr->siso_addr = *faddr;
43036403Ssklower 
43136403Ssklower 	IFDEBUG(D_TPISO)
43236403Ssklower 		printf("tpclnp_output_dg  faddr: \n");
433*37469Ssklower 		dump_isoaddr(&tmppcb.isop_sfaddr);
43436403Ssklower 		printf("\ntpclnp_output_dg  laddr: \n");
435*37469Ssklower 		dump_isoaddr(&tmppcb.isop_sladdr);
43636403Ssklower 		printf("\n");
43736403Ssklower 	ENDDEBUG
43836403Ssklower 
43936403Ssklower 	/*
44036403Ssklower 	 *	Do not use packet cache since this is a one shot error packet
44136403Ssklower 	 */
44236403Ssklower 	flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0));
44336403Ssklower 
44436403Ssklower 	IncStat(ts_tpdu_sent);
44536403Ssklower 
446*37469Ssklower 	if ((m->m_flags & M_PKTHDR) == 0) {
447*37469Ssklower 		printf("tpclnp_output: non headered mbuf");
448*37469Ssklower 		MGETHDR(m, M_DONTWAIT, MT_DATA);
449*37469Ssklower 		if (m == 0) {
450*37469Ssklower 			m_freem(m0);
451*37469Ssklower 			return ENOBUFS;
452*37469Ssklower 		}
453*37469Ssklower 		m->m_next = m0;
454*37469Ssklower 		m->m_len = 0;
455*37469Ssklower 		m->m_pkthdr.len = datalen;
456*37469Ssklower 		m0 = m;
457*37469Ssklower 	}
458*37469Ssklower 	err = clnp_output(m0, &tmppcb, flags);
45936403Ssklower 
46036403Ssklower 	/*
46136403Ssklower 	 *	Free route allocated by clnp (if the route was indeed allocated)
46236403Ssklower 	 */
46336403Ssklower 	if (tmppcb.isop_route.ro_rt)
46436403Ssklower 		RTFREE(tmppcb.isop_route.ro_rt);
46536403Ssklower 
46636403Ssklower 	return(err);
46736403Ssklower }
468*37469Ssklower extern struct sockaddr_iso blank_siso;
46936403Ssklower /*
47036403Ssklower  * CALLED FROM:
47136403Ssklower  * 	clnp's input routine, indirectly through the protosw.
47236403Ssklower  * FUNCTION and ARGUMENTS:
47336403Ssklower  * Take a packet (m) from clnp, strip off the clnp header and give it to tp
47436403Ssklower  * No return value.
47536403Ssklower  */
47636403Ssklower ProtoHook
47736403Ssklower tpclnp_input(m, faddr, laddr, clnp_len)
47836403Ssklower 	struct mbuf *m;
47936403Ssklower 	struct iso_addr *faddr, *laddr;
48036403Ssklower 	int clnp_len;
48136403Ssklower {
48236403Ssklower 	struct sockaddr_iso src, dst;
48336403Ssklower 	int s = splnet();
484*37469Ssklower 	struct mbuf *tp_inputprep();
48536403Ssklower 
48636403Ssklower 	IncStat(ts_pkt_rcvd);
48736403Ssklower 
48836403Ssklower 	IFDEBUG(D_TPINPUT)
48936403Ssklower 		printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len);
49036403Ssklower 		dump_mbuf(m, "at tpclnp_input");
49136403Ssklower 	ENDDEBUG
49236403Ssklower 	/*
49336403Ssklower 	 * CLNP gives us an mbuf chain WITH the clnp header pulled up,
49436403Ssklower 	 * and the length of the clnp header.
49536403Ssklower 	 * First, strip off the Clnp header. leave the mbuf there for the
49636403Ssklower 	 * pullup that follows.
49736403Ssklower 	 */
49836403Ssklower 
49936403Ssklower 	m->m_len -= clnp_len;
500*37469Ssklower 	m->m_data += clnp_len;
50136403Ssklower 
502*37469Ssklower 	m = tp_inputprep(m);
50336403Ssklower 
50436403Ssklower 	IFDEBUG(D_TPINPUT)
50536403Ssklower 		dump_mbuf(m, "after tpclnp_input both pullups");
50636403Ssklower 	ENDDEBUG
50736403Ssklower 
508*37469Ssklower 	src = blank_siso; dst = blank_siso;
509*37469Ssklower 	bcopy((caddr_t)faddr, (caddr_t)&src.siso_addr, 1 + faddr->isoa_len);
510*37469Ssklower 	bcopy((caddr_t)laddr, (caddr_t)&dst.siso_addr, 1 + laddr->isoa_len);
51136403Ssklower 
51236403Ssklower 	IFDEBUG(D_TPISO)
51336403Ssklower 		printf("calling tp_input: &src 0x%x  &dst 0x%x, src addr:\n",
51436403Ssklower 			&src, &dst);
51536403Ssklower 		printf(" dst addr:\n");
51636403Ssklower 		dump_isoaddr(&src);
51736403Ssklower 		dump_isoaddr(&dst);
51836403Ssklower 	ENDDEBUG
51936403Ssklower 
520*37469Ssklower 	(void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst,
521*37469Ssklower 				0, tpclnp_output_dg);
52236403Ssklower 
52336403Ssklower 	IFDEBUG(D_QUENCH)
52436403Ssklower 		{
52536403Ssklower 			if(time.tv_usec & 0x4 && time.tv_usec & 0x40) {
52636403Ssklower 				printf("tpclnp_input: FAKING %s\n",
52736403Ssklower 					tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2");
52836403Ssklower 				if(tp_stat.ts_pkt_rcvd & 0x1) {
52936403Ssklower 					tpclnp_ctlinput(PRC_QUENCH, &src);
53036403Ssklower 				} else {
53136403Ssklower 					tpclnp_ctlinput(PRC_QUENCH2, &src);
53236403Ssklower 				}
53336403Ssklower 			}
53436403Ssklower 		}
53536403Ssklower 	ENDDEBUG
53636403Ssklower 
53736403Ssklower 	splx(s);
53836403Ssklower 	return 0;
53936403Ssklower }
54036403Ssklower 
54136403Ssklower ProtoHook
54236403Ssklower iso_rtchange()
54336403Ssklower {
54436403Ssklower 	return 0;
54536403Ssklower }
54636403Ssklower 
54736403Ssklower /*
54836403Ssklower  * CALLED FROM:
54936403Ssklower  *  tpclnp_ctlinput()
55036403Ssklower  * FUNCTION and ARGUMENTS:
55136403Ssklower  *  find the tpcb pointer and pass it to tp_quench
55236403Ssklower  */
55336403Ssklower void
55436403Ssklower tpiso_decbit(isop)
55536403Ssklower 	struct isopcb *isop;
55636403Ssklower {
557*37469Ssklower 	tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH2);
55836403Ssklower }
55936403Ssklower /*
56036403Ssklower  * CALLED FROM:
56136403Ssklower  *  tpclnp_ctlinput()
56236403Ssklower  * FUNCTION and ARGUMENTS:
56336403Ssklower  *  find the tpcb pointer and pass it to tp_quench
56436403Ssklower  */
56536403Ssklower void
56636403Ssklower tpiso_quench(isop)
56736403Ssklower 	struct isopcb *isop;
56836403Ssklower {
569*37469Ssklower 	tp_quench((struct tp_pcb *)isop->isop_socket->so_tpcb, PRC_QUENCH);
57036403Ssklower }
57136403Ssklower 
57236403Ssklower /*
57336403Ssklower  * CALLED FROM:
57436403Ssklower  *  The network layer through the protosw table.
57536403Ssklower  * FUNCTION and ARGUMENTS:
57636403Ssklower  *	When clnp an ICMP-like msg this gets called.
57736403Ssklower  *	It either returns an error status to the user or
57836403Ssklower  *	it causes all connections on this address to be aborted
57936403Ssklower  *	by calling the appropriate xx_notify() routine.
58036403Ssklower  *	(cmd) is the type of ICMP error.
58136403Ssklower  * 	(siso) is the address of the guy who sent the ER CLNPDU
58236403Ssklower  */
58336403Ssklower ProtoHook
58436403Ssklower tpclnp_ctlinput(cmd, siso)
58536403Ssklower 	int cmd;
58636403Ssklower 	struct sockaddr_iso *siso;
58736403Ssklower {
588*37469Ssklower 	return tpclnp_ctlinput1(cmd, &siso->siso_addr);
589*37469Ssklower }
590*37469Ssklower 
591*37469Ssklower /*
592*37469Ssklower  *	Entry to ctlinput with argument of an iso_addr rather than a sockaddr
593*37469Ssklower  */
594*37469Ssklower ProtoHook
595*37469Ssklower tpclnp_ctlinput1(cmd, isoa)
596*37469Ssklower 	int cmd;
597*37469Ssklower 	struct iso_addr	*isoa;
598*37469Ssklower {
59936403Ssklower 	extern u_char inetctlerrmap[];
60036403Ssklower 	extern ProtoHook tpiso_abort();
60136403Ssklower 	extern ProtoHook iso_rtchange();
60236403Ssklower 	extern ProtoHook tpiso_reset();
603*37469Ssklower 	void iso_pcbnotify();
60436403Ssklower 
60536403Ssklower 	IFDEBUG(D_TPINPUT)
606*37469Ssklower 		printf("tpclnp_ctlinput1: cmd 0x%x addr: %s\n", cmd,
607*37469Ssklower 			clnp_iso_addrp(isoa));
60836403Ssklower 	ENDDEBUG
60936403Ssklower 
61036403Ssklower 	if (cmd < 0 || cmd > PRC_NCMDS)
61136403Ssklower 		return 0;
61236403Ssklower 	switch (cmd) {
61336403Ssklower 
61436403Ssklower 		case	PRC_QUENCH2:
615*37469Ssklower 			iso_pcbnotify(&tp_isopcb, isoa, 0, (int (*)())tpiso_decbit);
61636403Ssklower 			break;
61736403Ssklower 
61836403Ssklower 		case	PRC_QUENCH:
619*37469Ssklower 			iso_pcbnotify(&tp_isopcb, isoa, 0, (int (*)())tpiso_quench);
62036403Ssklower 			break;
62136403Ssklower 
62236403Ssklower 		case	PRC_TIMXCEED_REASS:
62336403Ssklower 		case	PRC_ROUTEDEAD:
624*37469Ssklower 			iso_pcbnotify(&tp_isopcb, isoa, 0, tpiso_reset);
62536403Ssklower 			break;
62636403Ssklower 
62736403Ssklower 		case	PRC_HOSTUNREACH:
62836403Ssklower 		case	PRC_UNREACH_NET:
62936403Ssklower 		case	PRC_IFDOWN:
63036403Ssklower 		case	PRC_HOSTDEAD:
631*37469Ssklower 			iso_pcbnotify(&tp_isopcb, isoa,
63236403Ssklower 					(int)inetctlerrmap[cmd], iso_rtchange);
63336403Ssklower 			break;
63436403Ssklower 
63536403Ssklower 		default:
63636403Ssklower 		/*
63736403Ssklower 		case	PRC_MSGSIZE:
63836403Ssklower 		case	PRC_UNREACH_HOST:
63936403Ssklower 		case	PRC_UNREACH_PROTOCOL:
64036403Ssklower 		case	PRC_UNREACH_PORT:
64136403Ssklower 		case	PRC_UNREACH_NEEDFRAG:
64236403Ssklower 		case	PRC_UNREACH_SRCFAIL:
64336403Ssklower 		case	PRC_REDIRECT_NET:
64436403Ssklower 		case	PRC_REDIRECT_HOST:
64536403Ssklower 		case	PRC_REDIRECT_TOSNET:
64636403Ssklower 		case	PRC_REDIRECT_TOSHOST:
64736403Ssklower 		case	PRC_TIMXCEED_INTRANS:
64836403Ssklower 		case	PRC_PARAMPROB:
64936403Ssklower 		*/
650*37469Ssklower 		iso_pcbnotify(&tp_isopcb, isoa, (int)inetctlerrmap[cmd], tpiso_abort);
65136403Ssklower 		break;
65236403Ssklower 	}
65336403Ssklower 	return 0;
65436403Ssklower }
65536403Ssklower 
65636403Ssklower /*
65736403Ssklower  * These next 2 routines are
65836403Ssklower  * CALLED FROM:
65936403Ssklower  *	xxx_notify() from tp_ctlinput() when
66036403Ssklower  *  net level gets some ICMP-equiv. type event.
66136403Ssklower  * FUNCTION and ARGUMENTS:
66236403Ssklower  *  Cause the connection to be aborted with some sort of error
66336403Ssklower  *  reason indicating that the network layer caused the abort.
66436403Ssklower  *  Fakes an ER TPDU so we can go through the driver.
66536403Ssklower  *  abort always aborts the TP connection.
66636403Ssklower  *  reset may or may not, depending on the TP class that's in use.
66736403Ssklower  */
66836403Ssklower ProtoHook
66936403Ssklower tpiso_abort(isop)
67036403Ssklower 	struct isopcb *isop;
67136403Ssklower {
67236403Ssklower 	struct tp_event e;
67336403Ssklower 
67436403Ssklower 	IFDEBUG(D_CONN)
67536403Ssklower 		printf("tpiso_abort 0x%x\n", isop);
67636403Ssklower 	ENDDEBUG
67736403Ssklower 	e.ev_number = ER_TPDU;
67836403Ssklower 	e.ATTR(ER_TPDU).e_reason = ECONNABORTED;
67936403Ssklower 	return  tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e);
68036403Ssklower }
68136403Ssklower 
68236403Ssklower ProtoHook
68336403Ssklower tpiso_reset(isop)
68436403Ssklower 	struct isopcb *isop;
68536403Ssklower {
68636403Ssklower 	struct tp_event e;
68736403Ssklower 
68836403Ssklower 	e.ev_number = T_NETRESET;
68936403Ssklower 	return tp_driver((struct tp_pcb *)isop->isop_socket->so_tpcb, &e);
69036403Ssklower 
69136403Ssklower }
69236403Ssklower 
69336403Ssklower #endif ISO
694