149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*50236Ssklower * @(#)tp_subr.c 7.9 (Berkeley) 06/27/91 849268Sbostic */ 949268Sbostic 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 416*50236Ssklower 41736413Ssklower struct timeval send_start_time; 418*50236Ssklower IFPERF(tpcb) 419*50236Ssklower GET_CUR_TIME(&send_start_time); 420*50236Ssklower ENDPERF 42136413Ssklower #endif TP_PERF_MEAS 42236413Ssklower 42336413Ssklower lowsave = lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1); 42436413Ssklower 42536413Ssklower ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff); 42636413Ssklower 42736413Ssklower if( tpcb->tp_rx_strat & TPRX_USE_CW ) { 42836413Ssklower /*first hiseq is temp vbl*/ 42936413Ssklower highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win); 43036413Ssklower } else { 43136413Ssklower highseq = tpcb->tp_fcredit; 43236413Ssklower } 43336413Ssklower highseq = SEQ(tpcb, tpcb->tp_snduna + highseq); 43436413Ssklower 43536413Ssklower SEQ_DEC(tpcb, highseq); 43636413Ssklower 43736413Ssklower IFDEBUG(D_DATA) 43836413Ssklower printf( 43936413Ssklower "tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n", 44036413Ssklower tpcb, lowseq, highseq); 44136413Ssklower dump_mbuf(sb->sb_mb, "sb_mb:"); 44236413Ssklower ENDDEBUG 44336413Ssklower IFTRACE(D_DATA) 44436413Ssklower tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna", 44536413Ssklower lowsave, tpcb->tp_sndhiwat, tpcb->tp_snduna, 0); 44636413Ssklower tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin", 44736413Ssklower lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); 44836413Ssklower ENDTRACE 44936413Ssklower 45036413Ssklower 45136413Ssklower if ( SEQ_GT(tpcb, lowseq, highseq) ) 45236413Ssklower return ; /* don't send, don't change hiwat, don't set timers */ 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: 567*50236Ssklower #ifdef TP_PERF_MEAS 56836413Ssklower IFPERF(tpcb) 56936413Ssklower { 57036413Ssklower register int npkts; 57136413Ssklower struct timeval send_end_time; 57236413Ssklower register struct timeval *t; 57336413Ssklower 57436413Ssklower npkts = lowseq; 57536413Ssklower SEQ_INC(tpcb, npkts); 57636413Ssklower npkts = SEQ_SUB(tpcb, npkts, lowsave); 57736413Ssklower 57836413Ssklower if(npkts > 0) 57936413Ssklower tpcb->tp_Nwindow++; 58036413Ssklower 58136413Ssklower if (npkts > TP_PM_MAX) 58236413Ssklower npkts = TP_PM_MAX; 58336413Ssklower 58436413Ssklower GET_TIME_SINCE(&send_start_time, &send_end_time); 58536413Ssklower t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); 58636413Ssklower t->tv_sec = 58736413Ssklower SMOOTH( long, TP_RTT_ALPHA, t->tv_sec, send_end_time.tv_sec); 58836413Ssklower t->tv_usec = 58936413Ssklower SMOOTH( long, TP_RTT_ALPHA, t->tv_usec, send_end_time.tv_usec); 59036413Ssklower 59136413Ssklower if ( SEQ_LT(tpcb, lowseq, highseq) ) { 59236413Ssklower IncPStat(tpcb, tps_win_lim_by_data[npkts] ); 59336413Ssklower } else { 59436413Ssklower IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); 59536413Ssklower /* not true with congestion-window being used */ 59636413Ssklower } 59736413Ssklower tpmeas( tpcb->tp_lref, 59836413Ssklower TPsbsend, &send_end_time, lowsave, tpcb->tp_Nwindow, npkts); 59936413Ssklower } 60036413Ssklower ENDPERF 601*50236Ssklower #endif TP_PERF_MEAS 60236413Ssklower 60336413Ssklower tpcb->tp_sndhiwat = lowseq; 60436413Ssklower 60536413Ssklower if ( SEQ_LEQ(tpcb, lowsave, tpcb->tp_sndhiwat) && 60636413Ssklower (tpcb->tp_class != TP_CLASS_0) ) 60736413Ssklower tp_etimeout(tpcb->tp_refp, TM_data_retrans, lowsave, 60836413Ssklower tpcb->tp_sndhiwat, 60936413Ssklower (u_int)tpcb->tp_Nretrans, (int)tpcb->tp_dt_ticks); 61036413Ssklower IFTRACE(D_DATA) 61136413Ssklower tptraceTPCB( TPPTmisc, 61236413Ssklower "tp_send at end: sndhiwat lowseq eotsdu_reached error", 61336413Ssklower tpcb->tp_sndhiwat, lowseq, eotsdu_reached, tpcb->tp_sock->so_error); 61436413Ssklower 61536413Ssklower ENDTRACE 61636413Ssklower } 61736413Ssklower 61836413Ssklower /* 61936413Ssklower * NAME: tp_stash() 62036413Ssklower * CALLED FROM: 62136413Ssklower * tp.trans on arrival of a DT tpdu 62236413Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 62336413Ssklower * Returns 1 if 62436413Ssklower * a) something new arrived and it's got eotsdu_reached bit on, 62536413Ssklower * b) this arrival was caused other out-of-sequence things to be 62636413Ssklower * accepted, or 62736413Ssklower * c) this arrival is the highest seq # for which we last gave credit 62836413Ssklower * (sender just sent a whole window) 62936413Ssklower * In other words, returns 1 if tp should send an ack immediately, 0 if 63036413Ssklower * the ack can wait a while. 63136413Ssklower * 63236413Ssklower * Note: this implementation no longer renegs on credit, (except 63336413Ssklower * when debugging option D_RENEG is on, for the purpose of testing 63436413Ssklower * ack subsequencing), so we don't need to check for incoming tpdus 63536413Ssklower * being in a reneged portion of the window. 63636413Ssklower */ 63736413Ssklower 63836413Ssklower int 63936413Ssklower tp_stash( tpcb, e ) 64036413Ssklower register struct tp_pcb *tpcb; 64136413Ssklower register struct tp_event *e; 64236413Ssklower { 64336413Ssklower register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; 64436413Ssklower /* 0--> delay acks until full window */ 64536413Ssklower /* 1--> ack each tpdu */ 64636413Ssklower int newrec = 0; 64736413Ssklower 64836413Ssklower #ifndef lint 64936413Ssklower #define E e->ATTR(DT_TPDU) 65036413Ssklower #else lint 65136413Ssklower #define E e->ev_union.EV_DT_TPDU 65236413Ssklower #endif lint 65336413Ssklower 65436413Ssklower if ( E.e_eot ) { 65536413Ssklower register struct mbuf *n = E.e_data; 65637469Ssklower n->m_flags |= M_EOR; 65738841Ssklower n->m_act = 0; 65837469Ssklower } 65936413Ssklower IFDEBUG(D_STASH) 66036413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 66136413Ssklower "stash: so_rcv before appending"); 66236413Ssklower dump_mbuf(E.e_data, 66336413Ssklower "stash: e_data before appending"); 66436413Ssklower ENDDEBUG 66536413Ssklower 66636413Ssklower IFPERF(tpcb) 66736413Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen; 66836413Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 66937469Ssklower E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); 67036413Ssklower ENDPERF 67136413Ssklower 67236413Ssklower if( E.e_seq == tpcb->tp_rcvnxt ) { 67336413Ssklower 67436413Ssklower IFDEBUG(D_STASH) 67536413Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", 67636413Ssklower E.e_seq, E.e_datalen, E.e_eot); 67736413Ssklower ENDDEBUG 67836413Ssklower 67936413Ssklower IFTRACE(D_STASH) 68036413Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 68136413Ssklower E.e_seq, E.e_datalen, E.e_eot, 0); 68236413Ssklower ENDTRACE 68336413Ssklower 68437469Ssklower sbappend(&tpcb->tp_sock->so_rcv, E.e_data); 68537469Ssklower 68636413Ssklower if (newrec = E.e_eot ) /* ASSIGNMENT */ 68736413Ssklower ack_reason |= ACK_EOT; 68836413Ssklower 68936413Ssklower SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 69036413Ssklower /* 69136413Ssklower * move chains from the rtc list to the socket buffer 69236413Ssklower * and free the rtc header 69336413Ssklower */ 69436413Ssklower { 69536413Ssklower register struct tp_rtc **r = &tpcb->tp_rcvnxt_rtc; 69636413Ssklower register struct tp_rtc *s = tpcb->tp_rcvnxt_rtc; 69736413Ssklower 69836413Ssklower while (s != (struct tp_rtc *)0 && s->tprt_seq == tpcb->tp_rcvnxt) { 69936413Ssklower *r = s->tprt_next; 70036413Ssklower 70137469Ssklower sbappend(&tpcb->tp_sock->so_rcv, s->tprt_data); 70236413Ssklower 70336413Ssklower SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 70436413Ssklower 70536413Ssklower (void) m_free( dtom( s ) ); 70636413Ssklower s = *r; 70736413Ssklower ack_reason |= ACK_REORDER; 70836413Ssklower } 70936413Ssklower } 71036413Ssklower IFDEBUG(D_STASH) 71136413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 71236413Ssklower "stash: so_rcv after appending"); 71336413Ssklower ENDDEBUG 71436413Ssklower 71536413Ssklower } else { 71636413Ssklower register struct tp_rtc **s = &tpcb->tp_rcvnxt_rtc; 71736413Ssklower register struct tp_rtc *r = tpcb->tp_rcvnxt_rtc; 71836413Ssklower register struct tp_rtc *t; 71936413Ssklower 72036413Ssklower IFTRACE(D_STASH) 72136413Ssklower tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", 72236413Ssklower E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); 72336413Ssklower ENDTRACE 72436413Ssklower 72536413Ssklower r = tpcb->tp_rcvnxt_rtc; 72636413Ssklower while (r != (struct tp_rtc *)0 && SEQ_LT(tpcb, r->tprt_seq, E.e_seq)) { 72736413Ssklower s = &r->tprt_next; 72836413Ssklower r = r->tprt_next; 72936413Ssklower } 73036413Ssklower 73136413Ssklower if (r == (struct tp_rtc *)0 || SEQ_GT(tpcb, r->tprt_seq, E.e_seq) ) { 73236413Ssklower IncStat(ts_dt_ooo); 73336413Ssklower 73436413Ssklower IFTRACE(D_STASH) 73536413Ssklower tptrace(TPPTmisc, 73636413Ssklower "tp_stash OUT OF ORDER- MAKE RTC: seq, 1st seq in list\n", 73736413Ssklower E.e_seq, r->tprt_seq,0,0); 73836413Ssklower ENDTRACE 73936413Ssklower IFDEBUG(D_STASH) 74036413Ssklower printf("tp_stash OUT OF ORDER- MAKE RTC\n"); 74136413Ssklower ENDDEBUG 74236413Ssklower TP_MAKE_RTC(t, E.e_seq, E.e_eot, E.e_data, E.e_datalen, 0, 74336413Ssklower TPMT_RCVRTC); 74436413Ssklower 74536413Ssklower *s = t; 74636413Ssklower t->tprt_next = (struct tp_rtc *)r; 74736413Ssklower ack_reason = ACK_DONT; 74836413Ssklower goto done; 74936413Ssklower } else { 75036413Ssklower IFDEBUG(D_STASH) 75136413Ssklower printf("tp_stash - drop & ack\n"); 75236413Ssklower ENDDEBUG 75336413Ssklower 75436413Ssklower /* retransmission - drop it and force an ack */ 75536413Ssklower IncStat(ts_dt_dup); 75636413Ssklower IFPERF(tpcb) 75736413Ssklower IncPStat(tpcb, tps_n_ack_cuz_dup); 75836413Ssklower ENDPERF 75936413Ssklower 76036413Ssklower m_freem( E.e_data ); 76136413Ssklower ack_reason |= ACK_DUP; 76236413Ssklower goto done; 76336413Ssklower } 76436413Ssklower } 76536413Ssklower 76636413Ssklower 76736413Ssklower /* 76836413Ssklower * an ack should be sent when at least one of the 76936413Ssklower * following holds: 77036413Ssklower * a) we've received a TPDU with EOTSDU set 77136413Ssklower * b) the TPDU that just arrived represents the 77236413Ssklower * full window last advertised, or 77336413Ssklower * c) when seq X arrives [ where 77436413Ssklower * X = last_sent_uwe - 1/2 last_lcredit_sent 77536413Ssklower * (the packet representing 1/2 the last advertised window) ] 77636413Ssklower * and lcredit at the time of X arrival > last_lcredit_sent/2 77736413Ssklower * In other words, if the last ack sent advertised cdt=8 and uwe = 8 77836413Ssklower * then when seq 4 arrives I'd like to send a new ack 77936413Ssklower * iff the credit at the time of 4's arrival is > 4. 78036413Ssklower * The other end thinks it has cdt of 4 so if local cdt 78136413Ssklower * is still 4 there's no point in sending an ack, but if 78236413Ssklower * my credit has increased because the receiver has taken 78336413Ssklower * some data out of the buffer (soreceive doesn't notify 78436413Ssklower * me until the SYSTEM CALL finishes), I'd like to tell 78536413Ssklower * the other end. 78636413Ssklower */ 78736413Ssklower 78836413Ssklower done: 78936413Ssklower { 79036413Ssklower LOCAL_CREDIT(tpcb); 79136413Ssklower 79236413Ssklower if ( E.e_seq == tpcb->tp_sent_uwe ) 79336413Ssklower ack_reason |= ACK_STRAT_FULLWIN; 79436413Ssklower 79536413Ssklower IFTRACE(D_STASH) 79636413Ssklower tptraceTPCB(TPPTmisc, 79736413Ssklower "end of stash, eot, ack_reason, sent_uwe ", 79836413Ssklower E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); 79936413Ssklower ENDTRACE 80036413Ssklower 80136413Ssklower if ( ack_reason == ACK_DONT ) { 80236413Ssklower IncStat( ts_ackreason[ACK_DONT] ); 80336413Ssklower return 0; 80436413Ssklower } else { 80536413Ssklower IFPERF(tpcb) 80636413Ssklower if(ack_reason & ACK_EOT) { 80736413Ssklower IncPStat(tpcb, tps_n_ack_cuz_eot); 80836413Ssklower } 80936413Ssklower if(ack_reason & ACK_STRAT_EACH) { 81036413Ssklower IncPStat(tpcb, tps_n_ack_cuz_strat); 81136413Ssklower } else if(ack_reason & ACK_STRAT_FULLWIN) { 81236413Ssklower IncPStat(tpcb, tps_n_ack_cuz_fullwin); 81336413Ssklower } else if(ack_reason & ACK_REORDER) { 81436413Ssklower IncPStat(tpcb, tps_n_ack_cuz_reorder); 81536413Ssklower } 81636413Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, 81736413Ssklower SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); 81836413Ssklower ENDPERF 81936413Ssklower { 82036413Ssklower register int i; 82136413Ssklower 82236413Ssklower /* keep track of all reasons that apply */ 82336413Ssklower for( i=1; i<_ACK_NUM_REASONS_ ;i++) { 82436413Ssklower if( ack_reason & (1<<i) ) 82536413Ssklower IncStat( ts_ackreason[i] ); 82636413Ssklower } 82736413Ssklower } 82836413Ssklower return 1; 82936413Ssklower } 83036413Ssklower } 83136413Ssklower } 832