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