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