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