xref: /csrg-svn/sys/netiso/tp_subr2.c (revision 48744)
136414Ssklower /***********************************************************
236414Ssklower 		Copyright IBM Corporation 1987
336414Ssklower 
436414Ssklower                       All Rights Reserved
536414Ssklower 
636414Ssklower Permission to use, copy, modify, and distribute this software and its
736414Ssklower documentation for any purpose and without fee is hereby granted,
836414Ssklower provided that the above copyright notice appear in all copies and that
936414Ssklower both that copyright notice and this permission notice appear in
1036414Ssklower supporting documentation, and that the name of IBM not be
1136414Ssklower used in advertising or publicity pertaining to distribution of the
1236414Ssklower software without specific, written prior permission.
1336414Ssklower 
1436414Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536414Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636414Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736414Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836414Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936414Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036414Ssklower SOFTWARE.
2136414Ssklower 
2236414Ssklower ******************************************************************/
2336414Ssklower 
2436414Ssklower /*
2536414Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636414Ssklower  */
2736414Ssklower /*
2836414Ssklower  * ARGO TP
2936414Ssklower  *
3036414Ssklower  * $Header: tp_subr2.c,v 5.5 88/11/18 17:28:55 nhall Exp $
3136414Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_subr2.c,v $
32*48744Ssklower  *	@(#)tp_subr2.c	7.7 (Berkeley) 04/26/91
3336414Ssklower  *
3436414Ssklower  * Some auxiliary routines:
3536414Ssklower  * 		tp_protocol_error: required by xebec- called when a combo of state,
3636414Ssklower  *			event, predicate isn't covered for by the transition file.
3736414Ssklower  *		tp_indicate: gives indications(signals) to the user process
3836414Ssklower  *		tp_getoptions: initializes variables that are affected by the options
3936414Ssklower  *          chosen.
4036414Ssklower  */
4136414Ssklower 
4236414Ssklower #ifndef lint
4336414Ssklower static char *rcsid = "$Header: tp_subr2.c,v 5.5 88/11/18 17:28:55 nhall Exp $";
4436414Ssklower #endif lint
4536414Ssklower 
4636414Ssklower /* this def'n is to cause the expansion of this macro in the
4736414Ssklower  * routine tp_local_credit :
4836414Ssklower  */
4936414Ssklower #define LOCAL_CREDIT_EXPAND
5036414Ssklower 
5136414Ssklower #include "param.h"
5236414Ssklower #include "mbuf.h"
5336414Ssklower #include "socket.h"
5436414Ssklower #include "socketvar.h"
5536414Ssklower #include "domain.h"
5636414Ssklower #include "protosw.h"
5736414Ssklower #include "errno.h"
5836414Ssklower #include "types.h"
5936414Ssklower #include "time.h"
6036414Ssklower #include "kernel.h"
6136414Ssklower #undef MNULL
6237469Ssklower #include "argo_debug.h"
6337469Ssklower #include "tp_param.h"
6437469Ssklower #include "tp_ip.h"
6537469Ssklower #include "iso.h"
6637469Ssklower #include "iso_errno.h"
6737469Ssklower #include "iso_pcb.h"
6837469Ssklower #include "tp_timer.h"
6937469Ssklower #include "tp_stat.h"
7037469Ssklower #include "tp_tpdu.h"
7137469Ssklower #include "tp_pcb.h"
7237469Ssklower #include "tp_seq.h"
7337469Ssklower #include "tp_trace.h"
7437469Ssklower #include "tp_user.h"
7537469Ssklower #include "cons.h"
7636414Ssklower 
7745900Ssklower #include "../net/if.h"
7845900Ssklower #ifdef TRUE
7945900Ssklower #undef FALSE
8045900Ssklower #undef TRUE
8145900Ssklower #endif
8245900Ssklower #include "../netccitt/x25.h"
8345900Ssklower #include "../netccitt/pk.h"
8445900Ssklower #include "../netccitt/pk_var.h"
8545900Ssklower 
8636414Ssklower /*
8736414Ssklower  * NAME: 	tp_local_credit()
8836414Ssklower  *
8936414Ssklower  * CALLED FROM:
9036414Ssklower  *  tp_emit(), tp_usrreq()
9136414Ssklower  *
9236414Ssklower  * FUNCTION and ARGUMENTS:
9336414Ssklower  *	Computes the local credit and stashes it in tpcb->tp_lcredit.
9436414Ssklower  *  It's a macro in the production system rather than a procdure.
9536414Ssklower  *
9636414Ssklower  * RETURNS:
9736414Ssklower  *
9836414Ssklower  * SIDE EFFECTS:
9936414Ssklower  *
10036414Ssklower  * NOTES:
10136414Ssklower  *  This doesn't actually get called in a production system -
10236414Ssklower  *  the macro gets expanded instead in place of calls to this proc.
10336414Ssklower  *  But for debugging, we call this and that allows us to add
10436414Ssklower  *  debugging messages easily here.
10536414Ssklower  */
10636414Ssklower void
10736414Ssklower tp_local_credit(tpcb)
10836414Ssklower 	struct tp_pcb *tpcb;
10936414Ssklower {
11036414Ssklower 	LOCAL_CREDIT(tpcb);
11136414Ssklower 	IFDEBUG(D_CREDIT)
11236414Ssklower 		printf("ref 0x%x lcdt 0x%x l_tpdusize 0x%x decbit 0x%x\n",
11336414Ssklower 			tpcb->tp_refp - tp_ref,
11436414Ssklower 			tpcb->tp_lcredit,
11536414Ssklower 			tpcb->tp_l_tpdusize,
11636414Ssklower 			tpcb->tp_decbit,
11736414Ssklower 			tpcb->tp_cong_win
11836414Ssklower 			);
11936414Ssklower 	ENDDEBUG
12036414Ssklower 	IFTRACE(D_CREDIT)
12136414Ssklower 		tptraceTPCB(TPPTmisc,
12236414Ssklower 			"lcdt tpdusz \n",
12336414Ssklower 			 tpcb->tp_lcredit, tpcb->tp_l_tpdusize, 0, 0);
12436414Ssklower 	ENDTRACE
12536414Ssklower }
12636414Ssklower 
12736414Ssklower /*
12836414Ssklower  * NAME:  tp_protocol_error()
12936414Ssklower  *
13036414Ssklower  * CALLED FROM:
13136414Ssklower  *  tp_driver(), when it doesn't know what to do with
13236414Ssklower  * 	a combo of event, state, predicate
13336414Ssklower  *
13436414Ssklower  * FUNCTION and ARGUMENTS:
13536414Ssklower  *  print error mesg
13636414Ssklower  *
13736414Ssklower  * RETURN VALUE:
13836414Ssklower  *  EIO - always
13936414Ssklower  *
14036414Ssklower  * SIDE EFFECTS:
14136414Ssklower  *
14236414Ssklower  * NOTES:
14336414Ssklower  */
14436414Ssklower int
14536414Ssklower tp_protocol_error(e,tpcb)
14636414Ssklower 	struct tp_event	*e;
14736414Ssklower 	struct tp_pcb	*tpcb;
14836414Ssklower {
14936414Ssklower 	printf("TP PROTOCOL ERROR! tpcb 0x%x event 0x%x, state 0x%x\n",
15036414Ssklower 		tpcb, e->ev_number, tpcb->tp_state);
15136414Ssklower 	IFTRACE(D_DRIVER)
15236414Ssklower 		tptraceTPCB(TPPTmisc, "PROTOCOL ERROR tpcb event state",
15336414Ssklower 			tpcb, e->ev_number, tpcb->tp_state, 0 );
15436414Ssklower 	ENDTRACE
15536414Ssklower 	return EIO; /* for lack of anything better */
15636414Ssklower }
15736414Ssklower 
15836414Ssklower 
15936414Ssklower /* Not used at the moment */
16036414Ssklower ProtoHook
16136414Ssklower tp_drain()
16236414Ssklower {
16336414Ssklower 	return 0;
16436414Ssklower }
16536414Ssklower 
16636414Ssklower 
16736414Ssklower /*
16836414Ssklower  * NAME: tp_indicate()
16936414Ssklower  *
17036414Ssklower  * CALLED FROM:
17136414Ssklower  * 	tp.trans when XPD arrive, when a connection is being disconnected by
17236414Ssklower  *  the arrival of a DR or ER, and when a connection times out.
17336414Ssklower  *
17436414Ssklower  * FUNCTION and ARGUMENTS:
17536414Ssklower  *  (ind) is the type of indication : T_DISCONNECT, T_XPD
17636414Ssklower  *  (error) is an E* value that will be put in the socket structure
17736414Ssklower  *  to be passed along to the user later.
17836414Ssklower  * 	Gives a SIGURG to the user process or group indicated by the socket
17936414Ssklower  * 	attached to the tpcb.
18036414Ssklower  *
18136414Ssklower  * RETURNS:  Rien
18236414Ssklower  *
18336414Ssklower  * SIDE EFFECTS:
18436414Ssklower  *
18536414Ssklower  * NOTES:
18636414Ssklower  */
18736414Ssklower void
18836414Ssklower tp_indicate(ind, tpcb, error)
18936414Ssklower 	int				ind;
19036414Ssklower 	u_short			error;
19136414Ssklower 	register struct tp_pcb	*tpcb;
19236414Ssklower {
19336414Ssklower 	register struct socket *so = tpcb->tp_sock;
19436414Ssklower 	IFTRACE(D_INDICATION)
19539197Ssklower 		tptraceTPCB(TPPTindicate, ind, *(u_short *)(tpcb->tp_lsuffix),
19639197Ssklower 			*(u_short *)(tpcb->tp_fsuffix), error,so->so_pgid);
19736414Ssklower 	ENDTRACE
19836414Ssklower 	IFDEBUG(D_INDICATION)
19937469Ssklower 		char *ls, *fs;
20036414Ssklower 		ls = tpcb->tp_lsuffix,
20136414Ssklower 		fs = tpcb->tp_fsuffix,
20236414Ssklower 
20336414Ssklower 		printf(
20437469Ssklower "indicate 0x%x lsuf 0x%02x%02x fsuf 0x%02x%02x err 0x%x  noind 0x%x ref 0x%x\n",
20536414Ssklower 		ind,
20636414Ssklower 		*ls, *(ls+1), *fs, *(fs+1),
20737469Ssklower 		error, /*so->so_pgrp,*/
20836414Ssklower 		tpcb->tp_no_disc_indications,
20936414Ssklower 		tpcb->tp_lref);
21036414Ssklower 	ENDDEBUG
21136414Ssklower 
212*48744Ssklower 	if (ind == ER_TPDU) {
213*48744Ssklower 		register struct mbuf *m;
214*48744Ssklower 		struct tp_disc_reason x;
215*48744Ssklower 
216*48744Ssklower 		if ((so->so_state & SS_CANTRCVMORE) == 0 &&
217*48744Ssklower 				(m = m_get(M_DONTWAIT, MT_OOBDATA)) != 0) {
218*48744Ssklower 
219*48744Ssklower 			x.dr_hdr.cmsg_len = m->m_len = sizeof(x);
220*48744Ssklower 			x.dr_hdr.cmsg_level = SOL_TRANSPORT;
221*48744Ssklower 			x.dr_hdr.cmsg_type= TPOPT_DISC_REASON;
222*48744Ssklower 			x.dr_reason = error;
223*48744Ssklower 			*mtod(m, struct tp_disc_reason *) = x;
224*48744Ssklower 			sbappendrecord(&tpcb->tp_Xrcv, m);
225*48744Ssklower 			error = 0;
226*48744Ssklower 		} else
227*48744Ssklower 			error = ECONNRESET;
228*48744Ssklower 	}
22936414Ssklower 	so->so_error = error;
23036414Ssklower 
23136414Ssklower 	if (ind == T_DISCONNECT)  {
232*48744Ssklower 		so->so_error = ENOTCONN;
23336414Ssklower 		if ( tpcb->tp_no_disc_indications )
23436414Ssklower 			return;
23536414Ssklower 	}
23636414Ssklower 	IFTRACE(D_INDICATION)
23736414Ssklower 		tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0);
23836414Ssklower 	ENDTRACE
23936414Ssklower 	sohasoutofband(so);
24036414Ssklower }
24136414Ssklower 
24236414Ssklower /*
24336414Ssklower  * NAME : tp_getoptions()
24436414Ssklower  *
24536414Ssklower  * CALLED FROM:
24636414Ssklower  * 	tp.trans whenever we go into OPEN state
24736414Ssklower  *
24836414Ssklower  * FUNCTION and ARGUMENTS:
24936414Ssklower  *  sets the proper flags and values in the tpcb, to control
25036414Ssklower  *  the appropriate actions for the given class, options,
25136414Ssklower  *  sequence space, etc, etc.
25236414Ssklower  *
25336414Ssklower  * RETURNS: Nada
25436414Ssklower  *
25536414Ssklower  * SIDE EFFECTS:
25636414Ssklower  *
25736414Ssklower  * NOTES:
25836414Ssklower  */
25936414Ssklower void
26036414Ssklower tp_getoptions(tpcb)
26136414Ssklower struct tp_pcb *tpcb;
26236414Ssklower {
26336414Ssklower 	tpcb->tp_seqmask =
26436414Ssklower 		tpcb->tp_xtd_format ?	TP_XTD_FMT_MASK :	TP_NML_FMT_MASK ;
26536414Ssklower 	tpcb->tp_seqbit =
26636414Ssklower 		tpcb->tp_xtd_format ?	TP_XTD_FMT_BIT :	TP_NML_FMT_BIT ;
26736414Ssklower 	tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
26836414Ssklower 	tpcb->tp_dt_ticks =
26936414Ssklower 		MAX(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2));
27036414Ssklower 
27136414Ssklower }
27236414Ssklower 
27336414Ssklower /*
27436414Ssklower  * NAME:  tp_recycle_tsuffix()
27536414Ssklower  *
27636414Ssklower  * CALLED FROM:
27736414Ssklower  *  Called when a ref is frozen.
27836414Ssklower  *
27936414Ssklower  * FUNCTION and ARGUMENTS:
28036414Ssklower  *  allows the suffix to be reused.
28136414Ssklower  *
28236414Ssklower  * RETURNS: zilch
28336414Ssklower  *
28436414Ssklower  * SIDE EFFECTS:
28536414Ssklower  *
28636414Ssklower  * NOTES:
28736414Ssklower  */
28836414Ssklower void
28936414Ssklower tp_recycle_tsuffix(tpcb)
29036414Ssklower 	struct tp_pcb	*tpcb;
29136414Ssklower {
29237469Ssklower 	bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix));
29337469Ssklower 	bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix));
29436414Ssklower 	tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0;
29536414Ssklower 
29636414Ssklower 	(tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb);
29736414Ssklower }
29836414Ssklower 
29936414Ssklower /*
30036414Ssklower  * NAME: tp_quench()
30136414Ssklower  *
30236414Ssklower  * CALLED FROM:
30336414Ssklower  *  tp{af}_quench() when ICMP source quench or similar thing arrives.
30436414Ssklower  *
30536414Ssklower  * FUNCTION and ARGUMENTS:
30636414Ssklower  *  Drop the congestion window back to 1.
30736414Ssklower  *  Congestion window scheme:
30836414Ssklower  *  Initial value is 1.  ("slow start" as Nagle, et. al. call it)
30936414Ssklower  *  For each good ack that arrives, the congestion window is increased
31036414Ssklower  *  by 1 (up to max size of logical infinity, which is to say,
31136414Ssklower  *	it doesn't wrap around).
31236414Ssklower  *  Source quench causes it to drop back to 1.
31336414Ssklower  *  tp_send() uses the smaller of (regular window, congestion window).
31436414Ssklower  *  One retransmission strategy option is to have any retransmission
31536414Ssklower  *	cause reset the congestion window back  to 1.
31636414Ssklower  *
31736414Ssklower  *	(cmd) is either PRC_QUENCH: source quench, or
31836414Ssklower  *		PRC_QUENCH2: dest. quench (dec bit)
31936414Ssklower  *
32036414Ssklower  * RETURNS:
32136414Ssklower  *
32236414Ssklower  * SIDE EFFECTS:
32336414Ssklower  *
32436414Ssklower  * NOTES:
32536414Ssklower  */
32636414Ssklower void
32736414Ssklower tp_quench( tpcb, cmd )
32836414Ssklower 	struct tp_pcb *tpcb;
32936414Ssklower 	int cmd;
33036414Ssklower {
33136414Ssklower 	IFDEBUG(D_QUENCH)
33236414Ssklower 		printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n",
33339197Ssklower 			tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix));
33436414Ssklower 		printf("cong_win 0x%x decbit 0x%x \n",
33536414Ssklower 			tpcb->tp_cong_win, tpcb->tp_decbit);
33636414Ssklower 	ENDDEBUG
33736414Ssklower 	switch(cmd) {
33836414Ssklower 		case PRC_QUENCH:
33936414Ssklower 			tpcb->tp_cong_win = 1;
34036414Ssklower 			IncStat(ts_quench);
34136414Ssklower 			break;
34236414Ssklower 		case PRC_QUENCH2:
34336414Ssklower 			tpcb->tp_cong_win = 1; /* might as well quench source also */
34436414Ssklower 			tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT;
34536414Ssklower 			IncStat(ts_rcvdecbit);
34636414Ssklower 			break;
34736414Ssklower 	}
34836414Ssklower }
34936414Ssklower 
35036414Ssklower 
35136414Ssklower /*
35236414Ssklower  * NAME:	tp_netcmd()
35336414Ssklower  *
35436414Ssklower  * CALLED FROM:
35536414Ssklower  *
35636414Ssklower  * FUNCTION and ARGUMENTS:
35736414Ssklower  *
35836414Ssklower  * RETURNS:
35936414Ssklower  *
36036414Ssklower  * SIDE EFFECTS:
36136414Ssklower  *
36236414Ssklower  * NOTES:
36336414Ssklower  */
36436414Ssklower tp_netcmd( tpcb, cmd )
36536414Ssklower 	struct tp_pcb *tpcb;
36636414Ssklower 	int cmd;
36736414Ssklower {
36845900Ssklower #ifdef TPCONS
36945900Ssklower 	struct isopcb *isop;
37045900Ssklower 	struct pklcd *lcp;
37145900Ssklower 
37245900Ssklower 	if (tpcb->tp_netservice != ISO_CONS)
37345900Ssklower 		return;
37445900Ssklower 	isop = (struct isopcb *)tpcb->tp_npcb;
37545900Ssklower 	lcp = (struct pklcd *)isop->isop_chan;
37636414Ssklower 	switch (cmd) {
37736414Ssklower 
37836414Ssklower 	case CONN_CLOSE:
37936414Ssklower 	case CONN_REFUSE:
38045900Ssklower 		if (isop->isop_refcnt == 1)
38145900Ssklower 			pk_disconnect(lcp);
38245900Ssklower 		isop->isop_chan = 0;
38345900Ssklower 		isop->isop_refcnt = 0;
38436414Ssklower 		break;
38536414Ssklower 
38636414Ssklower 	default:
38736414Ssklower 		printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd);
38836414Ssklower 		break;
38936414Ssklower 	}
39045900Ssklower #else TPCONS
39136414Ssklower 	printf("tp_netcmd(): X25 NOT CONFIGURED!!\n");
39245900Ssklower #endif
39336414Ssklower }
39436414Ssklower /*
39536414Ssklower  * CALLED FROM:
39636414Ssklower  *  tp_ctloutput() and tp_emit()
39736414Ssklower  * FUNCTION and ARGUMENTS:
39836414Ssklower  * 	Convert a class mask to the highest numeric value it represents.
39936414Ssklower  */
40036414Ssklower 
40136414Ssklower int
40236414Ssklower tp_mask_to_num(x)
40336414Ssklower 	u_char x;
40436414Ssklower {
40536414Ssklower 	register int j;
40636414Ssklower 
40736414Ssklower 	for(j = 4; j>=0 ;j--) {
40836414Ssklower 		if(x & (1<<j))
40936414Ssklower 			break;
41036414Ssklower 	}
41136414Ssklower 	ASSERT( (j == 4) || (j == 0) ); /* for now */
41236414Ssklower 	if( (j != 4) && (j != 0) ) {
41336414Ssklower 		printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n",
41436414Ssklower 			x, j);
41536414Ssklower 	}
41636414Ssklower 	IFTRACE(D_TPINPUT)
41736414Ssklower 		tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0);
41836414Ssklower 	ENDTRACE
41936414Ssklower 	IFDEBUG(D_TPINPUT)
42036414Ssklower 		printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j);
42136414Ssklower 	ENDDEBUG
42236414Ssklower 	return j;
42336414Ssklower }
42436414Ssklower 
42536414Ssklower static
42636414Ssklower copyQOSparms(src, dst)
42736414Ssklower 	struct tp_conn_param *src, *dst;
42836414Ssklower {
42936414Ssklower 	/* copy all but the bits stuff at the end */
43036414Ssklower #define COPYSIZE (12 * sizeof(short))
43136414Ssklower 
43237469Ssklower 	bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE);
43336414Ssklower 	dst->p_tpdusize = src->p_tpdusize;
43436414Ssklower 	dst->p_ack_strat = src->p_ack_strat;
43536414Ssklower 	dst->p_rx_strat = src->p_rx_strat;
43636414Ssklower #undef COPYSIZE
43736414Ssklower }
43836414Ssklower 
43936414Ssklower /*
44036414Ssklower  * CALLED FROM:
44136414Ssklower  *  tp_usrreq on PRU_CONNECT and tp_input on receipt of CR
44236414Ssklower  *
44336414Ssklower  * FUNCTION and ARGUMENTS:
44436414Ssklower  * 	route directly to x.25 if the address is type 37 - GROT.
44536414Ssklower  *  furthermore, let TP0 handle only type-37 addresses
44636414Ssklower  *
44736414Ssklower  *	Since this assumes that its address argument is in a mbuf, the
44836414Ssklower  *	parameter was changed to reflect this assumtion. This also
44936414Ssklower  *	implies that an mbuf must be allocated when this is
45036414Ssklower  *	called from tp_input
45136414Ssklower  *
45236414Ssklower  * RETURNS:
45336414Ssklower  *	errno value	 :
45436414Ssklower  *	EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic)
45536414Ssklower  *	ECONNREFUSED if trying to run TP0 with non-type 37 address
45636414Ssklower  *  possibly other E* returned from cons_netcmd()
45736414Ssklower  * NOTE:
45836414Ssklower  *  Would like to eliminate as much of this as possible --
45936414Ssklower  *  only one set of defaults (let the user set the parms according
46036414Ssklower  *  to parameters provided in the directory service).
46136414Ssklower  *  Left here for now 'cause we don't yet have a clean way to handle
46236414Ssklower  *  it on the passive end.
46336414Ssklower  */
46436414Ssklower int
46536414Ssklower tp_route_to( m, tpcb, channel)
46636414Ssklower 	struct mbuf					*m;
46736414Ssklower 	register struct tp_pcb		*tpcb;
46845900Ssklower 	caddr_t 					channel;
46936414Ssklower {
47036414Ssklower 	register struct sockaddr_iso *siso;	/* NOTE: this may be a sockaddr_in */
47136414Ssklower 	extern struct tp_conn_param tp_conn_param[];
47245900Ssklower 	struct pklcd *lcp = (struct pklcd *)channel;
47336414Ssklower 	int error = 0;
47436414Ssklower 
47536414Ssklower 	siso = mtod(m, struct sockaddr_iso *);
47636414Ssklower 	IFTRACE(D_CONN)
47736414Ssklower 		tptraceTPCB(TPPTmisc,
47836414Ssklower 		"route_to: so  afi netservice class",
47937469Ssklower 		tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice,
48036414Ssklower 			tpcb->tp_class);
48136414Ssklower 	ENDTRACE
48236414Ssklower 	IFDEBUG(D_CONN)
48336414Ssklower 		printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n",
48436414Ssklower 			m, channel, tpcb, tpcb->tp_netservice);
48536414Ssklower 		printf("m->mlen x%x, m->m_data:\n", m->m_len);
48636414Ssklower 		dump_buf(mtod(m, caddr_t), m->m_len);
48736414Ssklower 	ENDDEBUG
48845900Ssklower 	if (siso->siso_family != tpcb->tp_domain) {
48936414Ssklower 		error = EAFNOSUPPORT;
49036414Ssklower 		goto done;
49136414Ssklower 	}
49237469Ssklower 	IFDEBUG(D_CONN)
49337469Ssklower 		printf("tp_route_to  calling nlp_pcbconn, netserv %d\n",
49437469Ssklower 			tpcb->tp_netservice);
49537469Ssklower 	ENDDEBUG
49645900Ssklower #ifdef TPCONS
49745900Ssklower 	if (lcp) {
49845900Ssklower 		struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext,
49945900Ssklower 			*isop_new = (struct isopcb *)tpcb->tp_sock->so_pcb;
50045900Ssklower 		remque(isop_new);
50145900Ssklower 		free(isop_new, M_PCB);
50245900Ssklower 		tpcb->tp_sock->so_pcb = (caddr_t)isop;
50345900Ssklower 		if (isop->isop_refcnt == 0) {
50445900Ssklower 			extern struct isopcb tp_isopcb;
50545900Ssklower 			remque(isop);
50645900Ssklower 			insque(isop, &tp_isopcb);
50745900Ssklower 			isop->isop_head = &tp_isopcb;
50845900Ssklower 			iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL);
50945900Ssklower 		}
51045900Ssklower 		/* else there are already connections sharing this */
51145900Ssklower 		isop->isop_refcnt++;
51245900Ssklower 	} else
51345900Ssklower #endif
51445900Ssklower 		error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_sock->so_pcb, m);
51537469Ssklower 	if( error )
51637469Ssklower 		goto done;
51737469Ssklower 
51836414Ssklower 	{
51936414Ssklower 		register int save_netservice = tpcb->tp_netservice;
52036414Ssklower 
52136414Ssklower 		switch(tpcb->tp_netservice) {
52236414Ssklower 		case ISO_COSNS:
52336414Ssklower 		case ISO_CLNS:
52436414Ssklower 			/* This is a kludge but seems necessary so the passive end
52536414Ssklower 			 * can get long enough timers. sigh.
52637469Ssklower 			if( siso->siso_addr.osinet_idi[1] == (u_char)IDI_OSINET )
52736414Ssklower 			 */
52838841Ssklower #define	IDI_OSINET	0x0004	/* bcd of "0004" */
52937469Ssklower 			if( siso->siso_addr.isoa_genaddr[2] == (char)IDI_OSINET ) {
53036414Ssklower 				if( tpcb->tp_dont_change_params == 0) {
53136414Ssklower 					copyQOSparms( &tp_conn_param[ISO_COSNS],
53236414Ssklower 							&tpcb->_tp_param);
53336414Ssklower 				}
53436414Ssklower 				tpcb->tp_flags |= TPF_NLQOS_PDN;
53536414Ssklower 			}
53636414Ssklower 			/* drop through to IN_CLNS*/
53736414Ssklower 		case IN_CLNS:
53837469Ssklower 			if (iso_localifa(siso))
53937469Ssklower 				tpcb->tp_flags |= TPF_PEER_ON_SAMENET;
54036414Ssklower 			if( (tpcb->tp_class & TP_CLASS_4)==0 ) {
54136414Ssklower 				error = EPROTOTYPE;
54236414Ssklower 				break;
54336414Ssklower 			}
54436414Ssklower 			tpcb->tp_class = TP_CLASS_4;  /* IGNORE dont_change_parms */
54536414Ssklower 			break;
54636414Ssklower 
54736414Ssklower 		case ISO_CONS:
54845900Ssklower #ifdef TPCONS
54936414Ssklower 			tpcb->tp_flags |= TPF_NLQOS_PDN;
55036414Ssklower 			if( tpcb->tp_dont_change_params == 0 ) {
55136414Ssklower 				copyQOSparms( &tp_conn_param[ISO_CONS],
55236414Ssklower 							&tpcb->_tp_param);
55336414Ssklower 			}
55436414Ssklower 			/*
55536414Ssklower 			 * for use over x.25 really need a small receive window,
55636414Ssklower 			 * need to start slowly, need small max negotiable tpdu size,
55736414Ssklower 			 * and need to use the congestion window to the max
55836414Ssklower 			 * IGNORES tp_dont_change_params for these!
55936414Ssklower 			 */
56036414Ssklower 			if( tpcb->tp_sock->so_snd.sb_hiwat > 512 ) {
56136414Ssklower 				(void) soreserve(tpcb->tp_sock, 512, 512 );/* GAG */
56236414Ssklower 			}
56336414Ssklower 			tpcb->tp_rx_strat =  TPRX_USE_CW;
56436414Ssklower 
56536414Ssklower 			if( (tpcb->tp_nlproto != &nl_protosw[ISO_CONS]) ) {
56636414Ssklower 				IFDEBUG(D_CONN)
56736414Ssklower 					printf(
56836414Ssklower 					"tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n",
56936414Ssklower 							tpcb->tp_nlproto , &nl_protosw[ISO_CONS]);
57036414Ssklower 				ENDDEBUG
57136414Ssklower 				tpcb->tp_nlproto = &nl_protosw[ISO_CONS];
57236414Ssklower 			}
57336414Ssklower 			/* class 4 doesn't need to open a vc now - may use one already
57436414Ssklower 			 * opened or may open one only when it sends a pkt.
57536414Ssklower 			 */
57645900Ssklower #else TPCONS
57736414Ssklower 			error = ECONNREFUSED;
57845900Ssklower #endif TPCONS
57936414Ssklower 			break;
58036414Ssklower 		default:
58136414Ssklower 			error = EPROTOTYPE;
58236414Ssklower 		}
58336414Ssklower 
58436414Ssklower 		ASSERT( save_netservice == tpcb->tp_netservice);
58536414Ssklower 	}
58645900Ssklower 	if (error) {
58736414Ssklower 		tp_netcmd( tpcb, CONN_CLOSE);
58836414Ssklower 		goto done;
58936414Ssklower 	}
59036414Ssklower 	{	/* start with the global rtt, rtv stats */
59136414Ssklower 		register int i =
59236414Ssklower 		   (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN);
59336414Ssklower 
59436414Ssklower 		tpcb->tp_rtt = tp_stat.ts_rtt[i];
59536414Ssklower 		tpcb->tp_rtv = tp_stat.ts_rtv[i];
59636414Ssklower 	}
59736414Ssklower done:
59836414Ssklower 	IFDEBUG(D_CONN)
59936414Ssklower 		printf("tp_route_to  returns 0x%x\n", error);
60036414Ssklower 	ENDDEBUG
60136414Ssklower 	IFTRACE(D_CONN)
60236414Ssklower 		tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error,
60336414Ssklower 			tpcb->tp_netservice, tpcb->tp_class, 0);
60436414Ssklower 	ENDTRACE
60536414Ssklower 	return error;
60636414Ssklower }
60736414Ssklower 
60847280Ssklower 
60947280Ssklower /* class zero version */
61047280Ssklower void
61147280Ssklower tp0_stash( tpcb, e )
61247280Ssklower 	register struct tp_pcb		*tpcb;
61347280Ssklower 	register struct tp_event	*e;
61447280Ssklower {
61547280Ssklower #ifndef lint
61647280Ssklower #define E e->ATTR(DT_TPDU)
61747280Ssklower #else lint
61847280Ssklower #define E e->ev_union.EV_DT_TPDU
61947280Ssklower #endif lint
62047280Ssklower 
62147280Ssklower 	register struct sockbuf *sb = &tpcb->tp_sock->so_rcv;
62247280Ssklower 	register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
62347280Ssklower 
62447280Ssklower 	IFPERF(tpcb)
62547280Ssklower 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
62647280Ssklower 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
62747280Ssklower 				E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
62847280Ssklower 	ENDPERF
62947280Ssklower 
63047280Ssklower 	IFDEBUG(D_STASH)
63147280Ssklower 		printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x",
63247280Ssklower 		E.e_seq, E.e_datalen, E.e_eot);
63347280Ssklower 	ENDDEBUG
63447280Ssklower 
63547280Ssklower 	IFTRACE(D_STASH)
63647280Ssklower 		tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
63747280Ssklower 		E.e_seq, E.e_datalen, E.e_eot, 0);
63847280Ssklower 	ENDTRACE
63947280Ssklower 
64047280Ssklower 	if ( E.e_eot ) {
64147280Ssklower 		register struct mbuf *n = E.e_data;
64247280Ssklower 		n->m_flags |= M_EOR;
64347280Ssklower 		n->m_act = MNULL; /* set on tp_input */
64447280Ssklower 	}
64547280Ssklower 	sbappend(sb, E.e_data);
64647280Ssklower 	IFDEBUG(D_STASH)
64747280Ssklower 		dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending");
64847280Ssklower 	ENDDEBUG
64947280Ssklower 	if (tpcb->tp_netservice != ISO_CONS)
65047280Ssklower 		printf("tp0_stash: tp running over something wierd\n");
65147280Ssklower 	else {
65247280Ssklower 		register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
65347280Ssklower 		pk_flowcontrol(lcp, sbspace(sb) <= 0, 1);
65447280Ssklower 	}
65547280Ssklower }
65647280Ssklower 
65747280Ssklower void
65847280Ssklower tp0_openflow(tpcb)
65947280Ssklower register struct tp_pcb *tpcb;
66047280Ssklower {
66147280Ssklower 	register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
66247280Ssklower 	if (tpcb->tp_netservice != ISO_CONS)
66347280Ssklower 		printf("tp0_openflow: tp running over something wierd\n");
66447280Ssklower 	else {
66547280Ssklower 		register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
66647280Ssklower 		if (lcp->lcd_rxrnr_condition)
66747280Ssklower 			pk_flowcontrol(lcp, 0, 0);
66847280Ssklower 	}
66947280Ssklower }
67047280Ssklower #ifndef TPCONS
67147280Ssklower static
67247280Ssklower pk_flowcontrol() {}
67347280Ssklower #endif
67447280Ssklower 
67536414Ssklower #ifdef TP_PERF_MEAS
67636414Ssklower /*
67736414Ssklower  * CALLED FROM:
67836414Ssklower  *  tp_ctloutput() when the user sets TPOPT_PERF_MEAS on
67936414Ssklower  *  and tp_newsocket() when a new connection is made from
68036414Ssklower  *  a listening socket with tp_perf_on == true.
68136414Ssklower  * FUNCTION and ARGUMENTS:
68236414Ssklower  *  (tpcb) is the usual; this procedure gets a clear cluster mbuf for
68336414Ssklower  *  a tp_pmeas structure, and makes tpcb->tp_p_meas point to it.
68436414Ssklower  * RETURN VALUE:
68536414Ssklower  *  ENOBUFS if it cannot get a cluster mbuf.
68636414Ssklower  */
68736414Ssklower 
68836414Ssklower int
68936414Ssklower tp_setup_perf(tpcb)
69036414Ssklower 	register struct tp_pcb *tpcb;
69136414Ssklower {
69236414Ssklower 	register struct mbuf *q;
69336414Ssklower 
69437469Ssklower 	if( tpcb->tp_p_meas == 0 ) {
69537469Ssklower 		MGET(q, M_WAITOK, MT_PCB);
69636414Ssklower 		if (q == 0)
69736414Ssklower 			return ENOBUFS;
69837469Ssklower 		MCLGET(q, M_WAITOK);
69937469Ssklower 		if ((q->m_flags & M_EXT) == 0) {
70037469Ssklower 			(void) m_free(q);
70136414Ssklower 			return ENOBUFS;
70236414Ssklower 		}
70337469Ssklower 		q->m_len = sizeof (struct tp_pmeas);
70437469Ssklower 		tpcb->tp_p_mbuf = q;
70537469Ssklower 		tpcb->tp_p_meas = mtod(q, struct tp_pmeas *);
70637469Ssklower 		bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) );
70737469Ssklower 		IFDEBUG(D_PERF_MEAS)
70837469Ssklower 			printf(
70937469Ssklower 			"tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n",
71037469Ssklower 				tpcb, tpcb->tp_sock, tpcb->tp_lref,
71137469Ssklower 				tpcb->tp_p_meas, tpcb->tp_perf_on);
71237469Ssklower 		ENDDEBUG
71337469Ssklower 		tpcb->tp_perf_on = 1;
71436414Ssklower 	}
71536414Ssklower 	return 0;
71636414Ssklower }
71736414Ssklower #endif TP_PERF_MEAS
71836414Ssklower 
71936414Ssklower #ifdef ARGO_DEBUG
72036414Ssklower dump_addr (addr)
72136414Ssklower 	register struct sockaddr *addr;
72236414Ssklower {
72336414Ssklower 	switch( addr->sa_family ) {
72436414Ssklower 		case AF_INET:
72537469Ssklower 			dump_inaddr((struct sockaddr_in *)addr);
72636414Ssklower 			break;
72737469Ssklower #ifdef ISO
72836414Ssklower 		case AF_ISO:
72937469Ssklower 			dump_isoaddr((struct sockaddr_iso *)addr);
73036414Ssklower 			break;
73137469Ssklower #endif ISO
73236414Ssklower 		default:
73336414Ssklower 			printf("BAD AF: 0x%x\n", addr->sa_family);
73436414Ssklower 			break;
73536414Ssklower 	}
73636414Ssklower }
73736414Ssklower 
73837469Ssklower #define	MAX_COLUMNS	8
73937469Ssklower /*
74037469Ssklower  *	Dump the buffer to the screen in a readable format. Format is:
74137469Ssklower  *
74237469Ssklower  *		hex/dec  where hex is the hex format, dec is the decimal format.
74337469Ssklower  *		columns of hex/dec numbers will be printed, followed by the
74437469Ssklower  *		character representations (if printable).
74537469Ssklower  */
74637469Ssklower Dump_buf(buf, len)
74737469Ssklower caddr_t	buf;
74837469Ssklower int		len;
74937469Ssklower {
75037469Ssklower 	int		i,j;
75137469Ssklower 
75237469Ssklower 	printf("Dump buf 0x%x len 0x%x\n", buf, len);
75337469Ssklower 	for (i = 0; i < len; i += MAX_COLUMNS) {
75437469Ssklower 		printf("+%d:\t", i);
75537469Ssklower 		for (j = 0; j < MAX_COLUMNS; j++) {
75637469Ssklower 			if (i + j < len) {
75737469Ssklower 				printf("%x/%d\t", buf[i+j]&0xff, buf[i+j]);
75837469Ssklower 			} else {
75937469Ssklower 				printf("	");
76037469Ssklower 			}
76137469Ssklower 		}
76237469Ssklower 
76337469Ssklower 		for (j = 0; j < MAX_COLUMNS; j++) {
76437469Ssklower 			if (i + j < len) {
76537469Ssklower 				if (((buf[i+j]) > 31) && ((buf[i+j]) < 128))
76637469Ssklower 					printf("%c", buf[i+j]&0xff);
76737469Ssklower 				else
76837469Ssklower 					printf(".");
76937469Ssklower 			}
77037469Ssklower 		}
77137469Ssklower 		printf("\n");
77237469Ssklower 	}
77337469Ssklower }
77437469Ssklower 
77537469Ssklower 
77636414Ssklower #endif ARGO_DEBUG
77736414Ssklower 
778