149268Sbostic /*-
2*63222Sbostic * Copyright (c) 1991, 1993
3*63222Sbostic * The Regents of the University of California. All rights reserved.
449268Sbostic *
549268Sbostic * %sccs.include.redist.c%
649268Sbostic *
7*63222Sbostic * @(#)tp_subr2.c 8.1 (Berkeley) 06/10/93
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
5556533Sbostic #include <sys/param.h>
5656533Sbostic #include <sys/systm.h>
5756533Sbostic #include <sys/mbuf.h>
5856533Sbostic #include <sys/socket.h>
5956533Sbostic #include <sys/socketvar.h>
6056533Sbostic #include <sys/domain.h>
6156533Sbostic #include <sys/protosw.h>
6256533Sbostic #include <sys/errno.h>
6356533Sbostic #include <sys/time.h>
6456533Sbostic #include <sys/kernel.h>
6556533Sbostic
6636414Ssklower #undef MNULL
6756533Sbostic #include <netiso/argo_debug.h>
6856533Sbostic #include <netiso/tp_param.h>
6956533Sbostic #include <netiso/tp_ip.h>
7056533Sbostic #include <netiso/iso.h>
7156533Sbostic #include <netiso/iso_errno.h>
7256533Sbostic #include <netiso/iso_pcb.h>
7356533Sbostic #include <netiso/tp_timer.h>
7456533Sbostic #include <netiso/tp_stat.h>
7556533Sbostic #include <netiso/tp_tpdu.h>
7656533Sbostic #include <netiso/tp_pcb.h>
7756533Sbostic #include <netiso/tp_seq.h>
7856533Sbostic #include <netiso/tp_trace.h>
7956533Sbostic #include <netiso/tp_user.h>
8056533Sbostic #include <netiso/cons.h>
8136414Ssklower
8256533Sbostic #include <net/if.h>
8356533Sbostic #include <net/if_types.h>
8445900Ssklower #ifdef TRUE
8545900Ssklower #undef FALSE
8645900Ssklower #undef TRUE
8745900Ssklower #endif
8856533Sbostic #include <netccitt/x25.h>
8956533Sbostic #include <netccitt/pk.h>
9056533Sbostic #include <netccitt/pk_var.h>
9145900Ssklower
9253690Ssklower void tp_rsyset();
9353690Ssklower
9436414Ssklower /*
9536414Ssklower * NAME: tp_local_credit()
9636414Ssklower *
9736414Ssklower * CALLED FROM:
9836414Ssklower * tp_emit(), tp_usrreq()
9936414Ssklower *
10036414Ssklower * FUNCTION and ARGUMENTS:
10136414Ssklower * Computes the local credit and stashes it in tpcb->tp_lcredit.
10236414Ssklower * It's a macro in the production system rather than a procdure.
10336414Ssklower *
10436414Ssklower * RETURNS:
10536414Ssklower *
10636414Ssklower * SIDE EFFECTS:
10736414Ssklower *
10836414Ssklower * NOTES:
10936414Ssklower * This doesn't actually get called in a production system -
11036414Ssklower * the macro gets expanded instead in place of calls to this proc.
11136414Ssklower * But for debugging, we call this and that allows us to add
11236414Ssklower * debugging messages easily here.
11336414Ssklower */
11436414Ssklower void
tp_local_credit(tpcb)11536414Ssklower tp_local_credit(tpcb)
11636414Ssklower struct tp_pcb *tpcb;
11736414Ssklower {
11836414Ssklower LOCAL_CREDIT(tpcb);
11936414Ssklower IFDEBUG(D_CREDIT)
12036414Ssklower printf("ref 0x%x lcdt 0x%x l_tpdusize 0x%x decbit 0x%x\n",
12151213Ssklower tpcb->tp_lref,
12236414Ssklower tpcb->tp_lcredit,
12336414Ssklower tpcb->tp_l_tpdusize,
12436414Ssklower tpcb->tp_decbit,
12536414Ssklower tpcb->tp_cong_win
12636414Ssklower );
12736414Ssklower ENDDEBUG
12836414Ssklower IFTRACE(D_CREDIT)
12936414Ssklower tptraceTPCB(TPPTmisc,
13036414Ssklower "lcdt tpdusz \n",
13136414Ssklower tpcb->tp_lcredit, tpcb->tp_l_tpdusize, 0, 0);
13236414Ssklower ENDTRACE
13336414Ssklower }
13436414Ssklower
13536414Ssklower /*
13636414Ssklower * NAME: tp_protocol_error()
13736414Ssklower *
13836414Ssklower * CALLED FROM:
13936414Ssklower * tp_driver(), when it doesn't know what to do with
14036414Ssklower * a combo of event, state, predicate
14136414Ssklower *
14236414Ssklower * FUNCTION and ARGUMENTS:
14336414Ssklower * print error mesg
14436414Ssklower *
14536414Ssklower * RETURN VALUE:
14636414Ssklower * EIO - always
14736414Ssklower *
14836414Ssklower * SIDE EFFECTS:
14936414Ssklower *
15036414Ssklower * NOTES:
15136414Ssklower */
15236414Ssklower int
tp_protocol_error(e,tpcb)15336414Ssklower tp_protocol_error(e,tpcb)
15436414Ssklower struct tp_event *e;
15536414Ssklower struct tp_pcb *tpcb;
15636414Ssklower {
15736414Ssklower printf("TP PROTOCOL ERROR! tpcb 0x%x event 0x%x, state 0x%x\n",
15836414Ssklower tpcb, e->ev_number, tpcb->tp_state);
15936414Ssklower IFTRACE(D_DRIVER)
16036414Ssklower tptraceTPCB(TPPTmisc, "PROTOCOL ERROR tpcb event state",
16136414Ssklower tpcb, e->ev_number, tpcb->tp_state, 0 );
16236414Ssklower ENDTRACE
16336414Ssklower return EIO; /* for lack of anything better */
16436414Ssklower }
16536414Ssklower
16636414Ssklower
16736414Ssklower /* Not used at the moment */
16836414Ssklower ProtoHook
tp_drain()16936414Ssklower tp_drain()
17036414Ssklower {
17136414Ssklower return 0;
17236414Ssklower }
17336414Ssklower
17436414Ssklower
17536414Ssklower /*
17636414Ssklower * NAME: tp_indicate()
17736414Ssklower *
17836414Ssklower * CALLED FROM:
17936414Ssklower * tp.trans when XPD arrive, when a connection is being disconnected by
18036414Ssklower * the arrival of a DR or ER, and when a connection times out.
18136414Ssklower *
18236414Ssklower * FUNCTION and ARGUMENTS:
18336414Ssklower * (ind) is the type of indication : T_DISCONNECT, T_XPD
18436414Ssklower * (error) is an E* value that will be put in the socket structure
18536414Ssklower * to be passed along to the user later.
18636414Ssklower * Gives a SIGURG to the user process or group indicated by the socket
18736414Ssklower * attached to the tpcb.
18836414Ssklower *
18936414Ssklower * RETURNS: Rien
19036414Ssklower *
19136414Ssklower * SIDE EFFECTS:
19236414Ssklower *
19336414Ssklower * NOTES:
19436414Ssklower */
19536414Ssklower void
tp_indicate(ind,tpcb,error)19636414Ssklower tp_indicate(ind, tpcb, error)
19736414Ssklower int ind;
19836414Ssklower u_short error;
19936414Ssklower register struct tp_pcb *tpcb;
20036414Ssklower {
20136414Ssklower register struct socket *so = tpcb->tp_sock;
20236414Ssklower IFTRACE(D_INDICATION)
20339197Ssklower tptraceTPCB(TPPTindicate, ind, *(u_short *)(tpcb->tp_lsuffix),
20439197Ssklower *(u_short *)(tpcb->tp_fsuffix), error,so->so_pgid);
20536414Ssklower ENDTRACE
20636414Ssklower IFDEBUG(D_INDICATION)
20737469Ssklower char *ls, *fs;
20836414Ssklower ls = tpcb->tp_lsuffix,
20936414Ssklower fs = tpcb->tp_fsuffix,
21036414Ssklower
21136414Ssklower printf(
21237469Ssklower "indicate 0x%x lsuf 0x%02x%02x fsuf 0x%02x%02x err 0x%x noind 0x%x ref 0x%x\n",
21336414Ssklower ind,
21436414Ssklower *ls, *(ls+1), *fs, *(fs+1),
21537469Ssklower error, /*so->so_pgrp,*/
21636414Ssklower tpcb->tp_no_disc_indications,
21736414Ssklower tpcb->tp_lref);
21836414Ssklower ENDDEBUG
21936414Ssklower
22048744Ssklower if (ind == ER_TPDU) {
22148744Ssklower register struct mbuf *m;
22248744Ssklower struct tp_disc_reason x;
22348744Ssklower
22448744Ssklower if ((so->so_state & SS_CANTRCVMORE) == 0 &&
22548744Ssklower (m = m_get(M_DONTWAIT, MT_OOBDATA)) != 0) {
22648744Ssklower
22748744Ssklower x.dr_hdr.cmsg_len = m->m_len = sizeof(x);
22848744Ssklower x.dr_hdr.cmsg_level = SOL_TRANSPORT;
22948744Ssklower x.dr_hdr.cmsg_type= TPOPT_DISC_REASON;
23048744Ssklower x.dr_reason = error;
23148744Ssklower *mtod(m, struct tp_disc_reason *) = x;
23248744Ssklower sbappendrecord(&tpcb->tp_Xrcv, m);
23348744Ssklower error = 0;
23448744Ssklower } else
23548744Ssklower error = ECONNRESET;
23648744Ssklower }
23736414Ssklower so->so_error = error;
23836414Ssklower
23936414Ssklower if (ind == T_DISCONNECT) {
24051209Ssklower if (error == 0)
24151209Ssklower so->so_error = ENOTCONN;
24236414Ssklower if ( tpcb->tp_no_disc_indications )
24336414Ssklower return;
24436414Ssklower }
24536414Ssklower IFTRACE(D_INDICATION)
24636414Ssklower tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0);
24736414Ssklower ENDTRACE
24836414Ssklower sohasoutofband(so);
24936414Ssklower }
25036414Ssklower
25136414Ssklower /*
25236414Ssklower * NAME : tp_getoptions()
25336414Ssklower *
25436414Ssklower * CALLED FROM:
25536414Ssklower * tp.trans whenever we go into OPEN state
25636414Ssklower *
25736414Ssklower * FUNCTION and ARGUMENTS:
25836414Ssklower * sets the proper flags and values in the tpcb, to control
25936414Ssklower * the appropriate actions for the given class, options,
26036414Ssklower * sequence space, etc, etc.
26136414Ssklower *
26236414Ssklower * RETURNS: Nada
26336414Ssklower *
26436414Ssklower * SIDE EFFECTS:
26536414Ssklower *
26636414Ssklower * NOTES:
26736414Ssklower */
26836414Ssklower void
tp_getoptions(tpcb)26936414Ssklower tp_getoptions(tpcb)
27036414Ssklower struct tp_pcb *tpcb;
27136414Ssklower {
27236414Ssklower tpcb->tp_seqmask =
27336414Ssklower tpcb->tp_xtd_format ? TP_XTD_FMT_MASK : TP_NML_FMT_MASK ;
27436414Ssklower tpcb->tp_seqbit =
27536414Ssklower tpcb->tp_xtd_format ? TP_XTD_FMT_BIT : TP_NML_FMT_BIT ;
27636414Ssklower tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1;
27736414Ssklower tpcb->tp_dt_ticks =
27856307Smckusick max(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2));
27953690Ssklower tp_rsyset(tpcb);
28050975Ssklower
28136414Ssklower }
28236414Ssklower
28336414Ssklower /*
28436414Ssklower * NAME: tp_recycle_tsuffix()
28536414Ssklower *
28636414Ssklower * CALLED FROM:
28736414Ssklower * Called when a ref is frozen.
28836414Ssklower *
28936414Ssklower * FUNCTION and ARGUMENTS:
29036414Ssklower * allows the suffix to be reused.
29136414Ssklower *
29236414Ssklower * RETURNS: zilch
29336414Ssklower *
29436414Ssklower * SIDE EFFECTS:
29536414Ssklower *
29636414Ssklower * NOTES:
29736414Ssklower */
29836414Ssklower void
tp_recycle_tsuffix(tpcb)29936414Ssklower tp_recycle_tsuffix(tpcb)
30036414Ssklower struct tp_pcb *tpcb;
30136414Ssklower {
30237469Ssklower bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix));
30337469Ssklower bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix));
30436414Ssklower tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0;
30536414Ssklower
30636414Ssklower (tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb);
30736414Ssklower }
30836414Ssklower
30936414Ssklower /*
31036414Ssklower * NAME: tp_quench()
31136414Ssklower *
31236414Ssklower * CALLED FROM:
31336414Ssklower * tp{af}_quench() when ICMP source quench or similar thing arrives.
31436414Ssklower *
31536414Ssklower * FUNCTION and ARGUMENTS:
31636414Ssklower * Drop the congestion window back to 1.
31736414Ssklower * Congestion window scheme:
31836414Ssklower * Initial value is 1. ("slow start" as Nagle, et. al. call it)
31936414Ssklower * For each good ack that arrives, the congestion window is increased
32036414Ssklower * by 1 (up to max size of logical infinity, which is to say,
32136414Ssklower * it doesn't wrap around).
32236414Ssklower * Source quench causes it to drop back to 1.
32336414Ssklower * tp_send() uses the smaller of (regular window, congestion window).
32436414Ssklower * One retransmission strategy option is to have any retransmission
32536414Ssklower * cause reset the congestion window back to 1.
32636414Ssklower *
32736414Ssklower * (cmd) is either PRC_QUENCH: source quench, or
32836414Ssklower * PRC_QUENCH2: dest. quench (dec bit)
32936414Ssklower *
33036414Ssklower * RETURNS:
33136414Ssklower *
33236414Ssklower * SIDE EFFECTS:
33336414Ssklower *
33436414Ssklower * NOTES:
33536414Ssklower */
33636414Ssklower void
tp_quench(tpcb,cmd)33736414Ssklower tp_quench( tpcb, cmd )
33836414Ssklower struct tp_pcb *tpcb;
33936414Ssklower int cmd;
34036414Ssklower {
34136414Ssklower IFDEBUG(D_QUENCH)
34236414Ssklower printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n",
34339197Ssklower tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix));
34436414Ssklower printf("cong_win 0x%x decbit 0x%x \n",
34536414Ssklower tpcb->tp_cong_win, tpcb->tp_decbit);
34636414Ssklower ENDDEBUG
34736414Ssklower switch(cmd) {
34836414Ssklower case PRC_QUENCH:
34951204Ssklower tpcb->tp_cong_win = tpcb->tp_l_tpdusize;
35036414Ssklower IncStat(ts_quench);
35136414Ssklower break;
35236414Ssklower case PRC_QUENCH2:
35351204Ssklower tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* might as well quench source also */
35436414Ssklower tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT;
35536414Ssklower IncStat(ts_rcvdecbit);
35636414Ssklower break;
35736414Ssklower }
35836414Ssklower }
35936414Ssklower
36036414Ssklower
36136414Ssklower /*
36236414Ssklower * NAME: tp_netcmd()
36336414Ssklower *
36436414Ssklower * CALLED FROM:
36536414Ssklower *
36636414Ssklower * FUNCTION and ARGUMENTS:
36736414Ssklower *
36836414Ssklower * RETURNS:
36936414Ssklower *
37036414Ssklower * SIDE EFFECTS:
37136414Ssklower *
37236414Ssklower * NOTES:
37336414Ssklower */
37436414Ssklower tp_netcmd( tpcb, cmd )
37536414Ssklower struct tp_pcb *tpcb;
37636414Ssklower int cmd;
37736414Ssklower {
37845900Ssklower #ifdef TPCONS
37945900Ssklower struct isopcb *isop;
38045900Ssklower struct pklcd *lcp;
38145900Ssklower
38245900Ssklower if (tpcb->tp_netservice != ISO_CONS)
38345900Ssklower return;
38445900Ssklower isop = (struct isopcb *)tpcb->tp_npcb;
38545900Ssklower lcp = (struct pklcd *)isop->isop_chan;
38636414Ssklower switch (cmd) {
38736414Ssklower
38836414Ssklower case CONN_CLOSE:
38936414Ssklower case CONN_REFUSE:
39050648Ssklower if (isop->isop_refcnt == 1) {
39150648Ssklower /* This is really superfluous, since it would happen
39250648Ssklower anyway in iso_pcbdetach, although it is a courtesy
39350648Ssklower to free up the x.25 channel before the refwait timer
39450648Ssklower expires. */
39550648Ssklower lcp->lcd_upper = 0;
39650648Ssklower lcp->lcd_upnext = 0;
39745900Ssklower pk_disconnect(lcp);
39850648Ssklower isop->isop_chan = 0;
39950648Ssklower isop->isop_refcnt = 0;
40050648Ssklower }
40136414Ssklower break;
40236414Ssklower
40336414Ssklower default:
40436414Ssklower printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd);
40536414Ssklower break;
40636414Ssklower }
40760359Sbostic #else /* TPCONS */
40836414Ssklower printf("tp_netcmd(): X25 NOT CONFIGURED!!\n");
40945900Ssklower #endif
41036414Ssklower }
41136414Ssklower /*
41236414Ssklower * CALLED FROM:
41336414Ssklower * tp_ctloutput() and tp_emit()
41436414Ssklower * FUNCTION and ARGUMENTS:
41536414Ssklower * Convert a class mask to the highest numeric value it represents.
41636414Ssklower */
41736414Ssklower
41836414Ssklower int
tp_mask_to_num(x)41936414Ssklower tp_mask_to_num(x)
42036414Ssklower u_char x;
42136414Ssklower {
42236414Ssklower register int j;
42336414Ssklower
42436414Ssklower for(j = 4; j>=0 ;j--) {
42536414Ssklower if(x & (1<<j))
42636414Ssklower break;
42736414Ssklower }
42836414Ssklower ASSERT( (j == 4) || (j == 0) ); /* for now */
42936414Ssklower if( (j != 4) && (j != 0) ) {
43036414Ssklower printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n",
43136414Ssklower x, j);
43236414Ssklower }
43336414Ssklower IFTRACE(D_TPINPUT)
43436414Ssklower tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0);
43536414Ssklower ENDTRACE
43636414Ssklower IFDEBUG(D_TPINPUT)
43736414Ssklower printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j);
43836414Ssklower ENDDEBUG
43936414Ssklower return j;
44036414Ssklower }
44136414Ssklower
44236414Ssklower static
44336414Ssklower copyQOSparms(src, dst)
44436414Ssklower struct tp_conn_param *src, *dst;
44536414Ssklower {
44636414Ssklower /* copy all but the bits stuff at the end */
44736414Ssklower #define COPYSIZE (12 * sizeof(short))
44836414Ssklower
44937469Ssklower bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE);
45036414Ssklower dst->p_tpdusize = src->p_tpdusize;
45136414Ssklower dst->p_ack_strat = src->p_ack_strat;
45236414Ssklower dst->p_rx_strat = src->p_rx_strat;
45336414Ssklower #undef COPYSIZE
45436414Ssklower }
45551258Ssklower /*
45651258Ssklower * Determine a reasonable value for maxseg size.
45751258Ssklower * If the route is known, check route for mtu.
45851258Ssklower * We also initialize the congestion/slow start
45951258Ssklower * window to be a single segment if the destination isn't local.
46051258Ssklower * While looking at the routing entry, we also initialize other path-dependent
46151258Ssklower * parameters from pre-set or cached values in the routing entry.
46251258Ssklower */
46351258Ssklower void
tp_mss(tpcb,nhdr_size)46451258Ssklower tp_mss(tpcb, nhdr_size)
46551258Ssklower register struct tp_pcb *tpcb;
46651258Ssklower int nhdr_size;
46751258Ssklower {
46851258Ssklower register struct rtentry *rt;
46951258Ssklower struct ifnet *ifp;
47051258Ssklower register int rtt, mss;
47151258Ssklower u_long bufsize;
47251996Ssklower int i, ssthresh = 0, rt_mss;
47351258Ssklower struct socket *so;
47436414Ssklower
47551996Ssklower if (tpcb->tp_ptpdusize)
47651996Ssklower mss = tpcb->tp_ptpdusize << 7;
47751996Ssklower else
47851996Ssklower mss = 1 << tpcb->tp_tpdusize;
47951258Ssklower so = tpcb->tp_sock;
48051258Ssklower if ((rt = *(tpcb->tp_routep)) == 0) {
48151258Ssklower bufsize = so->so_rcv.sb_hiwat;
48251258Ssklower goto punt_route;
48351258Ssklower }
48451258Ssklower ifp = rt->rt_ifp;
48551258Ssklower
48651258Ssklower #ifdef RTV_MTU /* if route characteristics exist ... */
48751258Ssklower /*
48851258Ssklower * While we're here, check if there's an initial rtt
48951258Ssklower * or rttvar. Convert from the route-table units
49051258Ssklower * to hz ticks for the smoothed timers and slow-timeout units
49151258Ssklower * for other inital variables.
49251258Ssklower */
49351258Ssklower if (tpcb->tp_rtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) {
49451258Ssklower tpcb->tp_rtt = rtt * hz / RTM_RTTUNIT;
49551258Ssklower if (rt->rt_rmx.rmx_rttvar)
49651258Ssklower tpcb->tp_rtv = rt->rt_rmx.rmx_rttvar
49751258Ssklower * hz / RTM_RTTUNIT;
49851258Ssklower else
49951258Ssklower tpcb->tp_rtv = tpcb->tp_rtt;
50051258Ssklower }
50151258Ssklower /*
50251258Ssklower * if there's an mtu associated with the route, use it
50351258Ssklower */
50451258Ssklower if (rt->rt_rmx.rmx_mtu)
50551996Ssklower rt_mss = rt->rt_rmx.rmx_mtu - nhdr_size;
50651258Ssklower else
50751258Ssklower #endif /* RTV_MTU */
50851996Ssklower rt_mss = (ifp->if_mtu - nhdr_size);
50951996Ssklower if (tpcb->tp_ptpdusize == 0 || /* assume application doesn't care */
51051996Ssklower mss > rt_mss /* network won't support what was asked for */)
51151996Ssklower mss = rt_mss;
51251258Ssklower /* can propose mtu which are multiples of 128 */
51351258Ssklower mss &= ~0x7f;
51451258Ssklower /*
51551258Ssklower * If there's a pipesize, change the socket buffer
51651258Ssklower * to that size.
51751258Ssklower */
51851258Ssklower #ifdef RTV_SPIPE
51951258Ssklower if ((bufsize = rt->rt_rmx.rmx_sendpipe) > 0) {
52051258Ssklower #endif
52151258Ssklower bufsize = min(bufsize, so->so_snd.sb_hiwat);
52251258Ssklower (void) sbreserve(&so->so_snd, bufsize);
52351258Ssklower }
52451258Ssklower #ifdef RTV_SPIPE
52551258Ssklower if ((bufsize = rt->rt_rmx.rmx_recvpipe) > 0) {
52651258Ssklower #endif
52751258Ssklower bufsize = min(bufsize, so->so_rcv.sb_hiwat);
52851258Ssklower (void) sbreserve(&so->so_rcv, bufsize);
52951258Ssklower } else
53051258Ssklower bufsize = so->so_rcv.sb_hiwat;
53151258Ssklower #ifdef RTV_SSTHRESH
53251258Ssklower /*
53351258Ssklower * There's some sort of gateway or interface
53451258Ssklower * buffer limit on the path. Use this to set
53551258Ssklower * the slow start threshhold, but set the
53651258Ssklower * threshold to no less than 2*mss.
53751258Ssklower */
53851258Ssklower ssthresh = rt->rt_rmx.rmx_ssthresh;
53951258Ssklower punt_route:
54051258Ssklower /*
54151258Ssklower * The current mss is initialized to the default value.
54251258Ssklower * If we compute a smaller value, reduce the current mss.
54351258Ssklower * If we compute a larger value, return it for use in sending
54451258Ssklower * a max seg size option.
54551258Ssklower * If we received an offer, don't exceed it.
54651258Ssklower * However, do not accept offers under 128 bytes.
54751258Ssklower */
54851258Ssklower if (tpcb->tp_l_tpdusize)
54951258Ssklower mss = min(mss, tpcb->tp_l_tpdusize);
55051258Ssklower /*
55151258Ssklower * We want a minimum recv window of 4 packets to
55251258Ssklower * signal packet loss by duplicate acks.
55351258Ssklower */
55451258Ssklower mss = min(mss, bufsize >> 2) & ~0x7f;
55551258Ssklower mss = max(mss, 128); /* sanity */
55651258Ssklower tpcb->tp_cong_win =
55751258Ssklower (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) ? mss : bufsize;
55851258Ssklower tpcb->tp_l_tpdusize = mss;
55953690Ssklower tp_rsyset(tpcb);
56051258Ssklower tpcb->tp_ssthresh = max(2 * mss, ssthresh);
56151258Ssklower /* Calculate log2 of mss */
56251258Ssklower for (i = TP_MIN_TPDUSIZE + 1; i <= TP_MAX_TPDUSIZE; i++)
56351258Ssklower if ((1 << i) > mss)
56451258Ssklower break;
56551258Ssklower i--;
56651258Ssklower tpcb->tp_tpdusize = i;
56751258Ssklower #endif /* RTV_MTU */
56851258Ssklower }
56951258Ssklower
57036414Ssklower /*
57136414Ssklower * CALLED FROM:
57236414Ssklower * tp_usrreq on PRU_CONNECT and tp_input on receipt of CR
57336414Ssklower *
57436414Ssklower * FUNCTION and ARGUMENTS:
57551258Ssklower * -- An mbuf containing the peer's network address.
57651258Ssklower * -- Our control block, which will be modified
57751258Ssklower * -- In the case of cons, a control block for that layer.
57836414Ssklower *
57936414Ssklower *
58036414Ssklower * RETURNS:
58136414Ssklower * errno value :
58236414Ssklower * EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic)
58336414Ssklower * ECONNREFUSED if trying to run TP0 with non-type 37 address
58436414Ssklower * possibly other E* returned from cons_netcmd()
58551258Ssklower *
58651258Ssklower * SIDE EFFECTS:
58751258Ssklower * Determines recommended tpdusize, buffering and intial delays
58851258Ssklower * based on information cached on the route.
58936414Ssklower */
59036414Ssklower int
tp_route_to(m,tpcb,channel)59136414Ssklower tp_route_to( m, tpcb, channel)
59236414Ssklower struct mbuf *m;
59336414Ssklower register struct tp_pcb *tpcb;
59445900Ssklower caddr_t channel;
59536414Ssklower {
59636414Ssklower register struct sockaddr_iso *siso; /* NOTE: this may be a sockaddr_in */
59736414Ssklower extern struct tp_conn_param tp_conn_param[];
59850648Ssklower int error = 0, save_netservice = tpcb->tp_netservice;
59950648Ssklower register struct rtentry *rt = 0;
60051258Ssklower int nhdr_size, mtu, bufsize;
60136414Ssklower
60236414Ssklower siso = mtod(m, struct sockaddr_iso *);
60336414Ssklower IFTRACE(D_CONN)
60436414Ssklower tptraceTPCB(TPPTmisc,
60536414Ssklower "route_to: so afi netservice class",
60637469Ssklower tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice,
60736414Ssklower tpcb->tp_class);
60836414Ssklower ENDTRACE
60936414Ssklower IFDEBUG(D_CONN)
61036414Ssklower printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n",
61136414Ssklower m, channel, tpcb, tpcb->tp_netservice);
61236414Ssklower printf("m->mlen x%x, m->m_data:\n", m->m_len);
61336414Ssklower dump_buf(mtod(m, caddr_t), m->m_len);
61436414Ssklower ENDDEBUG
61550648Ssklower if (channel) {
61645900Ssklower #ifdef TPCONS
61750648Ssklower struct pklcd *lcp = (struct pklcd *)channel;
61845900Ssklower struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext,
61950435Ssklower *isop_new = (struct isopcb *)tpcb->tp_npcb;
62050648Ssklower /* The next 2 lines believe that you haven't
62150648Ssklower set any network level options or done a pcbconnect
62250648Ssklower and XXXXXXX'edly apply to both inpcb's and isopcb's */
62345900Ssklower remque(isop_new);
62445900Ssklower free(isop_new, M_PCB);
62550435Ssklower tpcb->tp_npcb = (caddr_t)isop;
62650648Ssklower tpcb->tp_netservice = ISO_CONS;
62750648Ssklower tpcb->tp_nlproto = nl_protosw + ISO_CONS;
62851258Ssklower if (isop->isop_refcnt++ == 0) {
62945900Ssklower iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL);
63051258Ssklower isop->isop_socket = tpcb->tp_sock;
63151258Ssklower } else
63250648Ssklower /* there are already connections sharing this */;
63345900Ssklower #endif
63450648Ssklower } else {
63550648Ssklower switch (siso->siso_family) {
63650648Ssklower default:
63750648Ssklower error = EAFNOSUPPORT;
63850648Ssklower goto done;
63950648Ssklower #ifdef ISO
64050648Ssklower case AF_ISO:
64151258Ssklower {
64251258Ssklower struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
64351258Ssklower int flags = tpcb->tp_sock->so_options & SO_DONTROUTE;
64450648Ssklower tpcb->tp_netservice = ISO_CLNS;
64551258Ssklower if (clnp_route(&siso->siso_addr, &isop->isop_route,
64651258Ssklower flags, (void **)0, (void **)0) == 0) {
64751258Ssklower rt = isop->isop_route.ro_rt;
64851258Ssklower if (rt && rt->rt_flags & RTF_PROTO1)
64950648Ssklower tpcb->tp_netservice = ISO_CONS;
65050648Ssklower }
65151258Ssklower } break;
65250648Ssklower #endif
65350648Ssklower #ifdef INET
65450648Ssklower case AF_INET:
65550648Ssklower tpcb->tp_netservice = IN_CLNS;
65651258Ssklower #endif
65750648Ssklower }
65850648Ssklower if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) {
65950648Ssklower IFDEBUG(D_CONN)
66050648Ssklower printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n",
66150648Ssklower save_netservice, tpcb->tp_netservice);
66250648Ssklower ENDDEBUG
66350648Ssklower if (error = tp_set_npcb(tpcb))
66450648Ssklower goto done;
66550648Ssklower }
66650648Ssklower IFDEBUG(D_CONN)
66750648Ssklower printf("tp_route_to calling nlp_pcbconn, netserv %d\n",
66850648Ssklower tpcb->tp_netservice);
66950648Ssklower ENDDEBUG
67050648Ssklower tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice;
67150435Ssklower error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m);
67250648Ssklower }
67351258Ssklower if (error)
67437469Ssklower goto done;
67551258Ssklower nhdr_size = tpcb->tp_nlproto->nlp_mtu(tpcb); /* only gets common info */
67651258Ssklower tp_mss(tpcb, nhdr_size);
67736414Ssklower done:
67836414Ssklower IFDEBUG(D_CONN)
67936414Ssklower printf("tp_route_to returns 0x%x\n", error);
68036414Ssklower ENDDEBUG
68136414Ssklower IFTRACE(D_CONN)
68236414Ssklower tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error,
68336414Ssklower tpcb->tp_netservice, tpcb->tp_class, 0);
68436414Ssklower ENDTRACE
68536414Ssklower return error;
68636414Ssklower }
68736414Ssklower
68847280Ssklower
68947280Ssklower /* class zero version */
69047280Ssklower void
tp0_stash(tpcb,e)69147280Ssklower tp0_stash( tpcb, e )
69247280Ssklower register struct tp_pcb *tpcb;
69347280Ssklower register struct tp_event *e;
69447280Ssklower {
69547280Ssklower #ifndef lint
69647280Ssklower #define E e->ATTR(DT_TPDU)
69760359Sbostic #else /* lint */
69847280Ssklower #define E e->ev_union.EV_DT_TPDU
69960359Sbostic #endif /* lint */
70047280Ssklower
70147280Ssklower register struct sockbuf *sb = &tpcb->tp_sock->so_rcv;
70247280Ssklower register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
70347280Ssklower
70447280Ssklower IFPERF(tpcb)
70547280Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen;
70647280Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time,
70747280Ssklower E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen);
70847280Ssklower ENDPERF
70947280Ssklower
71047280Ssklower IFDEBUG(D_STASH)
71147280Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x",
71247280Ssklower E.e_seq, E.e_datalen, E.e_eot);
71347280Ssklower ENDDEBUG
71447280Ssklower
71547280Ssklower IFTRACE(D_STASH)
71647280Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot",
71747280Ssklower E.e_seq, E.e_datalen, E.e_eot, 0);
71847280Ssklower ENDTRACE
71947280Ssklower
72047280Ssklower if ( E.e_eot ) {
72147280Ssklower register struct mbuf *n = E.e_data;
72247280Ssklower n->m_flags |= M_EOR;
72347280Ssklower n->m_act = MNULL; /* set on tp_input */
72447280Ssklower }
72547280Ssklower sbappend(sb, E.e_data);
72647280Ssklower IFDEBUG(D_STASH)
72747280Ssklower dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending");
72847280Ssklower ENDDEBUG
72947280Ssklower if (tpcb->tp_netservice != ISO_CONS)
73047280Ssklower printf("tp0_stash: tp running over something wierd\n");
73147280Ssklower else {
73247280Ssklower register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
73347280Ssklower pk_flowcontrol(lcp, sbspace(sb) <= 0, 1);
73447280Ssklower }
73547280Ssklower }
73647280Ssklower
73747280Ssklower void
tp0_openflow(tpcb)73847280Ssklower tp0_openflow(tpcb)
73947280Ssklower register struct tp_pcb *tpcb;
74047280Ssklower {
74147280Ssklower register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
74247280Ssklower if (tpcb->tp_netservice != ISO_CONS)
74347280Ssklower printf("tp0_openflow: tp running over something wierd\n");
74447280Ssklower else {
74547280Ssklower register struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
74647280Ssklower if (lcp->lcd_rxrnr_condition)
74747280Ssklower pk_flowcontrol(lcp, 0, 0);
74847280Ssklower }
74947280Ssklower }
75047280Ssklower #ifndef TPCONS
75147280Ssklower static
pk_flowcontrol()75247280Ssklower pk_flowcontrol() {}
75347280Ssklower #endif
75447280Ssklower
75536414Ssklower #ifdef TP_PERF_MEAS
75636414Ssklower /*
75736414Ssklower * CALLED FROM:
75836414Ssklower * tp_ctloutput() when the user sets TPOPT_PERF_MEAS on
75936414Ssklower * and tp_newsocket() when a new connection is made from
76036414Ssklower * a listening socket with tp_perf_on == true.
76136414Ssklower * FUNCTION and ARGUMENTS:
76236414Ssklower * (tpcb) is the usual; this procedure gets a clear cluster mbuf for
76336414Ssklower * a tp_pmeas structure, and makes tpcb->tp_p_meas point to it.
76436414Ssklower * RETURN VALUE:
76536414Ssklower * ENOBUFS if it cannot get a cluster mbuf.
76636414Ssklower */
76736414Ssklower
76836414Ssklower int
tp_setup_perf(tpcb)76936414Ssklower tp_setup_perf(tpcb)
77036414Ssklower register struct tp_pcb *tpcb;
77136414Ssklower {
77236414Ssklower register struct mbuf *q;
77336414Ssklower
77437469Ssklower if( tpcb->tp_p_meas == 0 ) {
77537469Ssklower MGET(q, M_WAITOK, MT_PCB);
77636414Ssklower if (q == 0)
77736414Ssklower return ENOBUFS;
77837469Ssklower MCLGET(q, M_WAITOK);
77937469Ssklower if ((q->m_flags & M_EXT) == 0) {
78037469Ssklower (void) m_free(q);
78136414Ssklower return ENOBUFS;
78236414Ssklower }
78337469Ssklower q->m_len = sizeof (struct tp_pmeas);
78437469Ssklower tpcb->tp_p_mbuf = q;
78537469Ssklower tpcb->tp_p_meas = mtod(q, struct tp_pmeas *);
78637469Ssklower bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) );
78737469Ssklower IFDEBUG(D_PERF_MEAS)
78837469Ssklower printf(
78937469Ssklower "tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n",
79037469Ssklower tpcb, tpcb->tp_sock, tpcb->tp_lref,
79137469Ssklower tpcb->tp_p_meas, tpcb->tp_perf_on);
79237469Ssklower ENDDEBUG
79337469Ssklower tpcb->tp_perf_on = 1;
79436414Ssklower }
79536414Ssklower return 0;
79636414Ssklower }
79760359Sbostic #endif /* TP_PERF_MEAS */
79836414Ssklower
79936414Ssklower #ifdef ARGO_DEBUG
dump_addr(addr)80036414Ssklower dump_addr (addr)
80136414Ssklower register struct sockaddr *addr;
80236414Ssklower {
80336414Ssklower switch( addr->sa_family ) {
80436414Ssklower case AF_INET:
80537469Ssklower dump_inaddr((struct sockaddr_in *)addr);
80636414Ssklower break;
80737469Ssklower #ifdef ISO
80836414Ssklower case AF_ISO:
80937469Ssklower dump_isoaddr((struct sockaddr_iso *)addr);
81036414Ssklower break;
81160359Sbostic #endif /* ISO */
81236414Ssklower default:
81336414Ssklower printf("BAD AF: 0x%x\n", addr->sa_family);
81436414Ssklower break;
81536414Ssklower }
81636414Ssklower }
81736414Ssklower
81837469Ssklower #define MAX_COLUMNS 8
81937469Ssklower /*
82037469Ssklower * Dump the buffer to the screen in a readable format. Format is:
82137469Ssklower *
82237469Ssklower * hex/dec where hex is the hex format, dec is the decimal format.
82337469Ssklower * columns of hex/dec numbers will be printed, followed by the
82437469Ssklower * character representations (if printable).
82537469Ssklower */
Dump_buf(buf,len)82637469Ssklower Dump_buf(buf, len)
82737469Ssklower caddr_t buf;
82837469Ssklower int len;
82937469Ssklower {
83037469Ssklower int i,j;
83150236Ssklower #define Buf ((u_char *)buf)
83237469Ssklower printf("Dump buf 0x%x len 0x%x\n", buf, len);
83337469Ssklower for (i = 0; i < len; i += MAX_COLUMNS) {
83437469Ssklower printf("+%d:\t", i);
83537469Ssklower for (j = 0; j < MAX_COLUMNS; j++) {
83637469Ssklower if (i + j < len) {
83750236Ssklower printf("%x/%d\t", Buf[i+j], Buf[i+j]);
83837469Ssklower } else {
83937469Ssklower printf(" ");
84037469Ssklower }
84137469Ssklower }
84237469Ssklower
84337469Ssklower for (j = 0; j < MAX_COLUMNS; j++) {
84437469Ssklower if (i + j < len) {
84550236Ssklower if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128))
84650236Ssklower printf("%c", Buf[i+j]);
84737469Ssklower else
84837469Ssklower printf(".");
84937469Ssklower }
85037469Ssklower }
85137469Ssklower printf("\n");
85237469Ssklower }
85337469Ssklower }
85460359Sbostic #endif /* ARGO_DEBUG */
855