149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*51996Ssklower * @(#)tp_subr2.c 7.18 (Berkeley) 12/17/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 } 45351258Ssklower /* 45451258Ssklower * Determine a reasonable value for maxseg size. 45551258Ssklower * If the route is known, check route for mtu. 45651258Ssklower * We also initialize the congestion/slow start 45751258Ssklower * window to be a single segment if the destination isn't local. 45851258Ssklower * While looking at the routing entry, we also initialize other path-dependent 45951258Ssklower * parameters from pre-set or cached values in the routing entry. 46051258Ssklower */ 46151258Ssklower void 46251258Ssklower tp_mss(tpcb, nhdr_size) 46351258Ssklower register struct tp_pcb *tpcb; 46451258Ssklower int nhdr_size; 46551258Ssklower { 46651258Ssklower register struct rtentry *rt; 46751258Ssklower struct ifnet *ifp; 46851258Ssklower register int rtt, mss; 46951258Ssklower u_long bufsize; 470*51996Ssklower int i, ssthresh = 0, rt_mss; 47151258Ssklower struct socket *so; 47236414Ssklower 473*51996Ssklower if (tpcb->tp_ptpdusize) 474*51996Ssklower mss = tpcb->tp_ptpdusize << 7; 475*51996Ssklower else 476*51996Ssklower mss = 1 << tpcb->tp_tpdusize; 47751258Ssklower so = tpcb->tp_sock; 47851258Ssklower if ((rt = *(tpcb->tp_routep)) == 0) { 47951258Ssklower bufsize = so->so_rcv.sb_hiwat; 48051258Ssklower goto punt_route; 48151258Ssklower } 48251258Ssklower ifp = rt->rt_ifp; 48351258Ssklower 48451258Ssklower #ifdef RTV_MTU /* if route characteristics exist ... */ 48551258Ssklower /* 48651258Ssklower * While we're here, check if there's an initial rtt 48751258Ssklower * or rttvar. Convert from the route-table units 48851258Ssklower * to hz ticks for the smoothed timers and slow-timeout units 48951258Ssklower * for other inital variables. 49051258Ssklower */ 49151258Ssklower if (tpcb->tp_rtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) { 49251258Ssklower tpcb->tp_rtt = rtt * hz / RTM_RTTUNIT; 49351258Ssklower if (rt->rt_rmx.rmx_rttvar) 49451258Ssklower tpcb->tp_rtv = rt->rt_rmx.rmx_rttvar 49551258Ssklower * hz / RTM_RTTUNIT; 49651258Ssklower else 49751258Ssklower tpcb->tp_rtv = tpcb->tp_rtt; 49851258Ssklower } 49951258Ssklower /* 50051258Ssklower * if there's an mtu associated with the route, use it 50151258Ssklower */ 50251258Ssklower if (rt->rt_rmx.rmx_mtu) 503*51996Ssklower rt_mss = rt->rt_rmx.rmx_mtu - nhdr_size; 50451258Ssklower else 50551258Ssklower #endif /* RTV_MTU */ 506*51996Ssklower rt_mss = (ifp->if_mtu - nhdr_size); 507*51996Ssklower if (tpcb->tp_ptpdusize == 0 || /* assume application doesn't care */ 508*51996Ssklower mss > rt_mss /* network won't support what was asked for */) 509*51996Ssklower mss = rt_mss; 51051258Ssklower /* can propose mtu which are multiples of 128 */ 51151258Ssklower mss &= ~0x7f; 51251258Ssklower /* 51351258Ssklower * If there's a pipesize, change the socket buffer 51451258Ssklower * to that size. 51551258Ssklower */ 51651258Ssklower #ifdef RTV_SPIPE 51751258Ssklower if ((bufsize = rt->rt_rmx.rmx_sendpipe) > 0) { 51851258Ssklower #endif 51951258Ssklower bufsize = min(bufsize, so->so_snd.sb_hiwat); 52051258Ssklower (void) sbreserve(&so->so_snd, bufsize); 52151258Ssklower } 52251258Ssklower #ifdef RTV_SPIPE 52351258Ssklower if ((bufsize = rt->rt_rmx.rmx_recvpipe) > 0) { 52451258Ssklower #endif 52551258Ssklower bufsize = min(bufsize, so->so_rcv.sb_hiwat); 52651258Ssklower (void) sbreserve(&so->so_rcv, bufsize); 52751258Ssklower } else 52851258Ssklower bufsize = so->so_rcv.sb_hiwat; 52951258Ssklower #ifdef RTV_SSTHRESH 53051258Ssklower /* 53151258Ssklower * There's some sort of gateway or interface 53251258Ssklower * buffer limit on the path. Use this to set 53351258Ssklower * the slow start threshhold, but set the 53451258Ssklower * threshold to no less than 2*mss. 53551258Ssklower */ 53651258Ssklower ssthresh = rt->rt_rmx.rmx_ssthresh; 53751258Ssklower punt_route: 53851258Ssklower /* 53951258Ssklower * The current mss is initialized to the default value. 54051258Ssklower * If we compute a smaller value, reduce the current mss. 54151258Ssklower * If we compute a larger value, return it for use in sending 54251258Ssklower * a max seg size option. 54351258Ssklower * If we received an offer, don't exceed it. 54451258Ssklower * However, do not accept offers under 128 bytes. 54551258Ssklower */ 54651258Ssklower if (tpcb->tp_l_tpdusize) 54751258Ssklower mss = min(mss, tpcb->tp_l_tpdusize); 54851258Ssklower /* 54951258Ssklower * We want a minimum recv window of 4 packets to 55051258Ssklower * signal packet loss by duplicate acks. 55151258Ssklower */ 55251258Ssklower mss = min(mss, bufsize >> 2) & ~0x7f; 55351258Ssklower mss = max(mss, 128); /* sanity */ 55451258Ssklower tpcb->tp_cong_win = 55551258Ssklower (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) ? mss : bufsize; 55651258Ssklower tpcb->tp_l_tpdusize = mss; 55751258Ssklower tpcb->tp_ssthresh = max(2 * mss, ssthresh); 55851258Ssklower /* Calculate log2 of mss */ 55951258Ssklower for (i = TP_MIN_TPDUSIZE + 1; i <= TP_MAX_TPDUSIZE; i++) 56051258Ssklower if ((1 << i) > mss) 56151258Ssklower break; 56251258Ssklower i--; 56351258Ssklower tpcb->tp_tpdusize = i; 56451258Ssklower #endif /* RTV_MTU */ 56551258Ssklower } 56651258Ssklower 56736414Ssklower /* 56836414Ssklower * CALLED FROM: 56936414Ssklower * tp_usrreq on PRU_CONNECT and tp_input on receipt of CR 57036414Ssklower * 57136414Ssklower * FUNCTION and ARGUMENTS: 57251258Ssklower * -- An mbuf containing the peer's network address. 57351258Ssklower * -- Our control block, which will be modified 57451258Ssklower * -- In the case of cons, a control block for that layer. 57536414Ssklower * 57636414Ssklower * 57736414Ssklower * RETURNS: 57836414Ssklower * errno value : 57936414Ssklower * EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic) 58036414Ssklower * ECONNREFUSED if trying to run TP0 with non-type 37 address 58136414Ssklower * possibly other E* returned from cons_netcmd() 58251258Ssklower * 58351258Ssklower * SIDE EFFECTS: 58451258Ssklower * Determines recommended tpdusize, buffering and intial delays 58551258Ssklower * based on information cached on the route. 58636414Ssklower */ 58736414Ssklower int 58836414Ssklower tp_route_to( m, tpcb, channel) 58936414Ssklower struct mbuf *m; 59036414Ssklower register struct tp_pcb *tpcb; 59145900Ssklower caddr_t channel; 59236414Ssklower { 59336414Ssklower register struct sockaddr_iso *siso; /* NOTE: this may be a sockaddr_in */ 59436414Ssklower extern struct tp_conn_param tp_conn_param[]; 59550648Ssklower int error = 0, save_netservice = tpcb->tp_netservice; 59650648Ssklower register struct rtentry *rt = 0; 59751258Ssklower int nhdr_size, mtu, bufsize; 59836414Ssklower 59936414Ssklower siso = mtod(m, struct sockaddr_iso *); 60036414Ssklower IFTRACE(D_CONN) 60136414Ssklower tptraceTPCB(TPPTmisc, 60236414Ssklower "route_to: so afi netservice class", 60337469Ssklower tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice, 60436414Ssklower tpcb->tp_class); 60536414Ssklower ENDTRACE 60636414Ssklower IFDEBUG(D_CONN) 60736414Ssklower printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n", 60836414Ssklower m, channel, tpcb, tpcb->tp_netservice); 60936414Ssklower printf("m->mlen x%x, m->m_data:\n", m->m_len); 61036414Ssklower dump_buf(mtod(m, caddr_t), m->m_len); 61136414Ssklower ENDDEBUG 61250648Ssklower if (channel) { 61345900Ssklower #ifdef TPCONS 61450648Ssklower struct pklcd *lcp = (struct pklcd *)channel; 61545900Ssklower struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext, 61650435Ssklower *isop_new = (struct isopcb *)tpcb->tp_npcb; 61750648Ssklower /* The next 2 lines believe that you haven't 61850648Ssklower set any network level options or done a pcbconnect 61950648Ssklower and XXXXXXX'edly apply to both inpcb's and isopcb's */ 62045900Ssklower remque(isop_new); 62145900Ssklower free(isop_new, M_PCB); 62250435Ssklower tpcb->tp_npcb = (caddr_t)isop; 62350648Ssklower tpcb->tp_netservice = ISO_CONS; 62450648Ssklower tpcb->tp_nlproto = nl_protosw + ISO_CONS; 62551258Ssklower if (isop->isop_refcnt++ == 0) { 62645900Ssklower iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL); 62751258Ssklower isop->isop_socket = tpcb->tp_sock; 62851258Ssklower } else 62950648Ssklower /* there are already connections sharing this */; 63045900Ssklower #endif 63150648Ssklower } else { 63250648Ssklower switch (siso->siso_family) { 63350648Ssklower default: 63450648Ssklower error = EAFNOSUPPORT; 63550648Ssklower goto done; 63650648Ssklower #ifdef ISO 63750648Ssklower case AF_ISO: 63851258Ssklower { 63951258Ssklower struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 64051258Ssklower int flags = tpcb->tp_sock->so_options & SO_DONTROUTE; 64150648Ssklower tpcb->tp_netservice = ISO_CLNS; 64251258Ssklower if (clnp_route(&siso->siso_addr, &isop->isop_route, 64351258Ssklower flags, (void **)0, (void **)0) == 0) { 64451258Ssklower rt = isop->isop_route.ro_rt; 64551258Ssklower if (rt && rt->rt_flags & RTF_PROTO1) 64650648Ssklower tpcb->tp_netservice = ISO_CONS; 64750648Ssklower } 64851258Ssklower } break; 64950648Ssklower #endif 65050648Ssklower #ifdef INET 65150648Ssklower case AF_INET: 65250648Ssklower tpcb->tp_netservice = IN_CLNS; 65351258Ssklower #endif 65450648Ssklower } 65550648Ssklower if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) { 65650648Ssklower IFDEBUG(D_CONN) 65750648Ssklower printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n", 65850648Ssklower save_netservice, tpcb->tp_netservice); 65950648Ssklower ENDDEBUG 66050648Ssklower if (error = tp_set_npcb(tpcb)) 66150648Ssklower goto done; 66250648Ssklower } 66350648Ssklower IFDEBUG(D_CONN) 66450648Ssklower printf("tp_route_to calling nlp_pcbconn, netserv %d\n", 66550648Ssklower tpcb->tp_netservice); 66650648Ssklower ENDDEBUG 66750648Ssklower tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice; 66850435Ssklower error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m); 66950648Ssklower } 67051258Ssklower if (error) 67137469Ssklower goto done; 67251258Ssklower nhdr_size = tpcb->tp_nlproto->nlp_mtu(tpcb); /* only gets common info */ 67351258Ssklower tp_mss(tpcb, nhdr_size); 67436414Ssklower done: 67536414Ssklower IFDEBUG(D_CONN) 67636414Ssklower printf("tp_route_to returns 0x%x\n", error); 67736414Ssklower ENDDEBUG 67836414Ssklower IFTRACE(D_CONN) 67936414Ssklower tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error, 68036414Ssklower tpcb->tp_netservice, tpcb->tp_class, 0); 68136414Ssklower ENDTRACE 68236414Ssklower return error; 68336414Ssklower } 68436414Ssklower 68547280Ssklower 68647280Ssklower /* class zero version */ 68747280Ssklower void 68847280Ssklower tp0_stash( tpcb, e ) 68947280Ssklower register struct tp_pcb *tpcb; 69047280Ssklower register struct tp_event *e; 69147280Ssklower { 69247280Ssklower #ifndef lint 69347280Ssklower #define E e->ATTR(DT_TPDU) 69447280Ssklower #else lint 69547280Ssklower #define E e->ev_union.EV_DT_TPDU 69647280Ssklower #endif lint 69747280Ssklower 69847280Ssklower register struct sockbuf *sb = &tpcb->tp_sock->so_rcv; 69947280Ssklower register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 70047280Ssklower 70147280Ssklower IFPERF(tpcb) 70247280Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen; 70347280Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 70447280Ssklower E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen); 70547280Ssklower ENDPERF 70647280Ssklower 70747280Ssklower IFDEBUG(D_STASH) 70847280Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x", 70947280Ssklower E.e_seq, E.e_datalen, E.e_eot); 71047280Ssklower ENDDEBUG 71147280Ssklower 71247280Ssklower IFTRACE(D_STASH) 71347280Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 71447280Ssklower E.e_seq, E.e_datalen, E.e_eot, 0); 71547280Ssklower ENDTRACE 71647280Ssklower 71747280Ssklower if ( E.e_eot ) { 71847280Ssklower register struct mbuf *n = E.e_data; 71947280Ssklower n->m_flags |= M_EOR; 72047280Ssklower n->m_act = MNULL; /* set on tp_input */ 72147280Ssklower } 72247280Ssklower sbappend(sb, E.e_data); 72347280Ssklower IFDEBUG(D_STASH) 72447280Ssklower dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending"); 72547280Ssklower ENDDEBUG 72647280Ssklower if (tpcb->tp_netservice != ISO_CONS) 72747280Ssklower printf("tp0_stash: tp running over something wierd\n"); 72847280Ssklower else { 72947280Ssklower register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 73047280Ssklower pk_flowcontrol(lcp, sbspace(sb) <= 0, 1); 73147280Ssklower } 73247280Ssklower } 73347280Ssklower 73447280Ssklower void 73547280Ssklower tp0_openflow(tpcb) 73647280Ssklower register struct tp_pcb *tpcb; 73747280Ssklower { 73847280Ssklower register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; 73947280Ssklower if (tpcb->tp_netservice != ISO_CONS) 74047280Ssklower printf("tp0_openflow: tp running over something wierd\n"); 74147280Ssklower else { 74247280Ssklower register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; 74347280Ssklower if (lcp->lcd_rxrnr_condition) 74447280Ssklower pk_flowcontrol(lcp, 0, 0); 74547280Ssklower } 74647280Ssklower } 74747280Ssklower #ifndef TPCONS 74847280Ssklower static 74947280Ssklower pk_flowcontrol() {} 75047280Ssklower #endif 75147280Ssklower 75236414Ssklower #ifdef TP_PERF_MEAS 75336414Ssklower /* 75436414Ssklower * CALLED FROM: 75536414Ssklower * tp_ctloutput() when the user sets TPOPT_PERF_MEAS on 75636414Ssklower * and tp_newsocket() when a new connection is made from 75736414Ssklower * a listening socket with tp_perf_on == true. 75836414Ssklower * FUNCTION and ARGUMENTS: 75936414Ssklower * (tpcb) is the usual; this procedure gets a clear cluster mbuf for 76036414Ssklower * a tp_pmeas structure, and makes tpcb->tp_p_meas point to it. 76136414Ssklower * RETURN VALUE: 76236414Ssklower * ENOBUFS if it cannot get a cluster mbuf. 76336414Ssklower */ 76436414Ssklower 76536414Ssklower int 76636414Ssklower tp_setup_perf(tpcb) 76736414Ssklower register struct tp_pcb *tpcb; 76836414Ssklower { 76936414Ssklower register struct mbuf *q; 77036414Ssklower 77137469Ssklower if( tpcb->tp_p_meas == 0 ) { 77237469Ssklower MGET(q, M_WAITOK, MT_PCB); 77336414Ssklower if (q == 0) 77436414Ssklower return ENOBUFS; 77537469Ssklower MCLGET(q, M_WAITOK); 77637469Ssklower if ((q->m_flags & M_EXT) == 0) { 77737469Ssklower (void) m_free(q); 77836414Ssklower return ENOBUFS; 77936414Ssklower } 78037469Ssklower q->m_len = sizeof (struct tp_pmeas); 78137469Ssklower tpcb->tp_p_mbuf = q; 78237469Ssklower tpcb->tp_p_meas = mtod(q, struct tp_pmeas *); 78337469Ssklower bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) ); 78437469Ssklower IFDEBUG(D_PERF_MEAS) 78537469Ssklower printf( 78637469Ssklower "tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n", 78737469Ssklower tpcb, tpcb->tp_sock, tpcb->tp_lref, 78837469Ssklower tpcb->tp_p_meas, tpcb->tp_perf_on); 78937469Ssklower ENDDEBUG 79037469Ssklower tpcb->tp_perf_on = 1; 79136414Ssklower } 79236414Ssklower return 0; 79336414Ssklower } 79436414Ssklower #endif TP_PERF_MEAS 79536414Ssklower 79636414Ssklower #ifdef ARGO_DEBUG 79736414Ssklower dump_addr (addr) 79836414Ssklower register struct sockaddr *addr; 79936414Ssklower { 80036414Ssklower switch( addr->sa_family ) { 80136414Ssklower case AF_INET: 80237469Ssklower dump_inaddr((struct sockaddr_in *)addr); 80336414Ssklower break; 80437469Ssklower #ifdef ISO 80536414Ssklower case AF_ISO: 80637469Ssklower dump_isoaddr((struct sockaddr_iso *)addr); 80736414Ssklower break; 80837469Ssklower #endif ISO 80936414Ssklower default: 81036414Ssklower printf("BAD AF: 0x%x\n", addr->sa_family); 81136414Ssklower break; 81236414Ssklower } 81336414Ssklower } 81436414Ssklower 81537469Ssklower #define MAX_COLUMNS 8 81637469Ssklower /* 81737469Ssklower * Dump the buffer to the screen in a readable format. Format is: 81837469Ssklower * 81937469Ssklower * hex/dec where hex is the hex format, dec is the decimal format. 82037469Ssklower * columns of hex/dec numbers will be printed, followed by the 82137469Ssklower * character representations (if printable). 82237469Ssklower */ 82337469Ssklower Dump_buf(buf, len) 82437469Ssklower caddr_t buf; 82537469Ssklower int len; 82637469Ssklower { 82737469Ssklower int i,j; 82850236Ssklower #define Buf ((u_char *)buf) 82937469Ssklower printf("Dump buf 0x%x len 0x%x\n", buf, len); 83037469Ssklower for (i = 0; i < len; i += MAX_COLUMNS) { 83137469Ssklower printf("+%d:\t", i); 83237469Ssklower for (j = 0; j < MAX_COLUMNS; j++) { 83337469Ssklower if (i + j < len) { 83450236Ssklower printf("%x/%d\t", Buf[i+j], Buf[i+j]); 83537469Ssklower } else { 83637469Ssklower printf(" "); 83737469Ssklower } 83837469Ssklower } 83937469Ssklower 84037469Ssklower for (j = 0; j < MAX_COLUMNS; j++) { 84137469Ssklower if (i + j < len) { 84250236Ssklower if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128)) 84350236Ssklower printf("%c", Buf[i+j]); 84437469Ssklower else 84537469Ssklower printf("."); 84637469Ssklower } 84737469Ssklower } 84837469Ssklower printf("\n"); 84937469Ssklower } 85037469Ssklower } 85137469Ssklower 85237469Ssklower 85336414Ssklower #endif ARGO_DEBUG 85436414Ssklower 855