xref: /csrg-svn/sys/netiso/tp_subr2.c (revision 51258)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51258Ssklower  *	@(#)tp_subr2.c	7.17 (Berkeley) 10/02/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"
8350648Ssklower #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",
11951213Ssklower 			tpcb->tp_lref,
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)  {
23851209Ssklower 		if (error == 0)
23951209Ssklower 			so->so_error = ENOTCONN;
24036414Ssklower 		if ( tpcb->tp_no_disc_indications )
24136414Ssklower 			return;
24236414Ssklower 	}
24336414Ssklower 	IFTRACE(D_INDICATION)
24436414Ssklower 		tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0);
24536414Ssklower 	ENDTRACE
24636414Ssklower 	sohasoutofband(so);
24736414Ssklower }
24836414Ssklower 
24936414Ssklower /*
25036414Ssklower  * NAME : tp_getoptions()
25136414Ssklower  *
25236414Ssklower  * CALLED FROM:
25336414Ssklower  * 	tp.trans whenever we go into OPEN state
25436414Ssklower  *
25536414Ssklower  * FUNCTION and ARGUMENTS:
25636414Ssklower  *  sets the proper flags and values in the tpcb, to control
25736414Ssklower  *  the appropriate actions for the given class, options,
25836414Ssklower  *  sequence space, etc, etc.
25936414Ssklower  *
26036414Ssklower  * RETURNS: Nada
26136414Ssklower  *
26236414Ssklower  * SIDE EFFECTS:
26336414Ssklower  *
26436414Ssklower  * NOTES:
26536414Ssklower  */
26636414Ssklower void
26736414Ssklower tp_getoptions(tpcb)
26836414Ssklower struct tp_pcb *tpcb;
26936414Ssklower {
27036414Ssklower 	tpcb->tp_seqmask =
27136414Ssklower 		tpcb->tp_xtd_format ?	TP_XTD_FMT_MASK :	TP_NML_FMT_MASK ;
27236414Ssklower 	tpcb->tp_seqbit =
27336414Ssklower 		tpcb->tp_xtd_format ?	TP_XTD_FMT_BIT :	TP_NML_FMT_BIT ;
27436414Ssklower 	tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
27536414Ssklower 	tpcb->tp_dt_ticks =
27636414Ssklower 		MAX(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2));
27750975Ssklower 	(void) tp_rsyset(tpcb);
27850975Ssklower 
27936414Ssklower }
28036414Ssklower 
28136414Ssklower /*
28236414Ssklower  * NAME:  tp_recycle_tsuffix()
28336414Ssklower  *
28436414Ssklower  * CALLED FROM:
28536414Ssklower  *  Called when a ref is frozen.
28636414Ssklower  *
28736414Ssklower  * FUNCTION and ARGUMENTS:
28836414Ssklower  *  allows the suffix to be reused.
28936414Ssklower  *
29036414Ssklower  * RETURNS: zilch
29136414Ssklower  *
29236414Ssklower  * SIDE EFFECTS:
29336414Ssklower  *
29436414Ssklower  * NOTES:
29536414Ssklower  */
29636414Ssklower void
29736414Ssklower tp_recycle_tsuffix(tpcb)
29836414Ssklower 	struct tp_pcb	*tpcb;
29936414Ssklower {
30037469Ssklower 	bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix));
30137469Ssklower 	bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix));
30236414Ssklower 	tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0;
30336414Ssklower 
30436414Ssklower 	(tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb);
30536414Ssklower }
30636414Ssklower 
30736414Ssklower /*
30836414Ssklower  * NAME: tp_quench()
30936414Ssklower  *
31036414Ssklower  * CALLED FROM:
31136414Ssklower  *  tp{af}_quench() when ICMP source quench or similar thing arrives.
31236414Ssklower  *
31336414Ssklower  * FUNCTION and ARGUMENTS:
31436414Ssklower  *  Drop the congestion window back to 1.
31536414Ssklower  *  Congestion window scheme:
31636414Ssklower  *  Initial value is 1.  ("slow start" as Nagle, et. al. call it)
31736414Ssklower  *  For each good ack that arrives, the congestion window is increased
31836414Ssklower  *  by 1 (up to max size of logical infinity, which is to say,
31936414Ssklower  *	it doesn't wrap around).
32036414Ssklower  *  Source quench causes it to drop back to 1.
32136414Ssklower  *  tp_send() uses the smaller of (regular window, congestion window).
32236414Ssklower  *  One retransmission strategy option is to have any retransmission
32336414Ssklower  *	cause reset the congestion window back  to 1.
32436414Ssklower  *
32536414Ssklower  *	(cmd) is either PRC_QUENCH: source quench, or
32636414Ssklower  *		PRC_QUENCH2: dest. quench (dec bit)
32736414Ssklower  *
32836414Ssklower  * RETURNS:
32936414Ssklower  *
33036414Ssklower  * SIDE EFFECTS:
33136414Ssklower  *
33236414Ssklower  * NOTES:
33336414Ssklower  */
33436414Ssklower void
33536414Ssklower tp_quench( tpcb, cmd )
33636414Ssklower 	struct tp_pcb *tpcb;
33736414Ssklower 	int cmd;
33836414Ssklower {
33936414Ssklower 	IFDEBUG(D_QUENCH)
34036414Ssklower 		printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n",
34139197Ssklower 			tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix));
34236414Ssklower 		printf("cong_win 0x%x decbit 0x%x \n",
34336414Ssklower 			tpcb->tp_cong_win, tpcb->tp_decbit);
34436414Ssklower 	ENDDEBUG
34536414Ssklower 	switch(cmd) {
34636414Ssklower 		case PRC_QUENCH:
34751204Ssklower 			tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
34836414Ssklower 			IncStat(ts_quench);
34936414Ssklower 			break;
35036414Ssklower 		case PRC_QUENCH2:
35151204Ssklower 			tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* might as well quench source also */
35236414Ssklower 			tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT;
35336414Ssklower 			IncStat(ts_rcvdecbit);
35436414Ssklower 			break;
35536414Ssklower 	}
35636414Ssklower }
35736414Ssklower 
35836414Ssklower 
35936414Ssklower /*
36036414Ssklower  * NAME:	tp_netcmd()
36136414Ssklower  *
36236414Ssklower  * CALLED FROM:
36336414Ssklower  *
36436414Ssklower  * FUNCTION and ARGUMENTS:
36536414Ssklower  *
36636414Ssklower  * RETURNS:
36736414Ssklower  *
36836414Ssklower  * SIDE EFFECTS:
36936414Ssklower  *
37036414Ssklower  * NOTES:
37136414Ssklower  */
37236414Ssklower tp_netcmd( tpcb, cmd )
37336414Ssklower 	struct tp_pcb *tpcb;
37436414Ssklower 	int cmd;
37536414Ssklower {
37645900Ssklower #ifdef TPCONS
37745900Ssklower 	struct isopcb *isop;
37845900Ssklower 	struct pklcd *lcp;
37945900Ssklower 
38045900Ssklower 	if (tpcb->tp_netservice != ISO_CONS)
38145900Ssklower 		return;
38245900Ssklower 	isop = (struct isopcb *)tpcb->tp_npcb;
38345900Ssklower 	lcp = (struct pklcd *)isop->isop_chan;
38436414Ssklower 	switch (cmd) {
38536414Ssklower 
38636414Ssklower 	case CONN_CLOSE:
38736414Ssklower 	case CONN_REFUSE:
38850648Ssklower 		if (isop->isop_refcnt == 1) {
38950648Ssklower 			/* This is really superfluous, since it would happen
39050648Ssklower 			   anyway in iso_pcbdetach, although it is a courtesy
39150648Ssklower 			   to free up the x.25 channel before the refwait timer
39250648Ssklower 			   expires. */
39350648Ssklower 			lcp->lcd_upper = 0;
39450648Ssklower 			lcp->lcd_upnext = 0;
39545900Ssklower 			pk_disconnect(lcp);
39650648Ssklower 			isop->isop_chan = 0;
39750648Ssklower 			isop->isop_refcnt = 0;
39850648Ssklower 		}
39936414Ssklower 		break;
40036414Ssklower 
40136414Ssklower 	default:
40236414Ssklower 		printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd);
40336414Ssklower 		break;
40436414Ssklower 	}
40545900Ssklower #else TPCONS
40636414Ssklower 	printf("tp_netcmd(): X25 NOT CONFIGURED!!\n");
40745900Ssklower #endif
40836414Ssklower }
40936414Ssklower /*
41036414Ssklower  * CALLED FROM:
41136414Ssklower  *  tp_ctloutput() and tp_emit()
41236414Ssklower  * FUNCTION and ARGUMENTS:
41336414Ssklower  * 	Convert a class mask to the highest numeric value it represents.
41436414Ssklower  */
41536414Ssklower 
41636414Ssklower int
41736414Ssklower tp_mask_to_num(x)
41836414Ssklower 	u_char x;
41936414Ssklower {
42036414Ssklower 	register int j;
42136414Ssklower 
42236414Ssklower 	for(j = 4; j>=0 ;j--) {
42336414Ssklower 		if(x & (1<<j))
42436414Ssklower 			break;
42536414Ssklower 	}
42636414Ssklower 	ASSERT( (j == 4) || (j == 0) ); /* for now */
42736414Ssklower 	if( (j != 4) && (j != 0) ) {
42836414Ssklower 		printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n",
42936414Ssklower 			x, j);
43036414Ssklower 	}
43136414Ssklower 	IFTRACE(D_TPINPUT)
43236414Ssklower 		tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0);
43336414Ssklower 	ENDTRACE
43436414Ssklower 	IFDEBUG(D_TPINPUT)
43536414Ssklower 		printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j);
43636414Ssklower 	ENDDEBUG
43736414Ssklower 	return j;
43836414Ssklower }
43936414Ssklower 
44036414Ssklower static
44136414Ssklower copyQOSparms(src, dst)
44236414Ssklower 	struct tp_conn_param *src, *dst;
44336414Ssklower {
44436414Ssklower 	/* copy all but the bits stuff at the end */
44536414Ssklower #define COPYSIZE (12 * sizeof(short))
44636414Ssklower 
44737469Ssklower 	bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE);
44836414Ssklower 	dst->p_tpdusize = src->p_tpdusize;
44936414Ssklower 	dst->p_ack_strat = src->p_ack_strat;
45036414Ssklower 	dst->p_rx_strat = src->p_rx_strat;
45136414Ssklower #undef COPYSIZE
45236414Ssklower }
453*51258Ssklower /*
454*51258Ssklower  * Determine a reasonable value for maxseg size.
455*51258Ssklower  * If the route is known, check route for mtu.
456*51258Ssklower  * We also initialize the congestion/slow start
457*51258Ssklower  * window to be a single segment if the destination isn't local.
458*51258Ssklower  * While looking at the routing entry, we also initialize other path-dependent
459*51258Ssklower  * parameters from pre-set or cached values in the routing entry.
460*51258Ssklower  */
461*51258Ssklower void
462*51258Ssklower tp_mss(tpcb, nhdr_size)
463*51258Ssklower 	register struct tp_pcb *tpcb;
464*51258Ssklower 	int nhdr_size;
465*51258Ssklower {
466*51258Ssklower 	register struct rtentry *rt;
467*51258Ssklower 	struct ifnet *ifp;
468*51258Ssklower 	register int rtt, mss;
469*51258Ssklower 	u_long bufsize;
470*51258Ssklower 	int i, ssthresh = 0;
471*51258Ssklower 	struct socket *so;
47236414Ssklower 
473*51258Ssklower 	mss = 1 << tpcb->tp_tpdusize;
474*51258Ssklower 	so = tpcb->tp_sock;
475*51258Ssklower 	if ((rt = *(tpcb->tp_routep)) == 0) {
476*51258Ssklower 		bufsize = so->so_rcv.sb_hiwat;
477*51258Ssklower 		goto punt_route;
478*51258Ssklower 	}
479*51258Ssklower 	ifp = rt->rt_ifp;
480*51258Ssklower 
481*51258Ssklower #ifdef RTV_MTU	/* if route characteristics exist ... */
482*51258Ssklower 	/*
483*51258Ssklower 	 * While we're here, check if there's an initial rtt
484*51258Ssklower 	 * or rttvar.  Convert from the route-table units
485*51258Ssklower 	 * to hz ticks for the smoothed timers and slow-timeout units
486*51258Ssklower 	 * for other inital variables.
487*51258Ssklower 	 */
488*51258Ssklower 	if (tpcb->tp_rtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) {
489*51258Ssklower 		tpcb->tp_rtt = rtt * hz / RTM_RTTUNIT;
490*51258Ssklower 		if (rt->rt_rmx.rmx_rttvar)
491*51258Ssklower 			tpcb->tp_rtv = rt->rt_rmx.rmx_rttvar
492*51258Ssklower 						* hz / RTM_RTTUNIT;
493*51258Ssklower 		else
494*51258Ssklower 			tpcb->tp_rtv = tpcb->tp_rtt;
495*51258Ssklower 	}
496*51258Ssklower 	/*
497*51258Ssklower 	 * if there's an mtu associated with the route, use it
498*51258Ssklower 	 */
499*51258Ssklower 	if (rt->rt_rmx.rmx_mtu)
500*51258Ssklower 		mss = rt->rt_rmx.rmx_mtu - nhdr_size;
501*51258Ssklower 	else
502*51258Ssklower #endif /* RTV_MTU */
503*51258Ssklower 		mss = (ifp->if_mtu - nhdr_size);
504*51258Ssklower 	/* can propose mtu which are multiples of 128 */
505*51258Ssklower 	mss &= ~0x7f;
506*51258Ssklower 	/*
507*51258Ssklower 	 * If there's a pipesize, change the socket buffer
508*51258Ssklower 	 * to that size.
509*51258Ssklower 	 */
510*51258Ssklower #ifdef RTV_SPIPE
511*51258Ssklower 	if ((bufsize = rt->rt_rmx.rmx_sendpipe) > 0) {
512*51258Ssklower #endif
513*51258Ssklower 		bufsize = min(bufsize, so->so_snd.sb_hiwat);
514*51258Ssklower 		(void) sbreserve(&so->so_snd, bufsize);
515*51258Ssklower 	}
516*51258Ssklower #ifdef RTV_SPIPE
517*51258Ssklower 	if ((bufsize = rt->rt_rmx.rmx_recvpipe) > 0) {
518*51258Ssklower #endif
519*51258Ssklower 		bufsize = min(bufsize, so->so_rcv.sb_hiwat);
520*51258Ssklower 		(void) sbreserve(&so->so_rcv, bufsize);
521*51258Ssklower 	} else
522*51258Ssklower 		bufsize = so->so_rcv.sb_hiwat;
523*51258Ssklower #ifdef RTV_SSTHRESH
524*51258Ssklower 	/*
525*51258Ssklower 	 * There's some sort of gateway or interface
526*51258Ssklower 	 * buffer limit on the path.  Use this to set
527*51258Ssklower 	 * the slow start threshhold, but set the
528*51258Ssklower 	 * threshold to no less than 2*mss.
529*51258Ssklower 	 */
530*51258Ssklower 	ssthresh = rt->rt_rmx.rmx_ssthresh;
531*51258Ssklower punt_route:
532*51258Ssklower 	/*
533*51258Ssklower 	 * The current mss is initialized to the default value.
534*51258Ssklower 	 * If we compute a smaller value, reduce the current mss.
535*51258Ssklower 	 * If we compute a larger value, return it for use in sending
536*51258Ssklower 	 * a max seg size option.
537*51258Ssklower 	 * If we received an offer, don't exceed it.
538*51258Ssklower 	 * However, do not accept offers under 128 bytes.
539*51258Ssklower 	 */
540*51258Ssklower 	if (tpcb->tp_l_tpdusize)
541*51258Ssklower 		mss = min(mss, tpcb->tp_l_tpdusize);
542*51258Ssklower 	/*
543*51258Ssklower 	 * We want a minimum recv window of 4 packets to
544*51258Ssklower 	 * signal packet loss by duplicate acks.
545*51258Ssklower 	 */
546*51258Ssklower 	mss = min(mss, bufsize >> 2) & ~0x7f;
547*51258Ssklower 	mss = max(mss, 128);		/* sanity */
548*51258Ssklower 	tpcb->tp_cong_win =
549*51258Ssklower 		(rt == 0 || (rt->rt_flags & RTF_GATEWAY)) ? mss : bufsize;
550*51258Ssklower 	tpcb->tp_l_tpdusize = mss;
551*51258Ssklower 	tpcb->tp_ssthresh = max(2 * mss, ssthresh);
552*51258Ssklower 	/* Calculate log2 of mss */
553*51258Ssklower 	for (i = TP_MIN_TPDUSIZE + 1; i <= TP_MAX_TPDUSIZE; i++)
554*51258Ssklower 		if ((1 << i) > mss)
555*51258Ssklower 			break;
556*51258Ssklower 	i--;
557*51258Ssklower 	tpcb->tp_tpdusize = i;
558*51258Ssklower #endif /* RTV_MTU */
559*51258Ssklower }
560*51258Ssklower 
56136414Ssklower /*
56236414Ssklower  * CALLED FROM:
56336414Ssklower  *  tp_usrreq on PRU_CONNECT and tp_input on receipt of CR
56436414Ssklower  *
56536414Ssklower  * FUNCTION and ARGUMENTS:
566*51258Ssklower  * 	-- An mbuf containing the peer's network address.
567*51258Ssklower  *  -- Our control block, which will be modified
568*51258Ssklower  *  -- In the case of cons, a control block for that layer.
56936414Ssklower  *
57036414Ssklower  *
57136414Ssklower  * RETURNS:
57236414Ssklower  *	errno value	 :
57336414Ssklower  *	EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic)
57436414Ssklower  *	ECONNREFUSED if trying to run TP0 with non-type 37 address
57536414Ssklower  *  possibly other E* returned from cons_netcmd()
576*51258Ssklower  *
577*51258Ssklower  * SIDE EFFECTS:
578*51258Ssklower  *   Determines recommended tpdusize, buffering and intial delays
579*51258Ssklower  *	 based on information cached on the route.
58036414Ssklower  */
58136414Ssklower int
58236414Ssklower tp_route_to( m, tpcb, channel)
58336414Ssklower 	struct mbuf					*m;
58436414Ssklower 	register struct tp_pcb		*tpcb;
58545900Ssklower 	caddr_t 					channel;
58636414Ssklower {
58736414Ssklower 	register struct sockaddr_iso *siso;	/* NOTE: this may be a sockaddr_in */
58836414Ssklower 	extern struct tp_conn_param tp_conn_param[];
58950648Ssklower 	int error = 0, save_netservice = tpcb->tp_netservice;
59050648Ssklower 	register struct rtentry *rt = 0;
591*51258Ssklower 	int nhdr_size, mtu, bufsize;
59236414Ssklower 
59336414Ssklower 	siso = mtod(m, struct sockaddr_iso *);
59436414Ssklower 	IFTRACE(D_CONN)
59536414Ssklower 		tptraceTPCB(TPPTmisc,
59636414Ssklower 		"route_to: so  afi netservice class",
59737469Ssklower 		tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice,
59836414Ssklower 			tpcb->tp_class);
59936414Ssklower 	ENDTRACE
60036414Ssklower 	IFDEBUG(D_CONN)
60136414Ssklower 		printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n",
60236414Ssklower 			m, channel, tpcb, tpcb->tp_netservice);
60336414Ssklower 		printf("m->mlen x%x, m->m_data:\n", m->m_len);
60436414Ssklower 		dump_buf(mtod(m, caddr_t), m->m_len);
60536414Ssklower 	ENDDEBUG
60650648Ssklower 	if (channel) {
60745900Ssklower #ifdef TPCONS
60850648Ssklower 		struct pklcd *lcp = (struct pklcd *)channel;
60945900Ssklower 		struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext,
61050435Ssklower 			*isop_new = (struct isopcb *)tpcb->tp_npcb;
61150648Ssklower 		/* The next 2 lines believe that you haven't
61250648Ssklower 		   set any network level options or done a pcbconnect
61350648Ssklower 		   and XXXXXXX'edly apply to both inpcb's and isopcb's */
61445900Ssklower 		remque(isop_new);
61545900Ssklower 		free(isop_new, M_PCB);
61650435Ssklower 		tpcb->tp_npcb = (caddr_t)isop;
61750648Ssklower 		tpcb->tp_netservice = ISO_CONS;
61850648Ssklower 		tpcb->tp_nlproto = nl_protosw + ISO_CONS;
619*51258Ssklower 		if (isop->isop_refcnt++ == 0) {
62045900Ssklower 			iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL);
621*51258Ssklower 			isop->isop_socket = tpcb->tp_sock;
622*51258Ssklower 		} else
62350648Ssklower 			/* there are already connections sharing this */;
62445900Ssklower #endif
62550648Ssklower 	} else {
62650648Ssklower 		switch (siso->siso_family) {
62750648Ssklower 		default:
62850648Ssklower 			error = EAFNOSUPPORT;
62950648Ssklower 			goto done;
63050648Ssklower #ifdef ISO
63150648Ssklower 		case AF_ISO:
632*51258Ssklower 		{
633*51258Ssklower 			struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
634*51258Ssklower 			int flags = tpcb->tp_sock->so_options & SO_DONTROUTE;
63550648Ssklower 			tpcb->tp_netservice = ISO_CLNS;
636*51258Ssklower 			if (clnp_route(&siso->siso_addr, &isop->isop_route,
637*51258Ssklower 							flags, (void **)0, (void **)0) == 0) {
638*51258Ssklower 				rt = isop->isop_route.ro_rt;
639*51258Ssklower 				if (rt && rt->rt_flags & RTF_PROTO1)
64050648Ssklower 					tpcb->tp_netservice = ISO_CONS;
64150648Ssklower 			}
642*51258Ssklower 		}    break;
64350648Ssklower #endif
64450648Ssklower #ifdef INET
64550648Ssklower 		case AF_INET:
64650648Ssklower 			tpcb->tp_netservice = IN_CLNS;
647*51258Ssklower #endif
64850648Ssklower 		}
64950648Ssklower 		if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) {
65050648Ssklower 			IFDEBUG(D_CONN)
65150648Ssklower 				printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n",
65250648Ssklower 						save_netservice, tpcb->tp_netservice);
65350648Ssklower 			ENDDEBUG
65450648Ssklower 			if (error = tp_set_npcb(tpcb))
65550648Ssklower 				goto done;
65650648Ssklower 		}
65750648Ssklower 		IFDEBUG(D_CONN)
65850648Ssklower 			printf("tp_route_to  calling nlp_pcbconn, netserv %d\n",
65950648Ssklower 				tpcb->tp_netservice);
66050648Ssklower 		ENDDEBUG
66150648Ssklower 		tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice;
66250435Ssklower 		error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m);
66350648Ssklower 	}
664*51258Ssklower 	if (error)
66537469Ssklower 		goto done;
666*51258Ssklower 	nhdr_size = tpcb->tp_nlproto->nlp_mtu(tpcb); /* only gets common info */
667*51258Ssklower 	tp_mss(tpcb, nhdr_size);
66836414Ssklower done:
66936414Ssklower 	IFDEBUG(D_CONN)
67036414Ssklower 		printf("tp_route_to  returns 0x%x\n", error);
67136414Ssklower 	ENDDEBUG
67236414Ssklower 	IFTRACE(D_CONN)
67336414Ssklower 		tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error,
67436414Ssklower 			tpcb->tp_netservice, tpcb->tp_class, 0);
67536414Ssklower 	ENDTRACE
67636414Ssklower 	return error;
67736414Ssklower }
67836414Ssklower 
67947280Ssklower 
68047280Ssklower /* class zero version */
68147280Ssklower void
68247280Ssklower tp0_stash( tpcb, e )
68347280Ssklower 	register struct tp_pcb		*tpcb;
68447280Ssklower 	register struct tp_event	*e;
68547280Ssklower {
68647280Ssklower #ifndef lint
68747280Ssklower #define E e->ATTR(DT_TPDU)
68847280Ssklower #else lint
68947280Ssklower #define E e->ev_union.EV_DT_TPDU
69047280Ssklower #endif lint
69147280Ssklower 
69247280Ssklower 	register struct sockbuf *sb = &tpcb->tp_sock->so_rcv;
69347280Ssklower 	register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
69447280Ssklower 
69547280Ssklower 	IFPERF(tpcb)
69647280Ssklower 		PStat(tpcb, Nb_from_ll) += E.e_datalen;
69747280Ssklower 		tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
69847280Ssklower 				E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
69947280Ssklower 	ENDPERF
70047280Ssklower 
70147280Ssklower 	IFDEBUG(D_STASH)
70247280Ssklower 		printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x",
70347280Ssklower 		E.e_seq, E.e_datalen, E.e_eot);
70447280Ssklower 	ENDDEBUG
70547280Ssklower 
70647280Ssklower 	IFTRACE(D_STASH)
70747280Ssklower 		tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
70847280Ssklower 		E.e_seq, E.e_datalen, E.e_eot, 0);
70947280Ssklower 	ENDTRACE
71047280Ssklower 
71147280Ssklower 	if ( E.e_eot ) {
71247280Ssklower 		register struct mbuf *n = E.e_data;
71347280Ssklower 		n->m_flags |= M_EOR;
71447280Ssklower 		n->m_act = MNULL; /* set on tp_input */
71547280Ssklower 	}
71647280Ssklower 	sbappend(sb, E.e_data);
71747280Ssklower 	IFDEBUG(D_STASH)
71847280Ssklower 		dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending");
71947280Ssklower 	ENDDEBUG
72047280Ssklower 	if (tpcb->tp_netservice != ISO_CONS)
72147280Ssklower 		printf("tp0_stash: tp running over something wierd\n");
72247280Ssklower 	else {
72347280Ssklower 		register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
72447280Ssklower 		pk_flowcontrol(lcp, sbspace(sb) <= 0, 1);
72547280Ssklower 	}
72647280Ssklower }
72747280Ssklower 
72847280Ssklower void
72947280Ssklower tp0_openflow(tpcb)
73047280Ssklower register struct tp_pcb *tpcb;
73147280Ssklower {
73247280Ssklower 	register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
73347280Ssklower 	if (tpcb->tp_netservice != ISO_CONS)
73447280Ssklower 		printf("tp0_openflow: tp running over something wierd\n");
73547280Ssklower 	else {
73647280Ssklower 		register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
73747280Ssklower 		if (lcp->lcd_rxrnr_condition)
73847280Ssklower 			pk_flowcontrol(lcp, 0, 0);
73947280Ssklower 	}
74047280Ssklower }
74147280Ssklower #ifndef TPCONS
74247280Ssklower static
74347280Ssklower pk_flowcontrol() {}
74447280Ssklower #endif
74547280Ssklower 
74636414Ssklower #ifdef TP_PERF_MEAS
74736414Ssklower /*
74836414Ssklower  * CALLED FROM:
74936414Ssklower  *  tp_ctloutput() when the user sets TPOPT_PERF_MEAS on
75036414Ssklower  *  and tp_newsocket() when a new connection is made from
75136414Ssklower  *  a listening socket with tp_perf_on == true.
75236414Ssklower  * FUNCTION and ARGUMENTS:
75336414Ssklower  *  (tpcb) is the usual; this procedure gets a clear cluster mbuf for
75436414Ssklower  *  a tp_pmeas structure, and makes tpcb->tp_p_meas point to it.
75536414Ssklower  * RETURN VALUE:
75636414Ssklower  *  ENOBUFS if it cannot get a cluster mbuf.
75736414Ssklower  */
75836414Ssklower 
75936414Ssklower int
76036414Ssklower tp_setup_perf(tpcb)
76136414Ssklower 	register struct tp_pcb *tpcb;
76236414Ssklower {
76336414Ssklower 	register struct mbuf *q;
76436414Ssklower 
76537469Ssklower 	if( tpcb->tp_p_meas == 0 ) {
76637469Ssklower 		MGET(q, M_WAITOK, MT_PCB);
76736414Ssklower 		if (q == 0)
76836414Ssklower 			return ENOBUFS;
76937469Ssklower 		MCLGET(q, M_WAITOK);
77037469Ssklower 		if ((q->m_flags & M_EXT) == 0) {
77137469Ssklower 			(void) m_free(q);
77236414Ssklower 			return ENOBUFS;
77336414Ssklower 		}
77437469Ssklower 		q->m_len = sizeof (struct tp_pmeas);
77537469Ssklower 		tpcb->tp_p_mbuf = q;
77637469Ssklower 		tpcb->tp_p_meas = mtod(q, struct tp_pmeas *);
77737469Ssklower 		bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) );
77837469Ssklower 		IFDEBUG(D_PERF_MEAS)
77937469Ssklower 			printf(
78037469Ssklower 			"tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n",
78137469Ssklower 				tpcb, tpcb->tp_sock, tpcb->tp_lref,
78237469Ssklower 				tpcb->tp_p_meas, tpcb->tp_perf_on);
78337469Ssklower 		ENDDEBUG
78437469Ssklower 		tpcb->tp_perf_on = 1;
78536414Ssklower 	}
78636414Ssklower 	return 0;
78736414Ssklower }
78836414Ssklower #endif TP_PERF_MEAS
78936414Ssklower 
79036414Ssklower #ifdef ARGO_DEBUG
79136414Ssklower dump_addr (addr)
79236414Ssklower 	register struct sockaddr *addr;
79336414Ssklower {
79436414Ssklower 	switch( addr->sa_family ) {
79536414Ssklower 		case AF_INET:
79637469Ssklower 			dump_inaddr((struct sockaddr_in *)addr);
79736414Ssklower 			break;
79837469Ssklower #ifdef ISO
79936414Ssklower 		case AF_ISO:
80037469Ssklower 			dump_isoaddr((struct sockaddr_iso *)addr);
80136414Ssklower 			break;
80237469Ssklower #endif ISO
80336414Ssklower 		default:
80436414Ssklower 			printf("BAD AF: 0x%x\n", addr->sa_family);
80536414Ssklower 			break;
80636414Ssklower 	}
80736414Ssklower }
80836414Ssklower 
80937469Ssklower #define	MAX_COLUMNS	8
81037469Ssklower /*
81137469Ssklower  *	Dump the buffer to the screen in a readable format. Format is:
81237469Ssklower  *
81337469Ssklower  *		hex/dec  where hex is the hex format, dec is the decimal format.
81437469Ssklower  *		columns of hex/dec numbers will be printed, followed by the
81537469Ssklower  *		character representations (if printable).
81637469Ssklower  */
81737469Ssklower Dump_buf(buf, len)
81837469Ssklower caddr_t	buf;
81937469Ssklower int		len;
82037469Ssklower {
82137469Ssklower 	int		i,j;
82250236Ssklower #define Buf ((u_char *)buf)
82337469Ssklower 	printf("Dump buf 0x%x len 0x%x\n", buf, len);
82437469Ssklower 	for (i = 0; i < len; i += MAX_COLUMNS) {
82537469Ssklower 		printf("+%d:\t", i);
82637469Ssklower 		for (j = 0; j < MAX_COLUMNS; j++) {
82737469Ssklower 			if (i + j < len) {
82850236Ssklower 				printf("%x/%d\t", Buf[i+j], Buf[i+j]);
82937469Ssklower 			} else {
83037469Ssklower 				printf("	");
83137469Ssklower 			}
83237469Ssklower 		}
83337469Ssklower 
83437469Ssklower 		for (j = 0; j < MAX_COLUMNS; j++) {
83537469Ssklower 			if (i + j < len) {
83650236Ssklower 				if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128))
83750236Ssklower 					printf("%c", Buf[i+j]);
83837469Ssklower 				else
83937469Ssklower 					printf(".");
84037469Ssklower 			}
84137469Ssklower 		}
84237469Ssklower 		printf("\n");
84337469Ssklower 	}
84437469Ssklower }
84537469Ssklower 
84637469Ssklower 
84736414Ssklower #endif ARGO_DEBUG
84836414Ssklower 
849