1*49268Sbostic /*- 2*49268Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*49268Sbostic * All rights reserved. 4*49268Sbostic * 5*49268Sbostic * %sccs.include.redist.c% 6*49268Sbostic * 7*49268Sbostic * @(#)tp_subr.c 7.8 (Berkeley) 05/06/91 8*49268Sbostic */ 9*49268Sbostic 1036413Ssklower /*********************************************************** 1136413Ssklower Copyright IBM Corporation 1987 1236413Ssklower 1336413Ssklower All Rights Reserved 1436413Ssklower 1536413Ssklower Permission to use, copy, modify, and distribute this software and its 1636413Ssklower documentation for any purpose and without fee is hereby granted, 1736413Ssklower provided that the above copyright notice appear in all copies and that 1836413Ssklower both that copyright notice and this permission notice appear in 1936413Ssklower supporting documentation, and that the name of IBM not be 2036413Ssklower used in advertising or publicity pertaining to distribution of the 2136413Ssklower software without specific, written prior permission. 2236413Ssklower 2336413Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2436413Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2536413Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2636413Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2736413Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2836413Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2936413Ssklower SOFTWARE. 3036413Ssklower 3136413Ssklower ******************************************************************/ 3236413Ssklower 3336413Ssklower /* 3436413Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3536413Ssklower */ 3636413Ssklower /* 3736413Ssklower * ARGO TP 3836413Ssklower * 3936413Ssklower * $Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $ 4036413Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_subr.c,v $ 4136413Ssklower * 4236413Ssklower * The main work of data transfer is done here. 4336413Ssklower * These routines are called from tp.trans. 4436413Ssklower * They include the routines that check the validity of acks and Xacks, 4536413Ssklower * (tp_goodack() and tp_goodXack() ) 4636413Ssklower * take packets from socket buffers and send them (tp_send()), 4736413Ssklower * drop the data from the socket buffers (tp_sbdrop()), 4836413Ssklower * and put incoming packet data into socket buffers (tp_stash()). 4936413Ssklower */ 5036413Ssklower 5136413Ssklower #include "param.h" 5236413Ssklower #include "mbuf.h" 5336413Ssklower #include "socket.h" 5436413Ssklower #include "socketvar.h" 5536413Ssklower #include "protosw.h" 5636413Ssklower #include "errno.h" 5736413Ssklower #include "types.h" 5836413Ssklower #include "time.h" 5936413Ssklower 6037469Ssklower #include "tp_ip.h" 6137469Ssklower #include "iso.h" 6237469Ssklower #include "argo_debug.h" 6337469Ssklower #include "tp_timer.h" 6437469Ssklower #include "tp_param.h" 6537469Ssklower #include "tp_stat.h" 6637469Ssklower #include "tp_pcb.h" 6737469Ssklower #include "tp_tpdu.h" 6837469Ssklower #include "tp_trace.h" 6937469Ssklower #include "tp_meas.h" 7037469Ssklower #include "tp_seq.h" 7136413Ssklower 7236413Ssklower int tp_emit(); 7336413Ssklower static void tp_sbdrop(); 7436413Ssklower 7536413Ssklower #define SMOOTH(newtype, alpha, old, new) \ 7636413Ssklower (newtype) (((new - old)>>alpha) + (old)) 7736413Ssklower 7836413Ssklower #define ABS(type, val) \ 7936413Ssklower (type) (((int)(val)<0)?-(val):(val)) 8036413Ssklower 8136413Ssklower #define TP_MAKE_RTC( Xreg, Xseq, Xeot, Xdata, Xlen, Xretval, Xtype) \ 8236413Ssklower { struct mbuf *xxn;\ 8336413Ssklower MGET(xxn, M_DONTWAIT, Xtype);\ 8436413Ssklower if( xxn == (struct mbuf *)0 ) {\ 8536413Ssklower printf("MAKE RTC FAILED: ENOBUFS\n");\ 8636413Ssklower return (int)Xretval;\ 8736413Ssklower }\ 8836413Ssklower xxn->m_act=MNULL;\ 8936413Ssklower Xreg = mtod(xxn, struct tp_rtc *);\ 9036413Ssklower if( Xreg == (struct tp_rtc *)0 ) {\ 9136413Ssklower return (int)Xretval;\ 9236413Ssklower }\ 9336413Ssklower Xreg->tprt_eot = Xeot;\ 9436413Ssklower Xreg->tprt_seq = Xseq;\ 9536413Ssklower Xreg->tprt_data = Xdata;\ 9636413Ssklower Xreg->tprt_octets = Xlen;\ 9736413Ssklower } 9836413Ssklower 9936413Ssklower 10036413Ssklower /* 10136413Ssklower * CALLED FROM: 10236413Ssklower * tp.trans, when an XAK arrives 10336413Ssklower * FUNCTION and ARGUMENTS: 10436413Ssklower * Determines if the sequence number (seq) from the XAK 10536413Ssklower * acks anything new. If so, drop the appropriate tpdu 10636413Ssklower * from the XPD send queue. 10736413Ssklower * RETURN VALUE: 10836413Ssklower * Returns 1 if it did this, 0 if the ack caused no action. 10936413Ssklower */ 11036413Ssklower int 11136413Ssklower tp_goodXack(tpcb, seq) 11236413Ssklower struct tp_pcb *tpcb; 11336413Ssklower SeqNum seq; 11436413Ssklower { 11536413Ssklower 11636413Ssklower IFTRACE(D_XPD) 11736413Ssklower tptraceTPCB(TPPTgotXack, 11836413Ssklower seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndhiwat, 11936413Ssklower tpcb->tp_snduna); 12036413Ssklower ENDTRACE 12136413Ssklower 12236413Ssklower if ( seq == tpcb->tp_Xuna ) { 12336413Ssklower tpcb->tp_Xuna = tpcb->tp_Xsndnxt; 12436413Ssklower 12536413Ssklower /* DROP 1 packet from the Xsnd socket buf - just so happens 12636413Ssklower * that only one packet can be there at any time 12736413Ssklower * so drop the whole thing. If you allow > 1 packet 12836413Ssklower * the socket buffer, then you'll have to keep 12936413Ssklower * track of how many characters went w/ each XPD tpdu, so this 13036413Ssklower * will get messier 13136413Ssklower */ 13236413Ssklower IFDEBUG(D_XPD) 13336413Ssklower dump_mbuf(tpcb->tp_Xsnd.sb_mb, 13436413Ssklower "tp_goodXack Xsnd before sbdrop"); 13536413Ssklower ENDDEBUG 13636413Ssklower 13736413Ssklower IFTRACE(D_XPD) 13836413Ssklower tptraceTPCB(TPPTmisc, 13936413Ssklower "goodXack: dropping cc ", 14036413Ssklower (int)(tpcb->tp_Xsnd.sb_cc), 14136413Ssklower 0,0,0); 14236413Ssklower ENDTRACE 14336413Ssklower sbdrop( &tpcb->tp_Xsnd, (int)(tpcb->tp_Xsnd.sb_cc)); 14439922Ssklower CONG_ACK(tpcb, seq); 14536413Ssklower return 1; 14636413Ssklower } 14736413Ssklower return 0; 14836413Ssklower } 14936413Ssklower 15036413Ssklower /* 15136413Ssklower * CALLED FROM: 15236413Ssklower * tp_good_ack() 15336413Ssklower * FUNCTION and ARGUMENTS: 15436413Ssklower * updates 15536413Ssklower * smoothed average round trip time (base_rtt) 15636413Ssklower * roundtrip time variance (base_rtv) - actually deviation, not variance 15736413Ssklower * given the new value (diff) 15836413Ssklower * RETURN VALUE: 15936413Ssklower * void 16036413Ssklower */ 16136413Ssklower 16236413Ssklower void 16336413Ssklower tp_rtt_rtv( base_rtt, base_rtv, newmeas ) 16436413Ssklower struct timeval *base_rtt, *base_rtv, *newmeas; 16536413Ssklower { 16636413Ssklower /* update rt variance (really just the deviation): 16736413Ssklower * rtv.smooth_ave = SMOOTH( | oldrtt.smooth_avg - rtt.this_instance | ) 16836413Ssklower */ 16936413Ssklower base_rtv->tv_sec = 17036413Ssklower SMOOTH( long, TP_RTV_ALPHA, base_rtv->tv_sec, 17144948Ssklower ABS( long, base_rtt->tv_sec - newmeas->tv_sec )); 17236413Ssklower base_rtv->tv_usec = 17336413Ssklower SMOOTH( long, TP_RTV_ALPHA, base_rtv->tv_usec, 17444948Ssklower ABS(long, base_rtt->tv_usec - newmeas->tv_usec )); 17536413Ssklower 17636413Ssklower /* update smoothed average rtt */ 17736413Ssklower base_rtt->tv_sec = 17836413Ssklower SMOOTH( long, TP_RTT_ALPHA, base_rtt->tv_sec, newmeas->tv_sec); 17936413Ssklower base_rtt->tv_usec = 18036413Ssklower SMOOTH( long, TP_RTT_ALPHA, base_rtt->tv_usec, newmeas->tv_usec); 18136413Ssklower 18236413Ssklower } 18336413Ssklower 18436413Ssklower /* 18536413Ssklower * CALLED FROM: 18636413Ssklower * tp.trans when an AK arrives 18736413Ssklower * FUNCTION and ARGUMENTS: 18836413Ssklower * Given (cdt), the credit from the AK tpdu, and 18936413Ssklower * (seq), the sequence number from the AK tpdu, 19036413Ssklower * tp_goodack() determines if the AK acknowledges something in the send 19136413Ssklower * window, and if so, drops the appropriate packets from the retransmission 19236413Ssklower * list, computes the round trip time, and updates the retransmission timer 19336413Ssklower * based on the new smoothed round trip time. 19436413Ssklower * RETURN VALUE: 19536413Ssklower * Returns 1 if 19636413Ssklower * EITHER it actually acked something heretofore unacknowledged 19736413Ssklower * OR no news but the credit should be processed. 19836413Ssklower * If something heretofore unacked was acked with this sequence number, 19936413Ssklower * the appropriate tpdus are dropped from the retransmission control list, 20036413Ssklower * by calling tp_sbdrop(). 20136413Ssklower * No need to see the tpdu itself. 20236413Ssklower */ 20336413Ssklower int 20436413Ssklower tp_goodack(tpcb, cdt, seq, subseq) 20536413Ssklower register struct tp_pcb *tpcb; 20636413Ssklower u_int cdt; 20736413Ssklower register SeqNum seq, subseq; 20836413Ssklower { 20936413Ssklower int old_fcredit = tpcb->tp_fcredit; 21036413Ssklower int bang = 0; /* bang --> ack for something heretofore unacked */ 21136413Ssklower 21236413Ssklower IFDEBUG(D_ACKRECV) 21336413Ssklower printf("goodack seq 0x%x cdt 0x%x snduna 0x%x sndhiwat 0x%x\n", 21436413Ssklower seq, cdt, tpcb->tp_snduna, tpcb->tp_sndhiwat); 21536413Ssklower ENDDEBUG 21636413Ssklower IFTRACE(D_ACKRECV) 21736413Ssklower tptraceTPCB(TPPTgotack, 21836413Ssklower seq,cdt, tpcb->tp_snduna,tpcb->tp_sndhiwat,subseq); 21936413Ssklower ENDTRACE 22036413Ssklower 22136413Ssklower IFPERF(tpcb) 22237469Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0); 22336413Ssklower ENDPERF 22436413Ssklower 22536413Ssklower if ( subseq != 0 && (subseq <= tpcb->tp_r_subseq) ) { 22636413Ssklower /* discard the ack */ 22736413Ssklower IFTRACE(D_ACKRECV) 22836413Ssklower tptraceTPCB(TPPTmisc, "goodack discard : subseq tp_r_subseq", 22936413Ssklower subseq, tpcb->tp_r_subseq, 0, 0); 23036413Ssklower ENDTRACE 23136413Ssklower return 0; 23236413Ssklower } else { 23336413Ssklower tpcb->tp_r_subseq = subseq; 23436413Ssklower } 23536413Ssklower 23636413Ssklower if ( IN_SWINDOW(tpcb, seq, 23736413Ssklower tpcb->tp_snduna, SEQ(tpcb, tpcb->tp_sndhiwat+1)) ) { 23836413Ssklower 23936413Ssklower IFDEBUG(D_XPD) 24036413Ssklower dump_mbuf(tpcb->tp_sock->so_snd.sb_mb, 24136413Ssklower "tp_goodack snd before sbdrop"); 24236413Ssklower ENDDEBUG 24336413Ssklower tp_sbdrop(tpcb, SEQ_SUB(tpcb, seq, 1) ); 24436413Ssklower 24536413Ssklower /* increase congestion window but don't let it get too big */ 24636413Ssklower { 24736413Ssklower register int maxcdt = tpcb->tp_xtd_format?0xffff:0xf; 24839922Ssklower CONG_ACK(tpcb, seq); 24936413Ssklower } 25036413Ssklower 25136413Ssklower /* Compute smoothed round trip time. 25236413Ssklower * Only measure rtt for tp_snduna if tp_snduna was among 25339922Ssklower * the last TP_RTT_NUM seq numbers sent, and if the data 25439922Ssklower * were not retransmitted. 25536413Ssklower */ 25636413Ssklower if (SEQ_GEQ(tpcb, tpcb->tp_snduna, 25739922Ssklower SEQ(tpcb, tpcb->tp_sndhiwat - TP_RTT_NUM)) 25839922Ssklower && SEQ_GT(tpcb, seq, SEQ_ADD(tpcb, tpcb->tp_retrans_hiwat, 1))) { 25936413Ssklower 26036413Ssklower struct timeval *t = &tpcb->tp_rttemit[tpcb->tp_snduna & TP_RTT_NUM]; 26136413Ssklower struct timeval x; 26236413Ssklower 26336413Ssklower GET_TIME_SINCE(t, &x); 26436413Ssklower 26536413Ssklower tp_rtt_rtv( &(tpcb->tp_rtt), &(tpcb->tp_rtv), &x ); 26636413Ssklower 26736413Ssklower { /* update the global rtt, rtv stats */ 26836413Ssklower register int i = 26936413Ssklower (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN); 27036413Ssklower tp_rtt_rtv( &(tp_stat.ts_rtt[i]), &(tp_stat.ts_rtv[i]), &x ); 27136413Ssklower 27236413Ssklower IFTRACE(D_RTT) 27336413Ssklower tptraceTPCB(TPPTmisc, "Global rtt, rtv: i", i, 0, 0, 0); 27436413Ssklower ENDTRACE 27536413Ssklower } 27636413Ssklower 27736413Ssklower IFTRACE(D_RTT) 27836413Ssklower tptraceTPCB(TPPTmisc, 27936413Ssklower "Smoothed rtt: tp_snduna, (time.sec, time.usec), peer_acktime", 28036413Ssklower tpcb->tp_snduna, time.tv_sec, time.tv_usec, 28136413Ssklower tpcb->tp_peer_acktime); 28236413Ssklower 28336413Ssklower tptraceTPCB(TPPTmisc, 28436413Ssklower "(secs): emittime diff(x) rtt, rtv", 28536413Ssklower t->tv_sec, 28636413Ssklower x.tv_sec, 28736413Ssklower tpcb->tp_rtt.tv_sec, 28836413Ssklower tpcb->tp_rtv.tv_sec); 28936413Ssklower tptraceTPCB(TPPTmisc, 29036413Ssklower "(usecs): emittime diff(x) rtt rtv", 29136413Ssklower t->tv_usec, 29236413Ssklower x.tv_usec, 29336413Ssklower tpcb->tp_rtt.tv_usec, 29436413Ssklower tpcb->tp_rtv.tv_usec); 29536413Ssklower ENDTRACE 29636413Ssklower 29736413Ssklower { 29836413Ssklower /* Update data retransmission timer based on the smoothed 29936413Ssklower * round trip time, peer ack time, and the pseudo-arbitrary 30036413Ssklower * number 4. 30136413Ssklower * new ticks: avg rtt + 2*dev 30236413Ssklower * rtt, rtv are in microsecs, and ticks are 500 ms 30336413Ssklower * so 1 tick = 500*1000 us = 500000 us 30436413Ssklower * so ticks = (rtt + 2 rtv)/500000 30536413Ssklower * with ticks no les than peer ack time and no less than 4 30636413Ssklower */ 30736413Ssklower 30836413Ssklower int rtt = tpcb->tp_rtt.tv_usec + 30936413Ssklower tpcb->tp_rtt.tv_sec*1000000; 31036413Ssklower int rtv = tpcb->tp_rtv.tv_usec + 31136413Ssklower tpcb->tp_rtv.tv_sec*1000000; 31236413Ssklower 31336413Ssklower IFTRACE(D_RTT) 31436413Ssklower tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks", 31536413Ssklower tpcb->tp_dt_ticks, 31636413Ssklower rtv, rtt, 31736413Ssklower (rtt/500000 + (2 * rtv)/500000)); 31836413Ssklower ENDTRACE 31936413Ssklower tpcb->tp_dt_ticks = (rtt+ (2 * rtv))/500000; 32036413Ssklower tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks, 32136413Ssklower tpcb->tp_peer_acktime); 32236413Ssklower tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks, 4); 32336413Ssklower } 32436413Ssklower } 32536413Ssklower tpcb->tp_snduna = seq; 32639922Ssklower tpcb->tp_retrans = tpcb->tp_Nretrans; /* CE_BIT */ 32736413Ssklower 32836413Ssklower bang++; 32936413Ssklower } 33036413Ssklower 33136413Ssklower if( cdt != 0 && old_fcredit == 0 ) { 33236413Ssklower tpcb->tp_sendfcc = 1; 33336413Ssklower } 33436413Ssklower if( cdt == 0 && old_fcredit != 0 ) { 33536413Ssklower IncStat(ts_zfcdt); 33636413Ssklower } 33736413Ssklower tpcb->tp_fcredit = cdt; 33836413Ssklower 33936413Ssklower IFDEBUG(D_ACKRECV) 34036413Ssklower printf("goodack returning 0x%x, bang 0x%x cdt 0x%x old_fcredit 0x%x\n", 34136413Ssklower (bang || (old_fcredit < cdt) ), bang, cdt, old_fcredit ); 34236413Ssklower ENDDEBUG 34336413Ssklower 34436413Ssklower return (bang || (old_fcredit < cdt)) ; 34536413Ssklower } 34636413Ssklower 34736413Ssklower /* 34836413Ssklower * CALLED FROM: 34936413Ssklower * tp_goodack() 35036413Ssklower * FUNCTION and ARGUMENTS: 35136413Ssklower * drops everything up TO and INCLUDING seq # (seq) 35236413Ssklower * from the retransmission queue. 35336413Ssklower */ 35436413Ssklower static void 35536413Ssklower tp_sbdrop(tpcb, seq) 35636413Ssklower struct tp_pcb *tpcb; 35736413Ssklower SeqNum seq; 35836413Ssklower { 35936413Ssklower register struct tp_rtc *s = tpcb->tp_snduna_rtc; 36036413Ssklower 36136413Ssklower IFDEBUG(D_ACKRECV) 36236413Ssklower printf("tp_sbdrop up through seq 0x%x\n", seq); 36336413Ssklower ENDDEBUG 36436413Ssklower while (s != (struct tp_rtc *)0 && (SEQ_LEQ(tpcb, s->tprt_seq, seq))) { 36536413Ssklower m_freem( s->tprt_data ); 36636413Ssklower tpcb->tp_snduna_rtc = s->tprt_next; 36736413Ssklower (void) m_free( dtom( s ) ); 36836413Ssklower s = tpcb->tp_snduna_rtc; 36936413Ssklower } 37036413Ssklower if(tpcb->tp_snduna_rtc == (struct tp_rtc *)0) 37136413Ssklower tpcb->tp_sndhiwat_rtc = (struct tp_rtc *) 0; 37236413Ssklower 37336413Ssklower } 37436413Ssklower 37536413Ssklower /* 37636413Ssklower * CALLED FROM: 37736413Ssklower * tp.trans on user send request, arrival of AK and arrival of XAK 37836413Ssklower * FUNCTION and ARGUMENTS: 37936413Ssklower * Emits tpdus starting at sequence number (lowseq). 38036413Ssklower * Emits until a) runs out of data, or b) runs into an XPD mark, or 38136413Ssklower * c) it hits seq number (highseq) 38236413Ssklower * Removes the octets from the front of the socket buffer 38336413Ssklower * and repackages them in one mbuf chain per tpdu. 38436413Ssklower * Moves the mbuf chain to the doubly linked list that runs from 38536413Ssklower * tpcb->tp_sndhiwat_rtc to tpcb->tp_snduna_rtc. 38636413Ssklower * 38736413Ssklower * Creates tpdus that are no larger than <tpcb->tp_l_tpdusize - headersize>, 38836413Ssklower * 38936413Ssklower * If you want XPD to buffer > 1 du per socket buffer, you can 39036413Ssklower * modifiy this to issue XPD tpdus also, but then it'll have 39136413Ssklower * to take some argument(s) to distinguish between the type of DU to 39236413Ssklower * hand tp_emit, the socket buffer from which to get the data, and 39336413Ssklower * the chain of tp_rtc structures on which to put the data sent. 39436413Ssklower * 39536413Ssklower * When something is sent for the first time, its time-of-send 39636413Ssklower * is stashed (the last RTT_NUM of them are stashed). When the 39736413Ssklower * ack arrives, the smoothed round-trip time is figured using this value. 39836413Ssklower * RETURN VALUE: 39936413Ssklower * the highest seq # sent successfully. 40036413Ssklower */ 40136413Ssklower tp_send(tpcb) 40236413Ssklower register struct tp_pcb *tpcb; 40336413Ssklower { 40436413Ssklower register int len; 40536413Ssklower register struct mbuf *m; /* the one we're inspecting now */ 40636413Ssklower struct mbuf *mb;/* beginning of this tpdu */ 40736413Ssklower struct mbuf *nextrecord; /* NOT next tpdu but next sb record */ 40836413Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 40936413Ssklower int maxsize = tpcb->tp_l_tpdusize 41036413Ssklower - tp_headersize(DT_TPDU_type, tpcb) 41136413Ssklower - (tpcb->tp_use_checksum?4:0) ; 41236413Ssklower unsigned int eotsdu_reached=0; 41336413Ssklower SeqNum lowseq, highseq ; 41436413Ssklower SeqNum lowsave; 41536413Ssklower #ifdef TP_PERF_MEAS 41636413Ssklower struct timeval send_start_time; 41736413Ssklower #endif TP_PERF_MEAS 41836413Ssklower 41936413Ssklower lowsave = lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1); 42036413Ssklower 42136413Ssklower ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff); 42236413Ssklower 42336413Ssklower if( tpcb->tp_rx_strat & TPRX_USE_CW ) { 42436413Ssklower /*first hiseq is temp vbl*/ 42536413Ssklower highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win); 42636413Ssklower } else { 42736413Ssklower highseq = tpcb->tp_fcredit; 42836413Ssklower } 42936413Ssklower highseq = SEQ(tpcb, tpcb->tp_snduna + highseq); 43036413Ssklower 43136413Ssklower SEQ_DEC(tpcb, highseq); 43236413Ssklower 43336413Ssklower IFDEBUG(D_DATA) 43436413Ssklower printf( 43536413Ssklower "tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n", 43636413Ssklower tpcb, lowseq, highseq); 43736413Ssklower dump_mbuf(sb->sb_mb, "sb_mb:"); 43836413Ssklower ENDDEBUG 43936413Ssklower IFTRACE(D_DATA) 44036413Ssklower tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna", 44136413Ssklower lowsave, tpcb->tp_sndhiwat, tpcb->tp_snduna, 0); 44236413Ssklower tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin", 44336413Ssklower lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); 44436413Ssklower ENDTRACE 44536413Ssklower 44636413Ssklower 44736413Ssklower if ( SEQ_GT(tpcb, lowseq, highseq) ) 44836413Ssklower return ; /* don't send, don't change hiwat, don't set timers */ 44936413Ssklower 45036413Ssklower IFPERF(tpcb) 45136413Ssklower GET_CUR_TIME(&send_start_time); 45236413Ssklower ENDPERF 45336413Ssklower 45436413Ssklower ASSERT( SEQ_LEQ(tpcb, lowseq, highseq) ); 45536413Ssklower SEQ_DEC(tpcb, lowseq); 45636413Ssklower 45736413Ssklower IFTRACE(D_DATA) 45836413Ssklower tptraceTPCB( TPPTmisc, "tp_send 2 low high fcredit congwin", 45936413Ssklower lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); 46036413Ssklower ENDTRACE 46136413Ssklower 46238841Ssklower while ((SEQ_LT(tpcb, lowseq, highseq)) && (mb = m = sb->sb_mb)) { 46337469Ssklower if (tpcb->tp_Xsnd.sb_mb) { 46436413Ssklower IFTRACE(D_XPD) 46536413Ssklower tptraceTPCB( TPPTmisc, 46636413Ssklower "tp_send XPD mark low high tpcb.Xuna", 46738841Ssklower lowseq, highseq, tpcb->tp_Xsnd.sb_mb, 0); 46836413Ssklower ENDTRACE 46937469Ssklower /* stop sending here because there are unacked XPD which were 47037469Ssklower * given to us before the next data were. 47137469Ssklower */ 47237469Ssklower IncStat(ts_xpd_intheway); 47337469Ssklower break; 47436413Ssklower } 47536413Ssklower eotsdu_reached = 0; 47636413Ssklower nextrecord = m->m_act; 47737469Ssklower for (len = 0; m; m = m->m_next) { 47836413Ssklower len += m->m_len; 47937469Ssklower if (m->m_flags & M_EOR) 48036413Ssklower eotsdu_reached = 1; 48136413Ssklower sbfree(sb, m); /* reduce counts in socket buffer */ 48236413Ssklower } 48338841Ssklower sb->sb_mb = nextrecord; 48437469Ssklower IFTRACE(D_STASH) 48537469Ssklower tptraceTPCB(TPPTmisc, "tp_send whole mbuf: m_len len maxsize", 48637469Ssklower 0, mb->m_len, len, maxsize); 48737469Ssklower ENDTRACE 48836413Ssklower 48936413Ssklower if ( len == 0 && !eotsdu_reached) { 49036413Ssklower /* THIS SHOULD NEVER HAPPEN! */ 49136413Ssklower ASSERT( 0 ); 49236413Ssklower goto done; 49336413Ssklower } 49436413Ssklower 49536413Ssklower /* If we arrive here one of the following holds: 49636413Ssklower * 1. We have exactly <maxsize> octets of whole mbufs, 49736413Ssklower * 2. We accumulated <maxsize> octets using partial mbufs, 49836413Ssklower * 3. We found an TPMT_EOT or an XPD mark 49936413Ssklower * 4. We hit the end of a chain through m_next. 50036413Ssklower * In this case, we'd LIKE to continue with the next record, 50136413Ssklower * but for the time being, for simplicity, we'll stop here. 50236413Ssklower * In all cases, m points to mbuf containing first octet to be 50336413Ssklower * sent in the tpdu AFTER the one we're going to send now, 50436413Ssklower * or else m is null. 50536413Ssklower * 50636413Ssklower * The chain we're working on now begins at mb and has length <len>. 50736413Ssklower */ 50836413Ssklower 50936413Ssklower IFTRACE(D_STASH) 51036413Ssklower tptraceTPCB( TPPTmisc, 51136413Ssklower "tp_send mcopy low high eotsdu_reached len", 51236413Ssklower lowseq, highseq, eotsdu_reached, len); 51336413Ssklower ENDTRACE 51436413Ssklower 51536413Ssklower /* make a copy - mb goes into the retransmission list 51636413Ssklower * while m gets emitted. m_copy won't copy a zero-length mbuf. 51736413Ssklower */ 51838841Ssklower if (len) { 51938841Ssklower if ((m = m_copy(mb, 0, len )) == MNULL) 52036413Ssklower goto done; 52136413Ssklower } else { 52236413Ssklower /* eotsdu reached */ 52336413Ssklower MGET(m, M_WAIT, TPMT_DATA); 52438841Ssklower if (m == MNULL) 52536413Ssklower goto done; 52636413Ssklower m->m_len = 0; 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, 55039196Ssklower "tp_send emitting DT lowseq eotsdu_reached len", 55139196Ssklower lowseq, eotsdu_reached, len, 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; 65437469Ssklower n->m_flags |= M_EOR; 65538841Ssklower n->m_act = 0; 65637469Ssklower } 65736413Ssklower IFDEBUG(D_STASH) 65836413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 65936413Ssklower "stash: so_rcv before appending"); 66036413Ssklower dump_mbuf(E.e_data, 66136413Ssklower "stash: e_data before appending"); 66236413Ssklower ENDDEBUG 66336413Ssklower 66436413Ssklower IFPERF(tpcb) 66536413Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen; 66636413Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 66737469Ssklower E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); 66836413Ssklower ENDPERF 66936413Ssklower 67036413Ssklower if( E.e_seq == tpcb->tp_rcvnxt ) { 67136413Ssklower 67236413Ssklower IFDEBUG(D_STASH) 67336413Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", 67436413Ssklower E.e_seq, E.e_datalen, E.e_eot); 67536413Ssklower ENDDEBUG 67636413Ssklower 67736413Ssklower IFTRACE(D_STASH) 67836413Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 67936413Ssklower E.e_seq, E.e_datalen, E.e_eot, 0); 68036413Ssklower ENDTRACE 68136413Ssklower 68237469Ssklower sbappend(&tpcb->tp_sock->so_rcv, E.e_data); 68337469Ssklower 68436413Ssklower if (newrec = E.e_eot ) /* ASSIGNMENT */ 68536413Ssklower ack_reason |= ACK_EOT; 68636413Ssklower 68736413Ssklower SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 68836413Ssklower /* 68936413Ssklower * move chains from the rtc list to the socket buffer 69036413Ssklower * and free the rtc header 69136413Ssklower */ 69236413Ssklower { 69336413Ssklower register struct tp_rtc **r = &tpcb->tp_rcvnxt_rtc; 69436413Ssklower register struct tp_rtc *s = tpcb->tp_rcvnxt_rtc; 69536413Ssklower 69636413Ssklower while (s != (struct tp_rtc *)0 && s->tprt_seq == tpcb->tp_rcvnxt) { 69736413Ssklower *r = s->tprt_next; 69836413Ssklower 69937469Ssklower sbappend(&tpcb->tp_sock->so_rcv, s->tprt_data); 70036413Ssklower 70136413Ssklower SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 70236413Ssklower 70336413Ssklower (void) m_free( dtom( s ) ); 70436413Ssklower s = *r; 70536413Ssklower ack_reason |= ACK_REORDER; 70636413Ssklower } 70736413Ssklower } 70836413Ssklower IFDEBUG(D_STASH) 70936413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 71036413Ssklower "stash: so_rcv after appending"); 71136413Ssklower ENDDEBUG 71236413Ssklower 71336413Ssklower } else { 71436413Ssklower register struct tp_rtc **s = &tpcb->tp_rcvnxt_rtc; 71536413Ssklower register struct tp_rtc *r = tpcb->tp_rcvnxt_rtc; 71636413Ssklower register struct tp_rtc *t; 71736413Ssklower 71836413Ssklower IFTRACE(D_STASH) 71936413Ssklower tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", 72036413Ssklower E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); 72136413Ssklower ENDTRACE 72236413Ssklower 72336413Ssklower r = tpcb->tp_rcvnxt_rtc; 72436413Ssklower while (r != (struct tp_rtc *)0 && SEQ_LT(tpcb, r->tprt_seq, E.e_seq)) { 72536413Ssklower s = &r->tprt_next; 72636413Ssklower r = r->tprt_next; 72736413Ssklower } 72836413Ssklower 72936413Ssklower if (r == (struct tp_rtc *)0 || SEQ_GT(tpcb, r->tprt_seq, E.e_seq) ) { 73036413Ssklower IncStat(ts_dt_ooo); 73136413Ssklower 73236413Ssklower IFTRACE(D_STASH) 73336413Ssklower tptrace(TPPTmisc, 73436413Ssklower "tp_stash OUT OF ORDER- MAKE RTC: seq, 1st seq in list\n", 73536413Ssklower E.e_seq, r->tprt_seq,0,0); 73636413Ssklower ENDTRACE 73736413Ssklower IFDEBUG(D_STASH) 73836413Ssklower printf("tp_stash OUT OF ORDER- MAKE RTC\n"); 73936413Ssklower ENDDEBUG 74036413Ssklower TP_MAKE_RTC(t, E.e_seq, E.e_eot, E.e_data, E.e_datalen, 0, 74136413Ssklower TPMT_RCVRTC); 74236413Ssklower 74336413Ssklower *s = t; 74436413Ssklower t->tprt_next = (struct tp_rtc *)r; 74536413Ssklower ack_reason = ACK_DONT; 74636413Ssklower goto done; 74736413Ssklower } else { 74836413Ssklower IFDEBUG(D_STASH) 74936413Ssklower printf("tp_stash - drop & ack\n"); 75036413Ssklower ENDDEBUG 75136413Ssklower 75236413Ssklower /* retransmission - drop it and force an ack */ 75336413Ssklower IncStat(ts_dt_dup); 75436413Ssklower IFPERF(tpcb) 75536413Ssklower IncPStat(tpcb, tps_n_ack_cuz_dup); 75636413Ssklower ENDPERF 75736413Ssklower 75836413Ssklower m_freem( E.e_data ); 75936413Ssklower ack_reason |= ACK_DUP; 76036413Ssklower goto done; 76136413Ssklower } 76236413Ssklower } 76336413Ssklower 76436413Ssklower 76536413Ssklower /* 76636413Ssklower * an ack should be sent when at least one of the 76736413Ssklower * following holds: 76836413Ssklower * a) we've received a TPDU with EOTSDU set 76936413Ssklower * b) the TPDU that just arrived represents the 77036413Ssklower * full window last advertised, or 77136413Ssklower * c) when seq X arrives [ where 77236413Ssklower * X = last_sent_uwe - 1/2 last_lcredit_sent 77336413Ssklower * (the packet representing 1/2 the last advertised window) ] 77436413Ssklower * and lcredit at the time of X arrival > last_lcredit_sent/2 77536413Ssklower * In other words, if the last ack sent advertised cdt=8 and uwe = 8 77636413Ssklower * then when seq 4 arrives I'd like to send a new ack 77736413Ssklower * iff the credit at the time of 4's arrival is > 4. 77836413Ssklower * The other end thinks it has cdt of 4 so if local cdt 77936413Ssklower * is still 4 there's no point in sending an ack, but if 78036413Ssklower * my credit has increased because the receiver has taken 78136413Ssklower * some data out of the buffer (soreceive doesn't notify 78236413Ssklower * me until the SYSTEM CALL finishes), I'd like to tell 78336413Ssklower * the other end. 78436413Ssklower */ 78536413Ssklower 78636413Ssklower done: 78736413Ssklower { 78836413Ssklower LOCAL_CREDIT(tpcb); 78936413Ssklower 79036413Ssklower if ( E.e_seq == tpcb->tp_sent_uwe ) 79136413Ssklower ack_reason |= ACK_STRAT_FULLWIN; 79236413Ssklower 79336413Ssklower IFTRACE(D_STASH) 79436413Ssklower tptraceTPCB(TPPTmisc, 79536413Ssklower "end of stash, eot, ack_reason, sent_uwe ", 79636413Ssklower E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); 79736413Ssklower ENDTRACE 79836413Ssklower 79936413Ssklower if ( ack_reason == ACK_DONT ) { 80036413Ssklower IncStat( ts_ackreason[ACK_DONT] ); 80136413Ssklower return 0; 80236413Ssklower } else { 80336413Ssklower IFPERF(tpcb) 80436413Ssklower if(ack_reason & ACK_EOT) { 80536413Ssklower IncPStat(tpcb, tps_n_ack_cuz_eot); 80636413Ssklower } 80736413Ssklower if(ack_reason & ACK_STRAT_EACH) { 80836413Ssklower IncPStat(tpcb, tps_n_ack_cuz_strat); 80936413Ssklower } else if(ack_reason & ACK_STRAT_FULLWIN) { 81036413Ssklower IncPStat(tpcb, tps_n_ack_cuz_fullwin); 81136413Ssklower } else if(ack_reason & ACK_REORDER) { 81236413Ssklower IncPStat(tpcb, tps_n_ack_cuz_reorder); 81336413Ssklower } 81436413Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, 81536413Ssklower SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); 81636413Ssklower ENDPERF 81736413Ssklower { 81836413Ssklower register int i; 81936413Ssklower 82036413Ssklower /* keep track of all reasons that apply */ 82136413Ssklower for( i=1; i<_ACK_NUM_REASONS_ ;i++) { 82236413Ssklower if( ack_reason & (1<<i) ) 82336413Ssklower IncStat( ts_ackreason[i] ); 82436413Ssklower } 82536413Ssklower } 82636413Ssklower return 1; 82736413Ssklower } 82836413Ssklower } 82936413Ssklower } 830