136413Ssklower /*********************************************************** 236413Ssklower Copyright IBM Corporation 1987 336413Ssklower 436413Ssklower All Rights Reserved 536413Ssklower 636413Ssklower Permission to use, copy, modify, and distribute this software and its 736413Ssklower documentation for any purpose and without fee is hereby granted, 836413Ssklower provided that the above copyright notice appear in all copies and that 936413Ssklower both that copyright notice and this permission notice appear in 1036413Ssklower supporting documentation, and that the name of IBM not be 1136413Ssklower used in advertising or publicity pertaining to distribution of the 1236413Ssklower software without specific, written prior permission. 1336413Ssklower 1436413Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 1536413Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 1636413Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 1736413Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 1836413Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 1936413Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2036413Ssklower SOFTWARE. 2136413Ssklower 2236413Ssklower ******************************************************************/ 2336413Ssklower 2436413Ssklower /* 2536413Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 2636413Ssklower */ 2736413Ssklower /* 2836413Ssklower * ARGO TP 2936413Ssklower * 3036413Ssklower * $Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $ 3136413Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_subr.c,v $ 32*38841Ssklower * @(#)tp_subr.c 7.3 (Berkeley) 08/29/89 * 3336413Ssklower * 3436413Ssklower * The main work of data transfer is done here. 3536413Ssklower * These routines are called from tp.trans. 3636413Ssklower * They include the routines that check the validity of acks and Xacks, 3736413Ssklower * (tp_goodack() and tp_goodXack() ) 3836413Ssklower * take packets from socket buffers and send them (tp_send()), 3936413Ssklower * drop the data from the socket buffers (tp_sbdrop()), 4036413Ssklower * and put incoming packet data into socket buffers (tp_stash()). 4136413Ssklower */ 4236413Ssklower 4336413Ssklower #ifndef lint 4436413Ssklower static char *rcsid = "$Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $"; 4536413Ssklower #endif lint 4636413Ssklower 4736413Ssklower #include "param.h" 4836413Ssklower #include "mbuf.h" 4936413Ssklower #include "socket.h" 5036413Ssklower #include "socketvar.h" 5136413Ssklower #include "protosw.h" 5236413Ssklower #include "errno.h" 5336413Ssklower #include "types.h" 5436413Ssklower #include "time.h" 5536413Ssklower 5637469Ssklower #include "tp_ip.h" 5737469Ssklower #include "iso.h" 5837469Ssklower #include "argo_debug.h" 5937469Ssklower #include "tp_timer.h" 6037469Ssklower #include "tp_param.h" 6137469Ssklower #include "tp_stat.h" 6237469Ssklower #include "tp_pcb.h" 6337469Ssklower #include "tp_tpdu.h" 6437469Ssklower #include "tp_trace.h" 6537469Ssklower #include "tp_meas.h" 6637469Ssklower #include "tp_seq.h" 6736413Ssklower 6836413Ssklower int tp_emit(); 6936413Ssklower static void tp_sbdrop(); 7036413Ssklower 7136413Ssklower #define SMOOTH(newtype, alpha, old, new) \ 7236413Ssklower (newtype) (((new - old)>>alpha) + (old)) 7336413Ssklower 7436413Ssklower #define ABS(type, val) \ 7536413Ssklower (type) (((int)(val)<0)?-(val):(val)) 7636413Ssklower 7736413Ssklower #define TP_MAKE_RTC( Xreg, Xseq, Xeot, Xdata, Xlen, Xretval, Xtype) \ 7836413Ssklower { struct mbuf *xxn;\ 7936413Ssklower MGET(xxn, M_DONTWAIT, Xtype);\ 8036413Ssklower if( xxn == (struct mbuf *)0 ) {\ 8136413Ssklower printf("MAKE RTC FAILED: ENOBUFS\n");\ 8236413Ssklower return (int)Xretval;\ 8336413Ssklower }\ 8436413Ssklower xxn->m_act=MNULL;\ 8536413Ssklower Xreg = mtod(xxn, struct tp_rtc *);\ 8636413Ssklower if( Xreg == (struct tp_rtc *)0 ) {\ 8736413Ssklower return (int)Xretval;\ 8836413Ssklower }\ 8936413Ssklower Xreg->tprt_eot = Xeot;\ 9036413Ssklower Xreg->tprt_seq = Xseq;\ 9136413Ssklower Xreg->tprt_data = Xdata;\ 9236413Ssklower Xreg->tprt_octets = Xlen;\ 9336413Ssklower } 9436413Ssklower 9536413Ssklower 9636413Ssklower /* 9736413Ssklower * CALLED FROM: 9836413Ssklower * tp.trans, when an XAK arrives 9936413Ssklower * FUNCTION and ARGUMENTS: 10036413Ssklower * Determines if the sequence number (seq) from the XAK 10136413Ssklower * acks anything new. If so, drop the appropriate tpdu 10236413Ssklower * from the XPD send queue. 10336413Ssklower * RETURN VALUE: 10436413Ssklower * Returns 1 if it did this, 0 if the ack caused no action. 10536413Ssklower */ 10636413Ssklower int 10736413Ssklower tp_goodXack(tpcb, seq) 10836413Ssklower struct tp_pcb *tpcb; 10936413Ssklower SeqNum seq; 11036413Ssklower { 11136413Ssklower 11236413Ssklower IFTRACE(D_XPD) 11336413Ssklower tptraceTPCB(TPPTgotXack, 11436413Ssklower seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndhiwat, 11536413Ssklower tpcb->tp_snduna); 11636413Ssklower ENDTRACE 11736413Ssklower 11836413Ssklower if ( seq == tpcb->tp_Xuna ) { 11936413Ssklower tpcb->tp_Xuna = tpcb->tp_Xsndnxt; 12036413Ssklower 12136413Ssklower /* DROP 1 packet from the Xsnd socket buf - just so happens 12236413Ssklower * that only one packet can be there at any time 12336413Ssklower * so drop the whole thing. If you allow > 1 packet 12436413Ssklower * the socket buffer, then you'll have to keep 12536413Ssklower * track of how many characters went w/ each XPD tpdu, so this 12636413Ssklower * will get messier 12736413Ssklower */ 12836413Ssklower IFDEBUG(D_XPD) 12936413Ssklower dump_mbuf(tpcb->tp_Xsnd.sb_mb, 13036413Ssklower "tp_goodXack Xsnd before sbdrop"); 13136413Ssklower ENDDEBUG 13236413Ssklower 13336413Ssklower IFTRACE(D_XPD) 13436413Ssklower tptraceTPCB(TPPTmisc, 13536413Ssklower "goodXack: dropping cc ", 13636413Ssklower (int)(tpcb->tp_Xsnd.sb_cc), 13736413Ssklower 0,0,0); 13836413Ssklower ENDTRACE 13936413Ssklower sbdrop( &tpcb->tp_Xsnd, (int)(tpcb->tp_Xsnd.sb_cc)); 14036413Ssklower return 1; 14136413Ssklower } 14236413Ssklower return 0; 14336413Ssklower } 14436413Ssklower 14536413Ssklower /* 14636413Ssklower * CALLED FROM: 14736413Ssklower * tp_good_ack() 14836413Ssklower * FUNCTION and ARGUMENTS: 14936413Ssklower * updates 15036413Ssklower * smoothed average round trip time (base_rtt) 15136413Ssklower * roundtrip time variance (base_rtv) - actually deviation, not variance 15236413Ssklower * given the new value (diff) 15336413Ssklower * RETURN VALUE: 15436413Ssklower * void 15536413Ssklower */ 15636413Ssklower 15736413Ssklower void 15836413Ssklower tp_rtt_rtv( base_rtt, base_rtv, newmeas ) 15936413Ssklower struct timeval *base_rtt, *base_rtv, *newmeas; 16036413Ssklower { 16136413Ssklower /* update rt variance (really just the deviation): 16236413Ssklower * rtv.smooth_ave = SMOOTH( | oldrtt.smooth_avg - rtt.this_instance | ) 16336413Ssklower */ 16436413Ssklower base_rtv->tv_sec = 16536413Ssklower SMOOTH( long, TP_RTV_ALPHA, base_rtv->tv_sec, 16636413Ssklower ABS( long, base_rtv->tv_sec - newmeas->tv_sec )); 16736413Ssklower base_rtv->tv_usec = 16836413Ssklower SMOOTH( long, TP_RTV_ALPHA, base_rtv->tv_usec, 16936413Ssklower ABS(long, base_rtv->tv_usec - newmeas->tv_usec )); 17036413Ssklower 17136413Ssklower /* update smoothed average rtt */ 17236413Ssklower base_rtt->tv_sec = 17336413Ssklower SMOOTH( long, TP_RTT_ALPHA, base_rtt->tv_sec, newmeas->tv_sec); 17436413Ssklower base_rtt->tv_usec = 17536413Ssklower SMOOTH( long, TP_RTT_ALPHA, base_rtt->tv_usec, newmeas->tv_usec); 17636413Ssklower 17736413Ssklower } 17836413Ssklower 17936413Ssklower /* 18036413Ssklower * CALLED FROM: 18136413Ssklower * tp.trans when an AK arrives 18236413Ssklower * FUNCTION and ARGUMENTS: 18336413Ssklower * Given (cdt), the credit from the AK tpdu, and 18436413Ssklower * (seq), the sequence number from the AK tpdu, 18536413Ssklower * tp_goodack() determines if the AK acknowledges something in the send 18636413Ssklower * window, and if so, drops the appropriate packets from the retransmission 18736413Ssklower * list, computes the round trip time, and updates the retransmission timer 18836413Ssklower * based on the new smoothed round trip time. 18936413Ssklower * RETURN VALUE: 19036413Ssklower * Returns 1 if 19136413Ssklower * EITHER it actually acked something heretofore unacknowledged 19236413Ssklower * OR no news but the credit should be processed. 19336413Ssklower * If something heretofore unacked was acked with this sequence number, 19436413Ssklower * the appropriate tpdus are dropped from the retransmission control list, 19536413Ssklower * by calling tp_sbdrop(). 19636413Ssklower * No need to see the tpdu itself. 19736413Ssklower */ 19836413Ssklower int 19936413Ssklower tp_goodack(tpcb, cdt, seq, subseq) 20036413Ssklower register struct tp_pcb *tpcb; 20136413Ssklower u_int cdt; 20236413Ssklower register SeqNum seq, subseq; 20336413Ssklower { 20436413Ssklower int old_fcredit = tpcb->tp_fcredit; 20536413Ssklower int bang = 0; /* bang --> ack for something heretofore unacked */ 20636413Ssklower 20736413Ssklower IFDEBUG(D_ACKRECV) 20836413Ssklower printf("goodack seq 0x%x cdt 0x%x snduna 0x%x sndhiwat 0x%x\n", 20936413Ssklower seq, cdt, tpcb->tp_snduna, tpcb->tp_sndhiwat); 21036413Ssklower ENDDEBUG 21136413Ssklower IFTRACE(D_ACKRECV) 21236413Ssklower tptraceTPCB(TPPTgotack, 21336413Ssklower seq,cdt, tpcb->tp_snduna,tpcb->tp_sndhiwat,subseq); 21436413Ssklower ENDTRACE 21536413Ssklower 21636413Ssklower IFPERF(tpcb) 21737469Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0); 21836413Ssklower ENDPERF 21936413Ssklower 22036413Ssklower if ( subseq != 0 && (subseq <= tpcb->tp_r_subseq) ) { 22136413Ssklower /* discard the ack */ 22236413Ssklower IFTRACE(D_ACKRECV) 22336413Ssklower tptraceTPCB(TPPTmisc, "goodack discard : subseq tp_r_subseq", 22436413Ssklower subseq, tpcb->tp_r_subseq, 0, 0); 22536413Ssklower ENDTRACE 22636413Ssklower return 0; 22736413Ssklower } else { 22836413Ssklower tpcb->tp_r_subseq = subseq; 22936413Ssklower } 23036413Ssklower 23136413Ssklower if ( IN_SWINDOW(tpcb, seq, 23236413Ssklower tpcb->tp_snduna, SEQ(tpcb, tpcb->tp_sndhiwat+1)) ) { 23336413Ssklower 23436413Ssklower IFDEBUG(D_XPD) 23536413Ssklower dump_mbuf(tpcb->tp_sock->so_snd.sb_mb, 23636413Ssklower "tp_goodack snd before sbdrop"); 23736413Ssklower ENDDEBUG 23836413Ssklower tp_sbdrop(tpcb, SEQ_SUB(tpcb, seq, 1) ); 23936413Ssklower 24036413Ssklower /* increase congestion window but don't let it get too big */ 24136413Ssklower { 24236413Ssklower register int maxcdt = tpcb->tp_xtd_format?0xffff:0xf; 24336413Ssklower 24436413Ssklower if( ++tpcb->tp_cong_win > maxcdt ) 24536413Ssklower tpcb->tp_cong_win = maxcdt; 24636413Ssklower } 24736413Ssklower 24836413Ssklower /* Compute smoothed round trip time. 24936413Ssklower * Only measure rtt for tp_snduna if tp_snduna was among 25036413Ssklower * the last TP_RTT_NUM seq numbers sent. 25136413Ssklower */ 25236413Ssklower if (SEQ_GEQ(tpcb, tpcb->tp_snduna, 25336413Ssklower SEQ(tpcb, tpcb->tp_sndhiwat - TP_RTT_NUM))) { 25436413Ssklower 25536413Ssklower struct timeval *t = &tpcb->tp_rttemit[tpcb->tp_snduna & TP_RTT_NUM]; 25636413Ssklower struct timeval x; 25736413Ssklower 25836413Ssklower GET_TIME_SINCE(t, &x); 25936413Ssklower 26036413Ssklower tp_rtt_rtv( &(tpcb->tp_rtt), &(tpcb->tp_rtv), &x ); 26136413Ssklower 26236413Ssklower { /* update the global rtt, rtv stats */ 26336413Ssklower register int i = 26436413Ssklower (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN); 26536413Ssklower tp_rtt_rtv( &(tp_stat.ts_rtt[i]), &(tp_stat.ts_rtv[i]), &x ); 26636413Ssklower 26736413Ssklower IFTRACE(D_RTT) 26836413Ssklower tptraceTPCB(TPPTmisc, "Global rtt, rtv: i", i, 0, 0, 0); 26936413Ssklower ENDTRACE 27036413Ssklower } 27136413Ssklower 27236413Ssklower IFTRACE(D_RTT) 27336413Ssklower tptraceTPCB(TPPTmisc, 27436413Ssklower "Smoothed rtt: tp_snduna, (time.sec, time.usec), peer_acktime", 27536413Ssklower tpcb->tp_snduna, time.tv_sec, time.tv_usec, 27636413Ssklower tpcb->tp_peer_acktime); 27736413Ssklower 27836413Ssklower tptraceTPCB(TPPTmisc, 27936413Ssklower "(secs): emittime diff(x) rtt, rtv", 28036413Ssklower t->tv_sec, 28136413Ssklower x.tv_sec, 28236413Ssklower tpcb->tp_rtt.tv_sec, 28336413Ssklower tpcb->tp_rtv.tv_sec); 28436413Ssklower tptraceTPCB(TPPTmisc, 28536413Ssklower "(usecs): emittime diff(x) rtt rtv", 28636413Ssklower t->tv_usec, 28736413Ssklower x.tv_usec, 28836413Ssklower tpcb->tp_rtt.tv_usec, 28936413Ssklower tpcb->tp_rtv.tv_usec); 29036413Ssklower ENDTRACE 29136413Ssklower 29236413Ssklower { 29336413Ssklower /* Update data retransmission timer based on the smoothed 29436413Ssklower * round trip time, peer ack time, and the pseudo-arbitrary 29536413Ssklower * number 4. 29636413Ssklower * new ticks: avg rtt + 2*dev 29736413Ssklower * rtt, rtv are in microsecs, and ticks are 500 ms 29836413Ssklower * so 1 tick = 500*1000 us = 500000 us 29936413Ssklower * so ticks = (rtt + 2 rtv)/500000 30036413Ssklower * with ticks no les than peer ack time and no less than 4 30136413Ssklower */ 30236413Ssklower 30336413Ssklower int rtt = tpcb->tp_rtt.tv_usec + 30436413Ssklower tpcb->tp_rtt.tv_sec*1000000; 30536413Ssklower int rtv = tpcb->tp_rtv.tv_usec + 30636413Ssklower tpcb->tp_rtv.tv_sec*1000000; 30736413Ssklower 30836413Ssklower IFTRACE(D_RTT) 30936413Ssklower tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks", 31036413Ssklower tpcb->tp_dt_ticks, 31136413Ssklower rtv, rtt, 31236413Ssklower (rtt/500000 + (2 * rtv)/500000)); 31336413Ssklower ENDTRACE 31436413Ssklower tpcb->tp_dt_ticks = (rtt+ (2 * rtv))/500000; 31536413Ssklower tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks, 31636413Ssklower tpcb->tp_peer_acktime); 31736413Ssklower tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks, 4); 31836413Ssklower } 31936413Ssklower } 32036413Ssklower tpcb->tp_snduna = seq; 32136413Ssklower 32236413Ssklower bang++; 32336413Ssklower } 32436413Ssklower 32536413Ssklower if( cdt != 0 && old_fcredit == 0 ) { 32636413Ssklower tpcb->tp_sendfcc = 1; 32736413Ssklower } 32836413Ssklower if( cdt == 0 && old_fcredit != 0 ) { 32936413Ssklower IncStat(ts_zfcdt); 33036413Ssklower } 33136413Ssklower tpcb->tp_fcredit = cdt; 33236413Ssklower 33336413Ssklower IFDEBUG(D_ACKRECV) 33436413Ssklower printf("goodack returning 0x%x, bang 0x%x cdt 0x%x old_fcredit 0x%x\n", 33536413Ssklower (bang || (old_fcredit < cdt) ), bang, cdt, old_fcredit ); 33636413Ssklower ENDDEBUG 33736413Ssklower 33836413Ssklower return (bang || (old_fcredit < cdt)) ; 33936413Ssklower } 34036413Ssklower 34136413Ssklower /* 34236413Ssklower * CALLED FROM: 34336413Ssklower * tp_goodack() 34436413Ssklower * FUNCTION and ARGUMENTS: 34536413Ssklower * drops everything up TO and INCLUDING seq # (seq) 34636413Ssklower * from the retransmission queue. 34736413Ssklower */ 34836413Ssklower static void 34936413Ssklower tp_sbdrop(tpcb, seq) 35036413Ssklower struct tp_pcb *tpcb; 35136413Ssklower SeqNum seq; 35236413Ssklower { 35336413Ssklower register struct tp_rtc *s = tpcb->tp_snduna_rtc; 35436413Ssklower 35536413Ssklower IFDEBUG(D_ACKRECV) 35636413Ssklower printf("tp_sbdrop up through seq 0x%x\n", seq); 35736413Ssklower ENDDEBUG 35836413Ssklower while (s != (struct tp_rtc *)0 && (SEQ_LEQ(tpcb, s->tprt_seq, seq))) { 35936413Ssklower m_freem( s->tprt_data ); 36036413Ssklower tpcb->tp_snduna_rtc = s->tprt_next; 36136413Ssklower (void) m_free( dtom( s ) ); 36236413Ssklower s = tpcb->tp_snduna_rtc; 36336413Ssklower } 36436413Ssklower if(tpcb->tp_snduna_rtc == (struct tp_rtc *)0) 36536413Ssklower tpcb->tp_sndhiwat_rtc = (struct tp_rtc *) 0; 36636413Ssklower 36736413Ssklower } 36836413Ssklower 36936413Ssklower /* 37036413Ssklower * CALLED FROM: 37136413Ssklower * tp.trans on user send request, arrival of AK and arrival of XAK 37236413Ssklower * FUNCTION and ARGUMENTS: 37336413Ssklower * Emits tpdus starting at sequence number (lowseq). 37436413Ssklower * Emits until a) runs out of data, or b) runs into an XPD mark, or 37536413Ssklower * c) it hits seq number (highseq) 37636413Ssklower * Removes the octets from the front of the socket buffer 37736413Ssklower * and repackages them in one mbuf chain per tpdu. 37836413Ssklower * Moves the mbuf chain to the doubly linked list that runs from 37936413Ssklower * tpcb->tp_sndhiwat_rtc to tpcb->tp_snduna_rtc. 38036413Ssklower * 38136413Ssklower * Creates tpdus that are no larger than <tpcb->tp_l_tpdusize - headersize>, 38236413Ssklower * 38336413Ssklower * If you want XPD to buffer > 1 du per socket buffer, you can 38436413Ssklower * modifiy this to issue XPD tpdus also, but then it'll have 38536413Ssklower * to take some argument(s) to distinguish between the type of DU to 38636413Ssklower * hand tp_emit, the socket buffer from which to get the data, and 38736413Ssklower * the chain of tp_rtc structures on which to put the data sent. 38836413Ssklower * 38936413Ssklower * When something is sent for the first time, its time-of-send 39036413Ssklower * is stashed (the last RTT_NUM of them are stashed). When the 39136413Ssklower * ack arrives, the smoothed round-trip time is figured using this value. 39236413Ssklower * RETURN VALUE: 39336413Ssklower * the highest seq # sent successfully. 39436413Ssklower */ 39536413Ssklower tp_send(tpcb) 39636413Ssklower register struct tp_pcb *tpcb; 39736413Ssklower { 39836413Ssklower register int len; 39936413Ssklower register struct mbuf *m; /* the one we're inspecting now */ 40036413Ssklower struct mbuf *mb;/* beginning of this tpdu */ 40136413Ssklower struct mbuf *nextrecord; /* NOT next tpdu but next sb record */ 40236413Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 40336413Ssklower int maxsize = tpcb->tp_l_tpdusize 40436413Ssklower - tp_headersize(DT_TPDU_type, tpcb) 40536413Ssklower - (tpcb->tp_use_checksum?4:0) ; 40636413Ssklower unsigned int eotsdu_reached=0; 40736413Ssklower SeqNum lowseq, highseq ; 40836413Ssklower SeqNum lowsave; 40936413Ssklower #ifdef TP_PERF_MEAS 41036413Ssklower struct timeval send_start_time; 41136413Ssklower #endif TP_PERF_MEAS 41236413Ssklower 41336413Ssklower lowsave = lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1); 41436413Ssklower 41536413Ssklower ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff); 41636413Ssklower 41736413Ssklower if( tpcb->tp_rx_strat & TPRX_USE_CW ) { 41836413Ssklower /*first hiseq is temp vbl*/ 41936413Ssklower highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win); 42036413Ssklower } else { 42136413Ssklower highseq = tpcb->tp_fcredit; 42236413Ssklower } 42336413Ssklower highseq = SEQ(tpcb, tpcb->tp_snduna + highseq); 42436413Ssklower 42536413Ssklower SEQ_DEC(tpcb, highseq); 42636413Ssklower 42736413Ssklower IFDEBUG(D_DATA) 42836413Ssklower printf( 42936413Ssklower "tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n", 43036413Ssklower tpcb, lowseq, highseq); 43136413Ssklower dump_mbuf(sb->sb_mb, "sb_mb:"); 43236413Ssklower ENDDEBUG 43336413Ssklower IFTRACE(D_DATA) 43436413Ssklower tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna", 43536413Ssklower lowsave, tpcb->tp_sndhiwat, tpcb->tp_snduna, 0); 43636413Ssklower tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin", 43736413Ssklower lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); 43836413Ssklower ENDTRACE 43936413Ssklower 44036413Ssklower 44136413Ssklower if ( SEQ_GT(tpcb, lowseq, highseq) ) 44236413Ssklower return ; /* don't send, don't change hiwat, don't set timers */ 44336413Ssklower 44436413Ssklower IFPERF(tpcb) 44536413Ssklower GET_CUR_TIME(&send_start_time); 44636413Ssklower ENDPERF 44736413Ssklower 44836413Ssklower ASSERT( SEQ_LEQ(tpcb, lowseq, highseq) ); 44936413Ssklower SEQ_DEC(tpcb, lowseq); 45036413Ssklower 45136413Ssklower IFTRACE(D_DATA) 45236413Ssklower tptraceTPCB( TPPTmisc, "tp_send 2 low high fcredit congwin", 45336413Ssklower lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); 45436413Ssklower ENDTRACE 45536413Ssklower 456*38841Ssklower while ((SEQ_LT(tpcb, lowseq, highseq)) && (mb = m = sb->sb_mb)) { 45737469Ssklower if (tpcb->tp_Xsnd.sb_mb) { 45836413Ssklower IFTRACE(D_XPD) 45936413Ssklower tptraceTPCB( TPPTmisc, 46036413Ssklower "tp_send XPD mark low high tpcb.Xuna", 461*38841Ssklower lowseq, highseq, tpcb->tp_Xsnd.sb_mb, 0); 46236413Ssklower ENDTRACE 46337469Ssklower /* stop sending here because there are unacked XPD which were 46437469Ssklower * given to us before the next data were. 46537469Ssklower */ 46637469Ssklower IncStat(ts_xpd_intheway); 46737469Ssklower break; 46836413Ssklower } 46936413Ssklower eotsdu_reached = 0; 47036413Ssklower nextrecord = m->m_act; 47137469Ssklower for (len = 0; m; m = m->m_next) { 47236413Ssklower len += m->m_len; 47337469Ssklower if (m->m_flags & M_EOR) 47436413Ssklower eotsdu_reached = 1; 47536413Ssklower sbfree(sb, m); /* reduce counts in socket buffer */ 47636413Ssklower } 477*38841Ssklower sb->sb_mb = nextrecord; 47837469Ssklower IFTRACE(D_STASH) 47937469Ssklower tptraceTPCB(TPPTmisc, "tp_send whole mbuf: m_len len maxsize", 48037469Ssklower 0, mb->m_len, len, maxsize); 48137469Ssklower ENDTRACE 48236413Ssklower 48336413Ssklower if ( len == 0 && !eotsdu_reached) { 48436413Ssklower /* THIS SHOULD NEVER HAPPEN! */ 48536413Ssklower ASSERT( 0 ); 48636413Ssklower goto done; 48736413Ssklower } 48836413Ssklower 48936413Ssklower /* If we arrive here one of the following holds: 49036413Ssklower * 1. We have exactly <maxsize> octets of whole mbufs, 49136413Ssklower * 2. We accumulated <maxsize> octets using partial mbufs, 49236413Ssklower * 3. We found an TPMT_EOT or an XPD mark 49336413Ssklower * 4. We hit the end of a chain through m_next. 49436413Ssklower * In this case, we'd LIKE to continue with the next record, 49536413Ssklower * but for the time being, for simplicity, we'll stop here. 49636413Ssklower * In all cases, m points to mbuf containing first octet to be 49736413Ssklower * sent in the tpdu AFTER the one we're going to send now, 49836413Ssklower * or else m is null. 49936413Ssklower * 50036413Ssklower * The chain we're working on now begins at mb and has length <len>. 50136413Ssklower */ 50236413Ssklower 50336413Ssklower IFTRACE(D_STASH) 50436413Ssklower tptraceTPCB( TPPTmisc, 50536413Ssklower "tp_send mcopy low high eotsdu_reached len", 50636413Ssklower lowseq, highseq, eotsdu_reached, len); 50736413Ssklower ENDTRACE 50836413Ssklower 50936413Ssklower /* make a copy - mb goes into the retransmission list 51036413Ssklower * while m gets emitted. m_copy won't copy a zero-length mbuf. 51136413Ssklower */ 512*38841Ssklower if (len) { 513*38841Ssklower if ((m = m_copy(mb, 0, len )) == MNULL) 51436413Ssklower goto done; 51536413Ssklower } else { 51636413Ssklower /* eotsdu reached */ 51736413Ssklower MGET(m, M_WAIT, TPMT_DATA); 518*38841Ssklower if (m == MNULL) 51936413Ssklower goto done; 52036413Ssklower m->m_len = 0; 52136413Ssklower } 52236413Ssklower 52336413Ssklower SEQ_INC(tpcb,lowseq); /* it was decremented at the beginning */ 52436413Ssklower { 52536413Ssklower struct tp_rtc *t; 52636413Ssklower /* make an rtc and put it at the end of the chain */ 52736413Ssklower 52836413Ssklower TP_MAKE_RTC( t, lowseq, eotsdu_reached, mb, len, lowseq, 52936413Ssklower TPMT_SNDRTC); 53036413Ssklower t->tprt_next = (struct tp_rtc *)0; 53136413Ssklower 53236413Ssklower if ( tpcb->tp_sndhiwat_rtc != (struct tp_rtc *)0 ) 53336413Ssklower tpcb->tp_sndhiwat_rtc->tprt_next = t; 53436413Ssklower else { 53536413Ssklower ASSERT( tpcb->tp_snduna_rtc == (struct tp_rtc *)0 ); 53636413Ssklower tpcb->tp_snduna_rtc = t; 53736413Ssklower } 53836413Ssklower 53936413Ssklower tpcb->tp_sndhiwat_rtc = t; 54036413Ssklower } 54136413Ssklower 54236413Ssklower IFTRACE(D_DATA) 54336413Ssklower tptraceTPCB( TPPTmisc, 54436413Ssklower "tp_send emitting DT lowseq eotsdu_reached", 54536413Ssklower lowseq, eotsdu_reached, 0, 0); 54636413Ssklower ENDTRACE 54736413Ssklower if( tpcb->tp_sock->so_error = 54836413Ssklower tp_emit(DT_TPDU_type, tpcb, lowseq, eotsdu_reached, m) ) { 54936413Ssklower /* error */ 55036413Ssklower SEQ_DEC(tpcb, lowseq); 55136413Ssklower goto done; 55236413Ssklower } 55336413Ssklower /* set the transmit-time for computation of round-trip times */ 55436413Ssklower bcopy( (caddr_t)&time, 55536413Ssklower (caddr_t)&( tpcb->tp_rttemit[ lowseq & TP_RTT_NUM ] ), 55636413Ssklower sizeof(struct timeval)); 55736413Ssklower 55836413Ssklower } 55936413Ssklower 56036413Ssklower done: 56136413Ssklower IFPERF(tpcb) 56236413Ssklower { 56336413Ssklower register int npkts; 56436413Ssklower struct timeval send_end_time; 56536413Ssklower register struct timeval *t; 56636413Ssklower 56736413Ssklower npkts = lowseq; 56836413Ssklower SEQ_INC(tpcb, npkts); 56936413Ssklower npkts = SEQ_SUB(tpcb, npkts, lowsave); 57036413Ssklower 57136413Ssklower if(npkts > 0) 57236413Ssklower tpcb->tp_Nwindow++; 57336413Ssklower 57436413Ssklower if (npkts > TP_PM_MAX) 57536413Ssklower npkts = TP_PM_MAX; 57636413Ssklower 57736413Ssklower GET_TIME_SINCE(&send_start_time, &send_end_time); 57836413Ssklower t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); 57936413Ssklower t->tv_sec = 58036413Ssklower SMOOTH( long, TP_RTT_ALPHA, t->tv_sec, send_end_time.tv_sec); 58136413Ssklower t->tv_usec = 58236413Ssklower SMOOTH( long, TP_RTT_ALPHA, t->tv_usec, send_end_time.tv_usec); 58336413Ssklower 58436413Ssklower if ( SEQ_LT(tpcb, lowseq, highseq) ) { 58536413Ssklower IncPStat(tpcb, tps_win_lim_by_data[npkts] ); 58636413Ssklower } else { 58736413Ssklower IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); 58836413Ssklower /* not true with congestion-window being used */ 58936413Ssklower } 59036413Ssklower tpmeas( tpcb->tp_lref, 59136413Ssklower TPsbsend, &send_end_time, lowsave, tpcb->tp_Nwindow, npkts); 59236413Ssklower } 59336413Ssklower ENDPERF 59436413Ssklower 59536413Ssklower tpcb->tp_sndhiwat = lowseq; 59636413Ssklower 59736413Ssklower if ( SEQ_LEQ(tpcb, lowsave, tpcb->tp_sndhiwat) && 59836413Ssklower (tpcb->tp_class != TP_CLASS_0) ) 59936413Ssklower tp_etimeout(tpcb->tp_refp, TM_data_retrans, lowsave, 60036413Ssklower tpcb->tp_sndhiwat, 60136413Ssklower (u_int)tpcb->tp_Nretrans, (int)tpcb->tp_dt_ticks); 60236413Ssklower IFTRACE(D_DATA) 60336413Ssklower tptraceTPCB( TPPTmisc, 60436413Ssklower "tp_send at end: sndhiwat lowseq eotsdu_reached error", 60536413Ssklower tpcb->tp_sndhiwat, lowseq, eotsdu_reached, tpcb->tp_sock->so_error); 60636413Ssklower 60736413Ssklower ENDTRACE 60836413Ssklower } 60936413Ssklower 61036413Ssklower /* 61136413Ssklower * NAME: tp_stash() 61236413Ssklower * CALLED FROM: 61336413Ssklower * tp.trans on arrival of a DT tpdu 61436413Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 61536413Ssklower * Returns 1 if 61636413Ssklower * a) something new arrived and it's got eotsdu_reached bit on, 61736413Ssklower * b) this arrival was caused other out-of-sequence things to be 61836413Ssklower * accepted, or 61936413Ssklower * c) this arrival is the highest seq # for which we last gave credit 62036413Ssklower * (sender just sent a whole window) 62136413Ssklower * In other words, returns 1 if tp should send an ack immediately, 0 if 62236413Ssklower * the ack can wait a while. 62336413Ssklower * 62436413Ssklower * Note: this implementation no longer renegs on credit, (except 62536413Ssklower * when debugging option D_RENEG is on, for the purpose of testing 62636413Ssklower * ack subsequencing), so we don't need to check for incoming tpdus 62736413Ssklower * being in a reneged portion of the window. 62836413Ssklower */ 62936413Ssklower 63036413Ssklower int 63136413Ssklower tp_stash( tpcb, e ) 63236413Ssklower register struct tp_pcb *tpcb; 63336413Ssklower register struct tp_event *e; 63436413Ssklower { 63536413Ssklower register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; 63636413Ssklower /* 0--> delay acks until full window */ 63736413Ssklower /* 1--> ack each tpdu */ 63836413Ssklower int newrec = 0; 63936413Ssklower 64036413Ssklower #ifndef lint 64136413Ssklower #define E e->ATTR(DT_TPDU) 64236413Ssklower #else lint 64336413Ssklower #define E e->ev_union.EV_DT_TPDU 64436413Ssklower #endif lint 64536413Ssklower 64636413Ssklower if ( E.e_eot ) { 64736413Ssklower register struct mbuf *n = E.e_data; 64837469Ssklower n->m_flags |= M_EOR; 649*38841Ssklower n->m_act = 0; 65037469Ssklower } 65136413Ssklower IFDEBUG(D_STASH) 65236413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 65336413Ssklower "stash: so_rcv before appending"); 65436413Ssklower dump_mbuf(E.e_data, 65536413Ssklower "stash: e_data before appending"); 65636413Ssklower ENDDEBUG 65736413Ssklower 65836413Ssklower IFPERF(tpcb) 65936413Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen; 66036413Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 66137469Ssklower E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); 66236413Ssklower ENDPERF 66336413Ssklower 66436413Ssklower if( E.e_seq == tpcb->tp_rcvnxt ) { 66536413Ssklower 66636413Ssklower IFDEBUG(D_STASH) 66736413Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", 66836413Ssklower E.e_seq, E.e_datalen, E.e_eot); 66936413Ssklower ENDDEBUG 67036413Ssklower 67136413Ssklower IFTRACE(D_STASH) 67236413Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 67336413Ssklower E.e_seq, E.e_datalen, E.e_eot, 0); 67436413Ssklower ENDTRACE 67536413Ssklower 67637469Ssklower sbappend(&tpcb->tp_sock->so_rcv, E.e_data); 67737469Ssklower 67836413Ssklower if (newrec = E.e_eot ) /* ASSIGNMENT */ 67936413Ssklower ack_reason |= ACK_EOT; 68036413Ssklower 68136413Ssklower SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 68236413Ssklower /* 68336413Ssklower * move chains from the rtc list to the socket buffer 68436413Ssklower * and free the rtc header 68536413Ssklower */ 68636413Ssklower { 68736413Ssklower register struct tp_rtc **r = &tpcb->tp_rcvnxt_rtc; 68836413Ssklower register struct tp_rtc *s = tpcb->tp_rcvnxt_rtc; 68936413Ssklower 69036413Ssklower while (s != (struct tp_rtc *)0 && s->tprt_seq == tpcb->tp_rcvnxt) { 69136413Ssklower *r = s->tprt_next; 69236413Ssklower 69337469Ssklower sbappend(&tpcb->tp_sock->so_rcv, s->tprt_data); 69436413Ssklower 69536413Ssklower SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 69636413Ssklower 69736413Ssklower (void) m_free( dtom( s ) ); 69836413Ssklower s = *r; 69936413Ssklower ack_reason |= ACK_REORDER; 70036413Ssklower } 70136413Ssklower } 70236413Ssklower IFDEBUG(D_STASH) 70336413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 70436413Ssklower "stash: so_rcv after appending"); 70536413Ssklower ENDDEBUG 70636413Ssklower 70736413Ssklower } else { 70836413Ssklower register struct tp_rtc **s = &tpcb->tp_rcvnxt_rtc; 70936413Ssklower register struct tp_rtc *r = tpcb->tp_rcvnxt_rtc; 71036413Ssklower register struct tp_rtc *t; 71136413Ssklower 71236413Ssklower IFTRACE(D_STASH) 71336413Ssklower tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", 71436413Ssklower E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); 71536413Ssklower ENDTRACE 71636413Ssklower 71736413Ssklower r = tpcb->tp_rcvnxt_rtc; 71836413Ssklower while (r != (struct tp_rtc *)0 && SEQ_LT(tpcb, r->tprt_seq, E.e_seq)) { 71936413Ssklower s = &r->tprt_next; 72036413Ssklower r = r->tprt_next; 72136413Ssklower } 72236413Ssklower 72336413Ssklower if (r == (struct tp_rtc *)0 || SEQ_GT(tpcb, r->tprt_seq, E.e_seq) ) { 72436413Ssklower IncStat(ts_dt_ooo); 72536413Ssklower 72636413Ssklower IFTRACE(D_STASH) 72736413Ssklower tptrace(TPPTmisc, 72836413Ssklower "tp_stash OUT OF ORDER- MAKE RTC: seq, 1st seq in list\n", 72936413Ssklower E.e_seq, r->tprt_seq,0,0); 73036413Ssklower ENDTRACE 73136413Ssklower IFDEBUG(D_STASH) 73236413Ssklower printf("tp_stash OUT OF ORDER- MAKE RTC\n"); 73336413Ssklower ENDDEBUG 73436413Ssklower TP_MAKE_RTC(t, E.e_seq, E.e_eot, E.e_data, E.e_datalen, 0, 73536413Ssklower TPMT_RCVRTC); 73636413Ssklower 73736413Ssklower *s = t; 73836413Ssklower t->tprt_next = (struct tp_rtc *)r; 73936413Ssklower ack_reason = ACK_DONT; 74036413Ssklower goto done; 74136413Ssklower } else { 74236413Ssklower IFDEBUG(D_STASH) 74336413Ssklower printf("tp_stash - drop & ack\n"); 74436413Ssklower ENDDEBUG 74536413Ssklower 74636413Ssklower /* retransmission - drop it and force an ack */ 74736413Ssklower IncStat(ts_dt_dup); 74836413Ssklower IFPERF(tpcb) 74936413Ssklower IncPStat(tpcb, tps_n_ack_cuz_dup); 75036413Ssklower ENDPERF 75136413Ssklower 75236413Ssklower m_freem( E.e_data ); 75336413Ssklower ack_reason |= ACK_DUP; 75436413Ssklower goto done; 75536413Ssklower } 75636413Ssklower } 75736413Ssklower 75836413Ssklower 75936413Ssklower /* 76036413Ssklower * an ack should be sent when at least one of the 76136413Ssklower * following holds: 76236413Ssklower * a) we've received a TPDU with EOTSDU set 76336413Ssklower * b) the TPDU that just arrived represents the 76436413Ssklower * full window last advertised, or 76536413Ssklower * c) when seq X arrives [ where 76636413Ssklower * X = last_sent_uwe - 1/2 last_lcredit_sent 76736413Ssklower * (the packet representing 1/2 the last advertised window) ] 76836413Ssklower * and lcredit at the time of X arrival > last_lcredit_sent/2 76936413Ssklower * In other words, if the last ack sent advertised cdt=8 and uwe = 8 77036413Ssklower * then when seq 4 arrives I'd like to send a new ack 77136413Ssklower * iff the credit at the time of 4's arrival is > 4. 77236413Ssklower * The other end thinks it has cdt of 4 so if local cdt 77336413Ssklower * is still 4 there's no point in sending an ack, but if 77436413Ssklower * my credit has increased because the receiver has taken 77536413Ssklower * some data out of the buffer (soreceive doesn't notify 77636413Ssklower * me until the SYSTEM CALL finishes), I'd like to tell 77736413Ssklower * the other end. 77836413Ssklower */ 77936413Ssklower 78036413Ssklower done: 78136413Ssklower { 78236413Ssklower LOCAL_CREDIT(tpcb); 78336413Ssklower 78436413Ssklower if ( E.e_seq == tpcb->tp_sent_uwe ) 78536413Ssklower ack_reason |= ACK_STRAT_FULLWIN; 78636413Ssklower 78736413Ssklower IFTRACE(D_STASH) 78836413Ssklower tptraceTPCB(TPPTmisc, 78936413Ssklower "end of stash, eot, ack_reason, sent_uwe ", 79036413Ssklower E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); 79136413Ssklower ENDTRACE 79236413Ssklower 79336413Ssklower if ( ack_reason == ACK_DONT ) { 79436413Ssklower IncStat( ts_ackreason[ACK_DONT] ); 79536413Ssklower return 0; 79636413Ssklower } else { 79736413Ssklower IFPERF(tpcb) 79836413Ssklower if(ack_reason & ACK_EOT) { 79936413Ssklower IncPStat(tpcb, tps_n_ack_cuz_eot); 80036413Ssklower } 80136413Ssklower if(ack_reason & ACK_STRAT_EACH) { 80236413Ssklower IncPStat(tpcb, tps_n_ack_cuz_strat); 80336413Ssklower } else if(ack_reason & ACK_STRAT_FULLWIN) { 80436413Ssklower IncPStat(tpcb, tps_n_ack_cuz_fullwin); 80536413Ssklower } else if(ack_reason & ACK_REORDER) { 80636413Ssklower IncPStat(tpcb, tps_n_ack_cuz_reorder); 80736413Ssklower } 80836413Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, 80936413Ssklower SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); 81036413Ssklower ENDPERF 81136413Ssklower { 81236413Ssklower register int i; 81336413Ssklower 81436413Ssklower /* keep track of all reasons that apply */ 81536413Ssklower for( i=1; i<_ACK_NUM_REASONS_ ;i++) { 81636413Ssklower if( ack_reason & (1<<i) ) 81736413Ssklower IncStat( ts_ackreason[i] ); 81836413Ssklower } 81936413Ssklower } 82036413Ssklower return 1; 82136413Ssklower } 82236413Ssklower } 82336413Ssklower } 82436413Ssklower 82536413Ssklower /* class zero version */ 82636413Ssklower void 82736413Ssklower tp0_stash( tpcb, e ) 82836413Ssklower register struct tp_pcb *tpcb; 82936413Ssklower register struct tp_event *e; 83036413Ssklower { 83136413Ssklower #ifndef lint 83236413Ssklower #define E e->ATTR(DT_TPDU) 83336413Ssklower #else lint 83436413Ssklower #define E e->ev_union.EV_DT_TPDU 83536413Ssklower #endif lint 83636413Ssklower 83736413Ssklower IFPERF(tpcb) 83836413Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen; 83936413Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 84036413Ssklower E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen); 84136413Ssklower ENDPERF 84236413Ssklower 84336413Ssklower IFDEBUG(D_STASH) 84436413Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x", 84536413Ssklower E.e_seq, E.e_datalen, E.e_eot); 84636413Ssklower ENDDEBUG 84736413Ssklower 84836413Ssklower IFTRACE(D_STASH) 84936413Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 85036413Ssklower E.e_seq, E.e_datalen, E.e_eot, 0); 85136413Ssklower ENDTRACE 85236413Ssklower 85336413Ssklower if ( E.e_eot ) { 85436413Ssklower register struct mbuf *n = E.e_data; 855*38841Ssklower n->m_flags |= M_EOR; 85636413Ssklower n->m_act = MNULL; /* set on tp_input */ 85736413Ssklower } 858*38841Ssklower sbappend(&tpcb->tp_sock->so_rcv, E.e_data); 85936413Ssklower IFDEBUG(D_STASH) 86036413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 86136413Ssklower "stash 0: so_rcv after appending"); 86236413Ssklower ENDDEBUG 86336413Ssklower } 864