xref: /csrg-svn/sys/netiso/tp_subr2.c (revision 50648)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*50648Ssklower  *	@(#)tp_subr2.c	7.12 (Berkeley) 07/29/91
849268Sbostic  */
949268Sbostic 
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:
4349268Sbostic  * 	tp_protocol_error: required by xebec- called when a combo of state,
4449268Sbostic  *	    event, predicate isn't covered for by the transition file.
4549268Sbostic  *	tp_indicate: gives indications(signals) to the user process
4649268Sbostic  *	tp_getoptions: initializes variables that are affected by the options
4749268Sbostic  *	    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"
5650243Ssklower #include "systm.h"
5736414Ssklower #include "mbuf.h"
5836414Ssklower #include "socket.h"
5936414Ssklower #include "socketvar.h"
6036414Ssklower #include "domain.h"
6136414Ssklower #include "protosw.h"
6236414Ssklower #include "errno.h"
6336414Ssklower #include "types.h"
6436414Ssklower #include "time.h"
6536414Ssklower #include "kernel.h"
6636414Ssklower #undef MNULL
6737469Ssklower #include "argo_debug.h"
6837469Ssklower #include "tp_param.h"
6937469Ssklower #include "tp_ip.h"
7037469Ssklower #include "iso.h"
7137469Ssklower #include "iso_errno.h"
7237469Ssklower #include "iso_pcb.h"
7337469Ssklower #include "tp_timer.h"
7437469Ssklower #include "tp_stat.h"
7537469Ssklower #include "tp_tpdu.h"
7637469Ssklower #include "tp_pcb.h"
7737469Ssklower #include "tp_seq.h"
7837469Ssklower #include "tp_trace.h"
7937469Ssklower #include "tp_user.h"
8037469Ssklower #include "cons.h"
8136414Ssklower 
8245900Ssklower #include "../net/if.h"
83*50648Ssklower #include "../net/if_types.h"
8445900Ssklower #ifdef TRUE
8545900Ssklower #undef FALSE
8645900Ssklower #undef TRUE
8745900Ssklower #endif
8845900Ssklower #include "../netccitt/x25.h"
8945900Ssklower #include "../netccitt/pk.h"
9045900Ssklower #include "../netccitt/pk_var.h"
9145900Ssklower 
9236414Ssklower /*
9336414Ssklower  * NAME: 	tp_local_credit()
9436414Ssklower  *
9536414Ssklower  * CALLED FROM:
9636414Ssklower  *  tp_emit(), tp_usrreq()
9736414Ssklower  *
9836414Ssklower  * FUNCTION and ARGUMENTS:
9936414Ssklower  *	Computes the local credit and stashes it in tpcb->tp_lcredit.
10036414Ssklower  *  It's a macro in the production system rather than a procdure.
10136414Ssklower  *
10236414Ssklower  * RETURNS:
10336414Ssklower  *
10436414Ssklower  * SIDE EFFECTS:
10536414Ssklower  *
10636414Ssklower  * NOTES:
10736414Ssklower  *  This doesn't actually get called in a production system -
10836414Ssklower  *  the macro gets expanded instead in place of calls to this proc.
10936414Ssklower  *  But for debugging, we call this and that allows us to add
11036414Ssklower  *  debugging messages easily here.
11136414Ssklower  */
11236414Ssklower void
11336414Ssklower tp_local_credit(tpcb)
11436414Ssklower 	struct tp_pcb *tpcb;
11536414Ssklower {
11636414Ssklower 	LOCAL_CREDIT(tpcb);
11736414Ssklower 	IFDEBUG(D_CREDIT)
11836414Ssklower 		printf("ref 0x%x lcdt 0x%x l_tpdusize 0x%x decbit 0x%x\n",
11936414Ssklower 			tpcb->tp_refp - tp_ref,
12036414Ssklower 			tpcb->tp_lcredit,
12136414Ssklower 			tpcb->tp_l_tpdusize,
12236414Ssklower 			tpcb->tp_decbit,
12336414Ssklower 			tpcb->tp_cong_win
12436414Ssklower 			);
12536414Ssklower 	ENDDEBUG
12636414Ssklower 	IFTRACE(D_CREDIT)
12736414Ssklower 		tptraceTPCB(TPPTmisc,
12836414Ssklower 			"lcdt tpdusz \n",
12936414Ssklower 			 tpcb->tp_lcredit, tpcb->tp_l_tpdusize, 0, 0);
13036414Ssklower 	ENDTRACE
13136414Ssklower }
13236414Ssklower 
13336414Ssklower /*
13436414Ssklower  * NAME:  tp_protocol_error()
13536414Ssklower  *
13636414Ssklower  * CALLED FROM:
13736414Ssklower  *  tp_driver(), when it doesn't know what to do with
13836414Ssklower  * 	a combo of event, state, predicate
13936414Ssklower  *
14036414Ssklower  * FUNCTION and ARGUMENTS:
14136414Ssklower  *  print error mesg
14236414Ssklower  *
14336414Ssklower  * RETURN VALUE:
14436414Ssklower  *  EIO - always
14536414Ssklower  *
14636414Ssklower  * SIDE EFFECTS:
14736414Ssklower  *
14836414Ssklower  * NOTES:
14936414Ssklower  */
15036414Ssklower int
15136414Ssklower tp_protocol_error(e,tpcb)
15236414Ssklower 	struct tp_event	*e;
15336414Ssklower 	struct tp_pcb	*tpcb;
15436414Ssklower {
15536414Ssklower 	printf("TP PROTOCOL ERROR! tpcb 0x%x event 0x%x, state 0x%x\n",
15636414Ssklower 		tpcb, e->ev_number, tpcb->tp_state);
15736414Ssklower 	IFTRACE(D_DRIVER)
15836414Ssklower 		tptraceTPCB(TPPTmisc, "PROTOCOL ERROR tpcb event state",
15936414Ssklower 			tpcb, e->ev_number, tpcb->tp_state, 0 );
16036414Ssklower 	ENDTRACE
16136414Ssklower 	return EIO; /* for lack of anything better */
16236414Ssklower }
16336414Ssklower 
16436414Ssklower 
16536414Ssklower /* Not used at the moment */
16636414Ssklower ProtoHook
16736414Ssklower tp_drain()
16836414Ssklower {
16936414Ssklower 	return 0;
17036414Ssklower }
17136414Ssklower 
17236414Ssklower 
17336414Ssklower /*
17436414Ssklower  * NAME: tp_indicate()
17536414Ssklower  *
17636414Ssklower  * CALLED FROM:
17736414Ssklower  * 	tp.trans when XPD arrive, when a connection is being disconnected by
17836414Ssklower  *  the arrival of a DR or ER, and when a connection times out.
17936414Ssklower  *
18036414Ssklower  * FUNCTION and ARGUMENTS:
18136414Ssklower  *  (ind) is the type of indication : T_DISCONNECT, T_XPD
18236414Ssklower  *  (error) is an E* value that will be put in the socket structure
18336414Ssklower  *  to be passed along to the user later.
18436414Ssklower  * 	Gives a SIGURG to the user process or group indicated by the socket
18536414Ssklower  * 	attached to the tpcb.
18636414Ssklower  *
18736414Ssklower  * RETURNS:  Rien
18836414Ssklower  *
18936414Ssklower  * SIDE EFFECTS:
19036414Ssklower  *
19136414Ssklower  * NOTES:
19236414Ssklower  */
19336414Ssklower void
19436414Ssklower tp_indicate(ind, tpcb, error)
19536414Ssklower 	int				ind;
19636414Ssklower 	u_short			error;
19736414Ssklower 	register struct tp_pcb	*tpcb;
19836414Ssklower {
19936414Ssklower 	register struct socket *so = tpcb->tp_sock;
20036414Ssklower 	IFTRACE(D_INDICATION)
20139197Ssklower 		tptraceTPCB(TPPTindicate, ind, *(u_short *)(tpcb->tp_lsuffix),
20239197Ssklower 			*(u_short *)(tpcb->tp_fsuffix), error,so->so_pgid);
20336414Ssklower 	ENDTRACE
20436414Ssklower 	IFDEBUG(D_INDICATION)
20537469Ssklower 		char *ls, *fs;
20636414Ssklower 		ls = tpcb->tp_lsuffix,
20736414Ssklower 		fs = tpcb->tp_fsuffix,
20836414Ssklower 
20936414Ssklower 		printf(
21037469Ssklower "indicate 0x%x lsuf 0x%02x%02x fsuf 0x%02x%02x err 0x%x  noind 0x%x ref 0x%x\n",
21136414Ssklower 		ind,
21236414Ssklower 		*ls, *(ls+1), *fs, *(fs+1),
21337469Ssklower 		error, /*so->so_pgrp,*/
21436414Ssklower 		tpcb->tp_no_disc_indications,
21536414Ssklower 		tpcb->tp_lref);
21636414Ssklower 	ENDDEBUG
21736414Ssklower 
21848744Ssklower 	if (ind == ER_TPDU) {
21948744Ssklower 		register struct mbuf *m;
22048744Ssklower 		struct tp_disc_reason x;
22148744Ssklower 
22248744Ssklower 		if ((so->so_state & SS_CANTRCVMORE) == 0 &&
22348744Ssklower 				(m = m_get(M_DONTWAIT, MT_OOBDATA)) != 0) {
22448744Ssklower 
22548744Ssklower 			x.dr_hdr.cmsg_len = m->m_len = sizeof(x);
22648744Ssklower 			x.dr_hdr.cmsg_level = SOL_TRANSPORT;
22748744Ssklower 			x.dr_hdr.cmsg_type= TPOPT_DISC_REASON;
22848744Ssklower 			x.dr_reason = error;
22948744Ssklower 			*mtod(m, struct tp_disc_reason *) = x;
23048744Ssklower 			sbappendrecord(&tpcb->tp_Xrcv, m);
23148744Ssklower 			error = 0;
23248744Ssklower 		} else
23348744Ssklower 			error = ECONNRESET;
23448744Ssklower 	}
23536414Ssklower 	so->so_error = error;
23636414Ssklower 
23736414Ssklower 	if (ind == T_DISCONNECT)  {
23848744Ssklower 		so->so_error = ENOTCONN;
23936414Ssklower 		if ( tpcb->tp_no_disc_indications )
24036414Ssklower 			return;
24136414Ssklower 	}
24236414Ssklower 	IFTRACE(D_INDICATION)
24336414Ssklower 		tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0);
24436414Ssklower 	ENDTRACE
24536414Ssklower 	sohasoutofband(so);
24636414Ssklower }
24736414Ssklower 
24836414Ssklower /*
24936414Ssklower  * NAME : tp_getoptions()
25036414Ssklower  *
25136414Ssklower  * CALLED FROM:
25236414Ssklower  * 	tp.trans whenever we go into OPEN state
25336414Ssklower  *
25436414Ssklower  * FUNCTION and ARGUMENTS:
25536414Ssklower  *  sets the proper flags and values in the tpcb, to control
25636414Ssklower  *  the appropriate actions for the given class, options,
25736414Ssklower  *  sequence space, etc, etc.
25836414Ssklower  *
25936414Ssklower  * RETURNS: Nada
26036414Ssklower  *
26136414Ssklower  * SIDE EFFECTS:
26236414Ssklower  *
26336414Ssklower  * NOTES:
26436414Ssklower  */
26536414Ssklower void
26636414Ssklower tp_getoptions(tpcb)
26736414Ssklower struct tp_pcb *tpcb;
26836414Ssklower {
26936414Ssklower 	tpcb->tp_seqmask =
27036414Ssklower 		tpcb->tp_xtd_format ?	TP_XTD_FMT_MASK :	TP_NML_FMT_MASK ;
27136414Ssklower 	tpcb->tp_seqbit =
27236414Ssklower 		tpcb->tp_xtd_format ?	TP_XTD_FMT_BIT :	TP_NML_FMT_BIT ;
27336414Ssklower 	tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
27436414Ssklower 	tpcb->tp_dt_ticks =
27536414Ssklower 		MAX(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2));
27636414Ssklower 
27736414Ssklower }
27836414Ssklower 
27936414Ssklower /*
28036414Ssklower  * NAME:  tp_recycle_tsuffix()
28136414Ssklower  *
28236414Ssklower  * CALLED FROM:
28336414Ssklower  *  Called when a ref is frozen.
28436414Ssklower  *
28536414Ssklower  * FUNCTION and ARGUMENTS:
28636414Ssklower  *  allows the suffix to be reused.
28736414Ssklower  *
28836414Ssklower  * RETURNS: zilch
28936414Ssklower  *
29036414Ssklower  * SIDE EFFECTS:
29136414Ssklower  *
29236414Ssklower  * NOTES:
29336414Ssklower  */
29436414Ssklower void
29536414Ssklower tp_recycle_tsuffix(tpcb)
29636414Ssklower 	struct tp_pcb	*tpcb;
29736414Ssklower {
29837469Ssklower 	bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix));
29937469Ssklower 	bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix));
30036414Ssklower 	tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0;
30136414Ssklower 
30236414Ssklower 	(tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb);
30336414Ssklower }
30436414Ssklower 
30536414Ssklower /*
30636414Ssklower  * NAME: tp_quench()
30736414Ssklower  *
30836414Ssklower  * CALLED FROM:
30936414Ssklower  *  tp{af}_quench() when ICMP source quench or similar thing arrives.
31036414Ssklower  *
31136414Ssklower  * FUNCTION and ARGUMENTS:
31236414Ssklower  *  Drop the congestion window back to 1.
31336414Ssklower  *  Congestion window scheme:
31436414Ssklower  *  Initial value is 1.  ("slow start" as Nagle, et. al. call it)
31536414Ssklower  *  For each good ack that arrives, the congestion window is increased
31636414Ssklower  *  by 1 (up to max size of logical infinity, which is to say,
31736414Ssklower  *	it doesn't wrap around).
31836414Ssklower  *  Source quench causes it to drop back to 1.
31936414Ssklower  *  tp_send() uses the smaller of (regular window, congestion window).
32036414Ssklower  *  One retransmission strategy option is to have any retransmission
32136414Ssklower  *	cause reset the congestion window back  to 1.
32236414Ssklower  *
32336414Ssklower  *	(cmd) is either PRC_QUENCH: source quench, or
32436414Ssklower  *		PRC_QUENCH2: dest. quench (dec bit)
32536414Ssklower  *
32636414Ssklower  * RETURNS:
32736414Ssklower  *
32836414Ssklower  * SIDE EFFECTS:
32936414Ssklower  *
33036414Ssklower  * NOTES:
33136414Ssklower  */
33236414Ssklower void
33336414Ssklower tp_quench( tpcb, cmd )
33436414Ssklower 	struct tp_pcb *tpcb;
33536414Ssklower 	int cmd;
33636414Ssklower {
33736414Ssklower 	IFDEBUG(D_QUENCH)
33836414Ssklower 		printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n",
33939197Ssklower 			tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix));
34036414Ssklower 		printf("cong_win 0x%x decbit 0x%x \n",
34136414Ssklower 			tpcb->tp_cong_win, tpcb->tp_decbit);
34236414Ssklower 	ENDDEBUG
34336414Ssklower 	switch(cmd) {
34436414Ssklower 		case PRC_QUENCH:
34536414Ssklower 			tpcb->tp_cong_win = 1;
34636414Ssklower 			IncStat(ts_quench);
34736414Ssklower 			break;
34836414Ssklower 		case PRC_QUENCH2:
34936414Ssklower 			tpcb->tp_cong_win = 1; /* might as well quench source also */
35036414Ssklower 			tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT;
35136414Ssklower 			IncStat(ts_rcvdecbit);
35236414Ssklower 			break;
35336414Ssklower 	}
35436414Ssklower }
35536414Ssklower 
35636414Ssklower 
35736414Ssklower /*
35836414Ssklower  * NAME:	tp_netcmd()
35936414Ssklower  *
36036414Ssklower  * CALLED FROM:
36136414Ssklower  *
36236414Ssklower  * FUNCTION and ARGUMENTS:
36336414Ssklower  *
36436414Ssklower  * RETURNS:
36536414Ssklower  *
36636414Ssklower  * SIDE EFFECTS:
36736414Ssklower  *
36836414Ssklower  * NOTES:
36936414Ssklower  */
37036414Ssklower tp_netcmd( tpcb, cmd )
37136414Ssklower 	struct tp_pcb *tpcb;
37236414Ssklower 	int cmd;
37336414Ssklower {
37445900Ssklower #ifdef TPCONS
37545900Ssklower 	struct isopcb *isop;
37645900Ssklower 	struct pklcd *lcp;
37745900Ssklower 
37845900Ssklower 	if (tpcb->tp_netservice != ISO_CONS)
37945900Ssklower 		return;
38045900Ssklower 	isop = (struct isopcb *)tpcb->tp_npcb;
38145900Ssklower 	lcp = (struct pklcd *)isop->isop_chan;
38236414Ssklower 	switch (cmd) {
38336414Ssklower 
38436414Ssklower 	case CONN_CLOSE:
38536414Ssklower 	case CONN_REFUSE:
386*50648Ssklower 		if (isop->isop_refcnt == 1) {
387*50648Ssklower 			/* This is really superfluous, since it would happen
388*50648Ssklower 			   anyway in iso_pcbdetach, although it is a courtesy
389*50648Ssklower 			   to free up the x.25 channel before the refwait timer
390*50648Ssklower 			   expires. */
391*50648Ssklower 			lcp->lcd_upper = 0;
392*50648Ssklower 			lcp->lcd_upnext = 0;
39345900Ssklower 			pk_disconnect(lcp);
394*50648Ssklower 			isop->isop_chan = 0;
395*50648Ssklower 			isop->isop_refcnt = 0;
396*50648Ssklower 		}
39736414Ssklower 		break;
39836414Ssklower 
39936414Ssklower 	default:
40036414Ssklower 		printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd);
40136414Ssklower 		break;
40236414Ssklower 	}
40345900Ssklower #else TPCONS
40436414Ssklower 	printf("tp_netcmd(): X25 NOT CONFIGURED!!\n");
40545900Ssklower #endif
40636414Ssklower }
40736414Ssklower /*
40836414Ssklower  * CALLED FROM:
40936414Ssklower  *  tp_ctloutput() and tp_emit()
41036414Ssklower  * FUNCTION and ARGUMENTS:
41136414Ssklower  * 	Convert a class mask to the highest numeric value it represents.
41236414Ssklower  */
41336414Ssklower 
41436414Ssklower int
41536414Ssklower tp_mask_to_num(x)
41636414Ssklower 	u_char x;
41736414Ssklower {
41836414Ssklower 	register int j;
41936414Ssklower 
42036414Ssklower 	for(j = 4; j>=0 ;j--) {
42136414Ssklower 		if(x & (1<<j))
42236414Ssklower 			break;
42336414Ssklower 	}
42436414Ssklower 	ASSERT( (j == 4) || (j == 0) ); /* for now */
42536414Ssklower 	if( (j != 4) && (j != 0) ) {
42636414Ssklower 		printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n",
42736414Ssklower 			x, j);
42836414Ssklower 	}
42936414Ssklower 	IFTRACE(D_TPINPUT)
43036414Ssklower 		tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0);
43136414Ssklower 	ENDTRACE
43236414Ssklower 	IFDEBUG(D_TPINPUT)
43336414Ssklower 		printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j);
43436414Ssklower 	ENDDEBUG
43536414Ssklower 	return j;
43636414Ssklower }
43736414Ssklower 
43836414Ssklower static
43936414Ssklower copyQOSparms(src, dst)
44036414Ssklower 	struct tp_conn_param *src, *dst;
44136414Ssklower {
44236414Ssklower 	/* copy all but the bits stuff at the end */
44336414Ssklower #define COPYSIZE (12 * sizeof(short))
44436414Ssklower 
44537469Ssklower 	bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE);
44636414Ssklower 	dst->p_tpdusize = src->p_tpdusize;
44736414Ssklower 	dst->p_ack_strat = src->p_ack_strat;
44836414Ssklower 	dst->p_rx_strat = src->p_rx_strat;
44936414Ssklower #undef COPYSIZE
45036414Ssklower }
45136414Ssklower 
45236414Ssklower /*
45336414Ssklower  * CALLED FROM:
45436414Ssklower  *  tp_usrreq on PRU_CONNECT and tp_input on receipt of CR
45536414Ssklower  *
45636414Ssklower  * FUNCTION and ARGUMENTS:
45736414Ssklower  * 	route directly to x.25 if the address is type 37 - GROT.
45836414Ssklower  *  furthermore, let TP0 handle only type-37 addresses
45936414Ssklower  *
46036414Ssklower  *	Since this assumes that its address argument is in a mbuf, the
46136414Ssklower  *	parameter was changed to reflect this assumtion. This also
46236414Ssklower  *	implies that an mbuf must be allocated when this is
46336414Ssklower  *	called from tp_input
46436414Ssklower  *
46536414Ssklower  * RETURNS:
46636414Ssklower  *	errno value	 :
46736414Ssklower  *	EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic)
46836414Ssklower  *	ECONNREFUSED if trying to run TP0 with non-type 37 address
46936414Ssklower  *  possibly other E* returned from cons_netcmd()
47036414Ssklower  * NOTE:
47136414Ssklower  *  Would like to eliminate as much of this as possible --
47236414Ssklower  *  only one set of defaults (let the user set the parms according
47336414Ssklower  *  to parameters provided in the directory service).
47436414Ssklower  *  Left here for now 'cause we don't yet have a clean way to handle
47536414Ssklower  *  it on the passive end.
47636414Ssklower  */
47736414Ssklower int
47836414Ssklower tp_route_to( m, tpcb, channel)
47936414Ssklower 	struct mbuf					*m;
48036414Ssklower 	register struct tp_pcb		*tpcb;
48145900Ssklower 	caddr_t 					channel;
48236414Ssklower {
48336414Ssklower 	register struct sockaddr_iso *siso;	/* NOTE: this may be a sockaddr_in */
48436414Ssklower 	extern struct tp_conn_param tp_conn_param[];
485*50648Ssklower 	int error = 0, save_netservice = tpcb->tp_netservice;
486*50648Ssklower 	register struct rtentry *rt = 0;
48736414Ssklower 
48836414Ssklower 	siso = mtod(m, struct sockaddr_iso *);
48936414Ssklower 	IFTRACE(D_CONN)
49036414Ssklower 		tptraceTPCB(TPPTmisc,
49136414Ssklower 		"route_to: so  afi netservice class",
49237469Ssklower 		tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice,
49336414Ssklower 			tpcb->tp_class);
49436414Ssklower 	ENDTRACE
49536414Ssklower 	IFDEBUG(D_CONN)
49636414Ssklower 		printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n",
49736414Ssklower 			m, channel, tpcb, tpcb->tp_netservice);
49836414Ssklower 		printf("m->mlen x%x, m->m_data:\n", m->m_len);
49936414Ssklower 		dump_buf(mtod(m, caddr_t), m->m_len);
50036414Ssklower 	ENDDEBUG
501*50648Ssklower 	if (channel) {
50245900Ssklower #ifdef TPCONS
503*50648Ssklower 		struct pklcd *lcp = (struct pklcd *)channel;
50445900Ssklower 		struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext,
50550435Ssklower 			*isop_new = (struct isopcb *)tpcb->tp_npcb;
506*50648Ssklower 		/* The next 2 lines believe that you haven't
507*50648Ssklower 		   set any network level options or done a pcbconnect
508*50648Ssklower 		   and XXXXXXX'edly apply to both inpcb's and isopcb's */
50945900Ssklower 		remque(isop_new);
51045900Ssklower 		free(isop_new, M_PCB);
51150435Ssklower 		tpcb->tp_npcb = (caddr_t)isop;
512*50648Ssklower 		tpcb->tp_netservice = ISO_CONS;
513*50648Ssklower 		tpcb->tp_nlproto = nl_protosw + ISO_CONS;
514*50648Ssklower 		isop->isop_socket = tpcb->tp_sock;
515*50648Ssklower 		if (isop->isop_refcnt == 0)
51645900Ssklower 			iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL);
517*50648Ssklower 		else
518*50648Ssklower 			/* there are already connections sharing this */;
51945900Ssklower 		isop->isop_refcnt++;
52045900Ssklower #endif
521*50648Ssklower 	} else {
522*50648Ssklower 		switch (siso->siso_family) {
523*50648Ssklower 		default:
524*50648Ssklower 			error = EAFNOSUPPORT;
525*50648Ssklower 			goto done;
526*50648Ssklower #ifdef ISO
527*50648Ssklower 		case AF_ISO:
528*50648Ssklower 			tpcb->tp_netservice = ISO_CLNS;
529*50648Ssklower 			if (rt = rtalloc1((struct sockaddr *)siso, 0)) {
530*50648Ssklower 				rt->rt_refcnt--;
531*50648Ssklower 				if (rt->rt_flags & RTF_PROTO1)
532*50648Ssklower 					tpcb->tp_netservice = ISO_CONS;
533*50648Ssklower 			}
534*50648Ssklower 			break;
535*50648Ssklower #endif
536*50648Ssklower #ifdef INET
537*50648Ssklower 		case AF_INET:
538*50648Ssklower 			tpcb->tp_netservice = IN_CLNS;
539*50648Ssklower 		}
540*50648Ssklower #endif
541*50648Ssklower 		if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) {
542*50648Ssklower 			IFDEBUG(D_CONN)
543*50648Ssklower 				printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n",
544*50648Ssklower 						save_netservice, tpcb->tp_netservice);
545*50648Ssklower 			ENDDEBUG
546*50648Ssklower 			if (error = tp_set_npcb(tpcb))
547*50648Ssklower 				goto done;
548*50648Ssklower 		}
549*50648Ssklower 		IFDEBUG(D_CONN)
550*50648Ssklower 			printf("tp_route_to  calling nlp_pcbconn, netserv %d\n",
551*50648Ssklower 				tpcb->tp_netservice);
552*50648Ssklower 		ENDDEBUG
553*50648Ssklower 		tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice;
55450435Ssklower 		error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m);
555*50648Ssklower 	}
55637469Ssklower 	if( error )
55737469Ssklower 		goto done;
55837469Ssklower 
55936414Ssklower 	{
56036414Ssklower 		switch(tpcb->tp_netservice) {
56136414Ssklower 		case ISO_COSNS:
56236414Ssklower 		case ISO_CLNS:
56336414Ssklower 			/* This is a kludge but seems necessary so the passive end
56436414Ssklower 			 * can get long enough timers. sigh.
56537469Ssklower 			if( siso->siso_addr.osinet_idi[1] == (u_char)IDI_OSINET )
56636414Ssklower 			 */
567*50648Ssklower 			if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_X25) {
56836414Ssklower 				if( tpcb->tp_dont_change_params == 0) {
56936414Ssklower 					copyQOSparms( &tp_conn_param[ISO_COSNS],
57036414Ssklower 							&tpcb->_tp_param);
57136414Ssklower 				}
57236414Ssklower 				tpcb->tp_flags |= TPF_NLQOS_PDN;
57336414Ssklower 			}
57436414Ssklower 			/* drop through to IN_CLNS*/
57536414Ssklower 		case IN_CLNS:
57637469Ssklower 			if (iso_localifa(siso))
57737469Ssklower 				tpcb->tp_flags |= TPF_PEER_ON_SAMENET;
578*50648Ssklower 			if((tpcb->tp_class & TP_CLASS_4) == 0) {
57936414Ssklower 				error = EPROTOTYPE;
58036414Ssklower 				break;
58136414Ssklower 			}
58236414Ssklower 			tpcb->tp_class = TP_CLASS_4;  /* IGNORE dont_change_parms */
58336414Ssklower 			break;
58436414Ssklower 
58536414Ssklower 		case ISO_CONS:
58645900Ssklower #ifdef TPCONS
58736414Ssklower 			tpcb->tp_flags |= TPF_NLQOS_PDN;
58836414Ssklower 			if( tpcb->tp_dont_change_params == 0 ) {
58936414Ssklower 				copyQOSparms( &tp_conn_param[ISO_CONS],
59036414Ssklower 							&tpcb->_tp_param);
59136414Ssklower 			}
59236414Ssklower 			/*
59336414Ssklower 			 * for use over x.25 really need a small receive window,
59436414Ssklower 			 * need to start slowly, need small max negotiable tpdu size,
59536414Ssklower 			 * and need to use the congestion window to the max
59636414Ssklower 			 * IGNORES tp_dont_change_params for these!
59736414Ssklower 			 */
59836414Ssklower 			if( tpcb->tp_sock->so_snd.sb_hiwat > 512 ) {
59936414Ssklower 				(void) soreserve(tpcb->tp_sock, 512, 512 );/* GAG */
60036414Ssklower 			}
60136414Ssklower 			tpcb->tp_rx_strat =  TPRX_USE_CW;
60236414Ssklower 
60336414Ssklower 			/* class 4 doesn't need to open a vc now - may use one already
60436414Ssklower 			 * opened or may open one only when it sends a pkt.
60536414Ssklower 			 */
60645900Ssklower #else TPCONS
60736414Ssklower 			error = ECONNREFUSED;
60845900Ssklower #endif TPCONS
60936414Ssklower 			break;
61036414Ssklower 		default:
61136414Ssklower 			error = EPROTOTYPE;
61236414Ssklower 		}
61336414Ssklower 
61436414Ssklower 	}
61545900Ssklower 	if (error) {
61636414Ssklower 		tp_netcmd( tpcb, CONN_CLOSE);
61736414Ssklower 		goto done;
61836414Ssklower 	}
61936414Ssklower 	{	/* start with the global rtt, rtv stats */
62036414Ssklower 		register int i =
62136414Ssklower 		   (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN);
62236414Ssklower 
62336414Ssklower 		tpcb->tp_rtt = tp_stat.ts_rtt[i];
62436414Ssklower 		tpcb->tp_rtv = tp_stat.ts_rtv[i];
62536414Ssklower 	}
62636414Ssklower done:
62736414Ssklower 	IFDEBUG(D_CONN)
62836414Ssklower 		printf("tp_route_to  returns 0x%x\n", error);
62936414Ssklower 	ENDDEBUG
63036414Ssklower 	IFTRACE(D_CONN)
63136414Ssklower 		tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error,
63236414Ssklower 			tpcb->tp_netservice, tpcb->tp_class, 0);
63336414Ssklower 	ENDTRACE
63436414Ssklower 	return error;
63536414Ssklower }
63636414Ssklower 
63747280Ssklower 
63847280Ssklower /* class zero version */
63947280Ssklower void
64047280Ssklower tp0_stash( tpcb, e )
64147280Ssklower 	register struct tp_pcb		*tpcb;
64247280Ssklower 	register struct tp_event	*e;
64347280Ssklower {
64447280Ssklower #ifndef lint
64547280Ssklower #define E e->ATTR(DT_TPDU)
64647280Ssklower #else lint
64747280Ssklower #define E e->ev_union.EV_DT_TPDU
64847280Ssklower #endif lint
64947280Ssklower 
65047280Ssklower 	register struct sockbuf *sb = &tpcb->tp_sock->so_rcv;
65147280Ssklower 	register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
65247280Ssklower 
65347280Ssklower 	IFPERF(tpcb)
65447280Ssklower 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
65547280Ssklower 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
65647280Ssklower 				E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
65747280Ssklower 	ENDPERF
65847280Ssklower 
65947280Ssklower 	IFDEBUG(D_STASH)
66047280Ssklower 		printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x",
66147280Ssklower 		E.e_seq, E.e_datalen, E.e_eot);
66247280Ssklower 	ENDDEBUG
66347280Ssklower 
66447280Ssklower 	IFTRACE(D_STASH)
66547280Ssklower 		tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
66647280Ssklower 		E.e_seq, E.e_datalen, E.e_eot, 0);
66747280Ssklower 	ENDTRACE
66847280Ssklower 
66947280Ssklower 	if ( E.e_eot ) {
67047280Ssklower 		register struct mbuf *n = E.e_data;
67147280Ssklower 		n->m_flags |= M_EOR;
67247280Ssklower 		n->m_act = MNULL; /* set on tp_input */
67347280Ssklower 	}
67447280Ssklower 	sbappend(sb, E.e_data);
67547280Ssklower 	IFDEBUG(D_STASH)
67647280Ssklower 		dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending");
67747280Ssklower 	ENDDEBUG
67847280Ssklower 	if (tpcb->tp_netservice != ISO_CONS)
67947280Ssklower 		printf("tp0_stash: tp running over something wierd\n");
68047280Ssklower 	else {
68147280Ssklower 		register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
68247280Ssklower 		pk_flowcontrol(lcp, sbspace(sb) <= 0, 1);
68347280Ssklower 	}
68447280Ssklower }
68547280Ssklower 
68647280Ssklower void
68747280Ssklower tp0_openflow(tpcb)
68847280Ssklower register struct tp_pcb *tpcb;
68947280Ssklower {
69047280Ssklower 	register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
69147280Ssklower 	if (tpcb->tp_netservice != ISO_CONS)
69247280Ssklower 		printf("tp0_openflow: tp running over something wierd\n");
69347280Ssklower 	else {
69447280Ssklower 		register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
69547280Ssklower 		if (lcp->lcd_rxrnr_condition)
69647280Ssklower 			pk_flowcontrol(lcp, 0, 0);
69747280Ssklower 	}
69847280Ssklower }
69947280Ssklower #ifndef TPCONS
70047280Ssklower static
70147280Ssklower pk_flowcontrol() {}
70247280Ssklower #endif
70347280Ssklower 
70436414Ssklower #ifdef TP_PERF_MEAS
70536414Ssklower /*
70636414Ssklower  * CALLED FROM:
70736414Ssklower  *  tp_ctloutput() when the user sets TPOPT_PERF_MEAS on
70836414Ssklower  *  and tp_newsocket() when a new connection is made from
70936414Ssklower  *  a listening socket with tp_perf_on == true.
71036414Ssklower  * FUNCTION and ARGUMENTS:
71136414Ssklower  *  (tpcb) is the usual; this procedure gets a clear cluster mbuf for
71236414Ssklower  *  a tp_pmeas structure, and makes tpcb->tp_p_meas point to it.
71336414Ssklower  * RETURN VALUE:
71436414Ssklower  *  ENOBUFS if it cannot get a cluster mbuf.
71536414Ssklower  */
71636414Ssklower 
71736414Ssklower int
71836414Ssklower tp_setup_perf(tpcb)
71936414Ssklower 	register struct tp_pcb *tpcb;
72036414Ssklower {
72136414Ssklower 	register struct mbuf *q;
72236414Ssklower 
72337469Ssklower 	if( tpcb->tp_p_meas == 0 ) {
72437469Ssklower 		MGET(q, M_WAITOK, MT_PCB);
72536414Ssklower 		if (q == 0)
72636414Ssklower 			return ENOBUFS;
72737469Ssklower 		MCLGET(q, M_WAITOK);
72837469Ssklower 		if ((q->m_flags & M_EXT) == 0) {
72937469Ssklower 			(void) m_free(q);
73036414Ssklower 			return ENOBUFS;
73136414Ssklower 		}
73237469Ssklower 		q->m_len = sizeof (struct tp_pmeas);
73337469Ssklower 		tpcb->tp_p_mbuf = q;
73437469Ssklower 		tpcb->tp_p_meas = mtod(q, struct tp_pmeas *);
73537469Ssklower 		bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) );
73637469Ssklower 		IFDEBUG(D_PERF_MEAS)
73737469Ssklower 			printf(
73837469Ssklower 			"tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n",
73937469Ssklower 				tpcb, tpcb->tp_sock, tpcb->tp_lref,
74037469Ssklower 				tpcb->tp_p_meas, tpcb->tp_perf_on);
74137469Ssklower 		ENDDEBUG
74237469Ssklower 		tpcb->tp_perf_on = 1;
74336414Ssklower 	}
74436414Ssklower 	return 0;
74536414Ssklower }
74636414Ssklower #endif TP_PERF_MEAS
74736414Ssklower 
74836414Ssklower #ifdef ARGO_DEBUG
74936414Ssklower dump_addr (addr)
75036414Ssklower 	register struct sockaddr *addr;
75136414Ssklower {
75236414Ssklower 	switch( addr->sa_family ) {
75336414Ssklower 		case AF_INET:
75437469Ssklower 			dump_inaddr((struct sockaddr_in *)addr);
75536414Ssklower 			break;
75637469Ssklower #ifdef ISO
75736414Ssklower 		case AF_ISO:
75837469Ssklower 			dump_isoaddr((struct sockaddr_iso *)addr);
75936414Ssklower 			break;
76037469Ssklower #endif ISO
76136414Ssklower 		default:
76236414Ssklower 			printf("BAD AF: 0x%x\n", addr->sa_family);
76336414Ssklower 			break;
76436414Ssklower 	}
76536414Ssklower }
76636414Ssklower 
76737469Ssklower #define	MAX_COLUMNS	8
76837469Ssklower /*
76937469Ssklower  *	Dump the buffer to the screen in a readable format. Format is:
77037469Ssklower  *
77137469Ssklower  *		hex/dec  where hex is the hex format, dec is the decimal format.
77237469Ssklower  *		columns of hex/dec numbers will be printed, followed by the
77337469Ssklower  *		character representations (if printable).
77437469Ssklower  */
77537469Ssklower Dump_buf(buf, len)
77637469Ssklower caddr_t	buf;
77737469Ssklower int		len;
77837469Ssklower {
77937469Ssklower 	int		i,j;
78050236Ssklower #define Buf ((u_char *)buf)
78137469Ssklower 	printf("Dump buf 0x%x len 0x%x\n", buf, len);
78237469Ssklower 	for (i = 0; i < len; i += MAX_COLUMNS) {
78337469Ssklower 		printf("+%d:\t", i);
78437469Ssklower 		for (j = 0; j < MAX_COLUMNS; j++) {
78537469Ssklower 			if (i + j < len) {
78650236Ssklower 				printf("%x/%d\t", Buf[i+j], Buf[i+j]);
78737469Ssklower 			} else {
78837469Ssklower 				printf("	");
78937469Ssklower 			}
79037469Ssklower 		}
79137469Ssklower 
79237469Ssklower 		for (j = 0; j < MAX_COLUMNS; j++) {
79337469Ssklower 			if (i + j < len) {
79450236Ssklower 				if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128))
79550236Ssklower 					printf("%c", Buf[i+j]);
79637469Ssklower 				else
79737469Ssklower 					printf(".");
79837469Ssklower 			}
79937469Ssklower 		}
80037469Ssklower 		printf("\n");
80137469Ssklower 	}
80237469Ssklower }
80337469Ssklower 
80437469Ssklower 
80536414Ssklower #endif ARGO_DEBUG
80636414Ssklower 
807