149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*51024Ssklower * @(#)tp_subr.c 7.13 (Berkeley) 09/06/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 8236413Ssklower /* 8336413Ssklower * CALLED FROM: 8436413Ssklower * tp.trans, when an XAK arrives 8536413Ssklower * FUNCTION and ARGUMENTS: 8636413Ssklower * Determines if the sequence number (seq) from the XAK 8736413Ssklower * acks anything new. If so, drop the appropriate tpdu 8836413Ssklower * from the XPD send queue. 8936413Ssklower * RETURN VALUE: 9036413Ssklower * Returns 1 if it did this, 0 if the ack caused no action. 9136413Ssklower */ 9236413Ssklower int 9336413Ssklower tp_goodXack(tpcb, seq) 9436413Ssklower struct tp_pcb *tpcb; 9536413Ssklower SeqNum seq; 9636413Ssklower { 9736413Ssklower 9836413Ssklower IFTRACE(D_XPD) 9936413Ssklower tptraceTPCB(TPPTgotXack, 10036413Ssklower seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndhiwat, 10136413Ssklower tpcb->tp_snduna); 10236413Ssklower ENDTRACE 10336413Ssklower 10436413Ssklower if ( seq == tpcb->tp_Xuna ) { 10536413Ssklower tpcb->tp_Xuna = tpcb->tp_Xsndnxt; 10636413Ssklower 10736413Ssklower /* DROP 1 packet from the Xsnd socket buf - just so happens 10836413Ssklower * that only one packet can be there at any time 10936413Ssklower * so drop the whole thing. If you allow > 1 packet 11036413Ssklower * the socket buffer, then you'll have to keep 11136413Ssklower * track of how many characters went w/ each XPD tpdu, so this 11236413Ssklower * will get messier 11336413Ssklower */ 11436413Ssklower IFDEBUG(D_XPD) 11536413Ssklower dump_mbuf(tpcb->tp_Xsnd.sb_mb, 11636413Ssklower "tp_goodXack Xsnd before sbdrop"); 11736413Ssklower ENDDEBUG 11836413Ssklower 11936413Ssklower IFTRACE(D_XPD) 12036413Ssklower tptraceTPCB(TPPTmisc, 12136413Ssklower "goodXack: dropping cc ", 12236413Ssklower (int)(tpcb->tp_Xsnd.sb_cc), 12336413Ssklower 0,0,0); 12436413Ssklower ENDTRACE 12536413Ssklower sbdrop( &tpcb->tp_Xsnd, (int)(tpcb->tp_Xsnd.sb_cc)); 12639922Ssklower CONG_ACK(tpcb, seq); 12736413Ssklower return 1; 12836413Ssklower } 12936413Ssklower return 0; 13036413Ssklower } 13136413Ssklower 13236413Ssklower /* 13336413Ssklower * CALLED FROM: 13436413Ssklower * tp_good_ack() 13536413Ssklower * FUNCTION and ARGUMENTS: 13636413Ssklower * updates 13736413Ssklower * smoothed average round trip time (base_rtt) 13836413Ssklower * roundtrip time variance (base_rtv) - actually deviation, not variance 13936413Ssklower * given the new value (diff) 14036413Ssklower * RETURN VALUE: 14136413Ssklower * void 14236413Ssklower */ 14336413Ssklower 14436413Ssklower void 14536413Ssklower tp_rtt_rtv( base_rtt, base_rtv, newmeas ) 14636413Ssklower struct timeval *base_rtt, *base_rtv, *newmeas; 14736413Ssklower { 14836413Ssklower /* update rt variance (really just the deviation): 14936413Ssklower * rtv.smooth_ave = SMOOTH( | oldrtt.smooth_avg - rtt.this_instance | ) 15036413Ssklower */ 15136413Ssklower base_rtv->tv_sec = 15236413Ssklower SMOOTH( long, TP_RTV_ALPHA, base_rtv->tv_sec, 15344948Ssklower ABS( long, base_rtt->tv_sec - newmeas->tv_sec )); 15436413Ssklower base_rtv->tv_usec = 15536413Ssklower SMOOTH( long, TP_RTV_ALPHA, base_rtv->tv_usec, 15644948Ssklower ABS(long, base_rtt->tv_usec - newmeas->tv_usec )); 15736413Ssklower 15836413Ssklower /* update smoothed average rtt */ 15936413Ssklower base_rtt->tv_sec = 16036413Ssklower SMOOTH( long, TP_RTT_ALPHA, base_rtt->tv_sec, newmeas->tv_sec); 16136413Ssklower base_rtt->tv_usec = 16236413Ssklower SMOOTH( long, TP_RTT_ALPHA, base_rtt->tv_usec, newmeas->tv_usec); 16336413Ssklower 16436413Ssklower } 16536413Ssklower 16636413Ssklower /* 16736413Ssklower * CALLED FROM: 16836413Ssklower * tp.trans when an AK arrives 16936413Ssklower * FUNCTION and ARGUMENTS: 17036413Ssklower * Given (cdt), the credit from the AK tpdu, and 17136413Ssklower * (seq), the sequence number from the AK tpdu, 17236413Ssklower * tp_goodack() determines if the AK acknowledges something in the send 17336413Ssklower * window, and if so, drops the appropriate packets from the retransmission 17436413Ssklower * list, computes the round trip time, and updates the retransmission timer 17536413Ssklower * based on the new smoothed round trip time. 17636413Ssklower * RETURN VALUE: 17736413Ssklower * Returns 1 if 17836413Ssklower * EITHER it actually acked something heretofore unacknowledged 17936413Ssklower * OR no news but the credit should be processed. 18036413Ssklower * If something heretofore unacked was acked with this sequence number, 18136413Ssklower * the appropriate tpdus are dropped from the retransmission control list, 18236413Ssklower * by calling tp_sbdrop(). 18336413Ssklower * No need to see the tpdu itself. 18436413Ssklower */ 18536413Ssklower int 18636413Ssklower tp_goodack(tpcb, cdt, seq, subseq) 18736413Ssklower register struct tp_pcb *tpcb; 18836413Ssklower u_int cdt; 18936413Ssklower register SeqNum seq, subseq; 19036413Ssklower { 19136413Ssklower int old_fcredit = tpcb->tp_fcredit; 19236413Ssklower int bang = 0; /* bang --> ack for something heretofore unacked */ 19336413Ssklower 19436413Ssklower IFDEBUG(D_ACKRECV) 19536413Ssklower printf("goodack seq 0x%x cdt 0x%x snduna 0x%x sndhiwat 0x%x\n", 19636413Ssklower seq, cdt, tpcb->tp_snduna, tpcb->tp_sndhiwat); 19736413Ssklower ENDDEBUG 19836413Ssklower IFTRACE(D_ACKRECV) 19936413Ssklower tptraceTPCB(TPPTgotack, 20036413Ssklower seq,cdt, tpcb->tp_snduna,tpcb->tp_sndhiwat,subseq); 20136413Ssklower ENDTRACE 20236413Ssklower 20336413Ssklower IFPERF(tpcb) 20437469Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0); 20536413Ssklower ENDPERF 20636413Ssklower 20736413Ssklower if ( subseq != 0 && (subseq <= tpcb->tp_r_subseq) ) { 20836413Ssklower /* discard the ack */ 20936413Ssklower IFTRACE(D_ACKRECV) 21036413Ssklower tptraceTPCB(TPPTmisc, "goodack discard : subseq tp_r_subseq", 21136413Ssklower subseq, tpcb->tp_r_subseq, 0, 0); 21236413Ssklower ENDTRACE 21336413Ssklower return 0; 21436413Ssklower } else { 21536413Ssklower tpcb->tp_r_subseq = subseq; 21636413Ssklower } 21736413Ssklower 21836413Ssklower if ( IN_SWINDOW(tpcb, seq, 21936413Ssklower tpcb->tp_snduna, SEQ(tpcb, tpcb->tp_sndhiwat+1)) ) { 22036413Ssklower 22136413Ssklower IFDEBUG(D_XPD) 22236413Ssklower dump_mbuf(tpcb->tp_sock->so_snd.sb_mb, 22336413Ssklower "tp_goodack snd before sbdrop"); 22436413Ssklower ENDDEBUG 22550901Ssklower tpsbcheck(tpcb, 0); 22650901Ssklower tp_sbdrop(tpcb, seq); 22750901Ssklower tpsbcheck(tpcb, 1); 22836413Ssklower 22936413Ssklower /* increase congestion window but don't let it get too big */ 23036413Ssklower { 23136413Ssklower register int maxcdt = tpcb->tp_xtd_format?0xffff:0xf; 23239922Ssklower CONG_ACK(tpcb, seq); 23336413Ssklower } 23436413Ssklower 23536413Ssklower /* Compute smoothed round trip time. 23636413Ssklower * Only measure rtt for tp_snduna if tp_snduna was among 23739922Ssklower * the last TP_RTT_NUM seq numbers sent, and if the data 23839922Ssklower * were not retransmitted. 23936413Ssklower */ 24036413Ssklower if (SEQ_GEQ(tpcb, tpcb->tp_snduna, 24139922Ssklower SEQ(tpcb, tpcb->tp_sndhiwat - TP_RTT_NUM)) 24239922Ssklower && SEQ_GT(tpcb, seq, SEQ_ADD(tpcb, tpcb->tp_retrans_hiwat, 1))) { 24336413Ssklower 24436413Ssklower struct timeval *t = &tpcb->tp_rttemit[tpcb->tp_snduna & TP_RTT_NUM]; 24536413Ssklower struct timeval x; 24636413Ssklower 24736413Ssklower GET_TIME_SINCE(t, &x); 24836413Ssklower 24936413Ssklower tp_rtt_rtv( &(tpcb->tp_rtt), &(tpcb->tp_rtv), &x ); 25036413Ssklower 25136413Ssklower { /* update the global rtt, rtv stats */ 25236413Ssklower register int i = 25336413Ssklower (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN); 25436413Ssklower tp_rtt_rtv( &(tp_stat.ts_rtt[i]), &(tp_stat.ts_rtv[i]), &x ); 25536413Ssklower 25636413Ssklower IFTRACE(D_RTT) 25736413Ssklower tptraceTPCB(TPPTmisc, "Global rtt, rtv: i", i, 0, 0, 0); 25836413Ssklower ENDTRACE 25936413Ssklower } 26036413Ssklower 26136413Ssklower IFTRACE(D_RTT) 26236413Ssklower tptraceTPCB(TPPTmisc, 26336413Ssklower "Smoothed rtt: tp_snduna, (time.sec, time.usec), peer_acktime", 26436413Ssklower tpcb->tp_snduna, time.tv_sec, time.tv_usec, 26536413Ssklower tpcb->tp_peer_acktime); 26636413Ssklower 26736413Ssklower tptraceTPCB(TPPTmisc, 26836413Ssklower "(secs): emittime diff(x) rtt, rtv", 26936413Ssklower t->tv_sec, 27036413Ssklower x.tv_sec, 27136413Ssklower tpcb->tp_rtt.tv_sec, 27236413Ssklower tpcb->tp_rtv.tv_sec); 27336413Ssklower tptraceTPCB(TPPTmisc, 27436413Ssklower "(usecs): emittime diff(x) rtt rtv", 27536413Ssklower t->tv_usec, 27636413Ssklower x.tv_usec, 27736413Ssklower tpcb->tp_rtt.tv_usec, 27836413Ssklower tpcb->tp_rtv.tv_usec); 27936413Ssklower ENDTRACE 28036413Ssklower 28136413Ssklower { 28236413Ssklower /* Update data retransmission timer based on the smoothed 28336413Ssklower * round trip time, peer ack time, and the pseudo-arbitrary 28436413Ssklower * number 4. 28536413Ssklower * new ticks: avg rtt + 2*dev 28636413Ssklower * rtt, rtv are in microsecs, and ticks are 500 ms 28736413Ssklower * so 1 tick = 500*1000 us = 500000 us 28836413Ssklower * so ticks = (rtt + 2 rtv)/500000 28936413Ssklower * with ticks no les than peer ack time and no less than 4 29036413Ssklower */ 29136413Ssklower 29236413Ssklower int rtt = tpcb->tp_rtt.tv_usec + 29336413Ssklower tpcb->tp_rtt.tv_sec*1000000; 29436413Ssklower int rtv = tpcb->tp_rtv.tv_usec + 29536413Ssklower tpcb->tp_rtv.tv_sec*1000000; 29636413Ssklower 29736413Ssklower IFTRACE(D_RTT) 29836413Ssklower tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks", 29936413Ssklower tpcb->tp_dt_ticks, 30036413Ssklower rtv, rtt, 30136413Ssklower (rtt/500000 + (2 * rtv)/500000)); 30236413Ssklower ENDTRACE 30336413Ssklower tpcb->tp_dt_ticks = (rtt+ (2 * rtv))/500000; 30436413Ssklower tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks, 30536413Ssklower tpcb->tp_peer_acktime); 30636413Ssklower tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks, 4); 30736413Ssklower } 30836413Ssklower } 30936413Ssklower tpcb->tp_snduna = seq; 31039922Ssklower tpcb->tp_retrans = tpcb->tp_Nretrans; /* CE_BIT */ 31136413Ssklower 31236413Ssklower bang++; 31336413Ssklower } 31436413Ssklower 31536413Ssklower if( cdt != 0 && old_fcredit == 0 ) { 31636413Ssklower tpcb->tp_sendfcc = 1; 31736413Ssklower } 31836413Ssklower if( cdt == 0 && old_fcredit != 0 ) { 31936413Ssklower IncStat(ts_zfcdt); 32036413Ssklower } 32136413Ssklower tpcb->tp_fcredit = cdt; 32236413Ssklower 32336413Ssklower IFDEBUG(D_ACKRECV) 32436413Ssklower printf("goodack returning 0x%x, bang 0x%x cdt 0x%x old_fcredit 0x%x\n", 32536413Ssklower (bang || (old_fcredit < cdt) ), bang, cdt, old_fcredit ); 32636413Ssklower ENDDEBUG 32736413Ssklower 32836413Ssklower return (bang || (old_fcredit < cdt)) ; 32936413Ssklower } 33036413Ssklower 33136413Ssklower /* 33236413Ssklower * CALLED FROM: 33336413Ssklower * tp_goodack() 33436413Ssklower * FUNCTION and ARGUMENTS: 33550901Ssklower * drops everything up TO but not INCLUDING seq # (seq) 33636413Ssklower * from the retransmission queue. 33736413Ssklower */ 33836413Ssklower static void 33936413Ssklower tp_sbdrop(tpcb, seq) 34050901Ssklower register struct tp_pcb *tpcb; 34136413Ssklower SeqNum seq; 34236413Ssklower { 34350901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 34450901Ssklower register int i = ((int)seq)-((int)tpcb->tp_snduna); 34536413Ssklower 34650901Ssklower if (i < 0) i += tpcb->tp_seqhalf; 34736413Ssklower IFDEBUG(D_ACKRECV) 34850901Ssklower printf("tp_sbdroping %d up through seq 0x%x\n", i, seq); 34936413Ssklower ENDDEBUG 35050901Ssklower while (i-- > 0) 35150901Ssklower sbdroprecord(sb); 35250901Ssklower if (SEQ_LT(tpcb, tpcb->tp_sndhiwat, seq)) 35350901Ssklower tpcb->tp_sndhiwat_m = 0; 35436413Ssklower 35536413Ssklower } 35636413Ssklower 35736413Ssklower /* 35836413Ssklower * CALLED FROM: 35936413Ssklower * tp.trans on user send request, arrival of AK and arrival of XAK 36036413Ssklower * FUNCTION and ARGUMENTS: 36136413Ssklower * Emits tpdus starting at sequence number (lowseq). 36236413Ssklower * Emits until a) runs out of data, or b) runs into an XPD mark, or 36336413Ssklower * c) it hits seq number (highseq) 36436413Ssklower * 36536413Ssklower * If you want XPD to buffer > 1 du per socket buffer, you can 36636413Ssklower * modifiy this to issue XPD tpdus also, but then it'll have 36736413Ssklower * to take some argument(s) to distinguish between the type of DU to 36850901Ssklower * hand tp_emit. 36936413Ssklower * 37036413Ssklower * When something is sent for the first time, its time-of-send 37136413Ssklower * is stashed (the last RTT_NUM of them are stashed). When the 37236413Ssklower * ack arrives, the smoothed round-trip time is figured using this value. 37336413Ssklower * RETURN VALUE: 37436413Ssklower * the highest seq # sent successfully. 37536413Ssklower */ 37636413Ssklower tp_send(tpcb) 37736413Ssklower register struct tp_pcb *tpcb; 37836413Ssklower { 37936413Ssklower register int len; 38036413Ssklower register struct mbuf *m; /* the one we're inspecting now */ 38136413Ssklower struct mbuf *mb;/* beginning of this tpdu */ 38236413Ssklower struct mbuf *nextrecord; /* NOT next tpdu but next sb record */ 38336413Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 38436413Ssklower unsigned int eotsdu_reached=0; 38536413Ssklower SeqNum lowseq, highseq ; 38636413Ssklower SeqNum lowsave; 38736413Ssklower #ifdef TP_PERF_MEAS 38850236Ssklower 38936413Ssklower struct timeval send_start_time; 39050236Ssklower IFPERF(tpcb) 39150236Ssklower GET_CUR_TIME(&send_start_time); 39250236Ssklower ENDPERF 39336413Ssklower #endif TP_PERF_MEAS 39436413Ssklower 39536413Ssklower lowsave = lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1); 39636413Ssklower 39736413Ssklower ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff); 39836413Ssklower 39936413Ssklower if( tpcb->tp_rx_strat & TPRX_USE_CW ) { 40036413Ssklower /*first hiseq is temp vbl*/ 40136413Ssklower highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win); 40236413Ssklower } else { 40336413Ssklower highseq = tpcb->tp_fcredit; 40436413Ssklower } 40536413Ssklower highseq = SEQ(tpcb, tpcb->tp_snduna + highseq); 40636413Ssklower 40736413Ssklower SEQ_DEC(tpcb, highseq); 40836413Ssklower 40936413Ssklower IFDEBUG(D_DATA) 41036413Ssklower printf( 41136413Ssklower "tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n", 41236413Ssklower tpcb, lowseq, highseq); 41336413Ssklower dump_mbuf(sb->sb_mb, "sb_mb:"); 41436413Ssklower ENDDEBUG 41536413Ssklower IFTRACE(D_DATA) 41636413Ssklower tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna", 41736413Ssklower lowsave, tpcb->tp_sndhiwat, tpcb->tp_snduna, 0); 41836413Ssklower tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin", 41936413Ssklower lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); 42036413Ssklower ENDTRACE 42136413Ssklower 42236413Ssklower 42336413Ssklower if ( SEQ_GT(tpcb, lowseq, highseq) ) 42436413Ssklower return ; /* don't send, don't change hiwat, don't set timers */ 42536413Ssklower 42636413Ssklower ASSERT( SEQ_LEQ(tpcb, lowseq, highseq) ); 42736413Ssklower SEQ_DEC(tpcb, lowseq); 42836413Ssklower 42950901Ssklower if (tpcb->tp_Xsnd.sb_mb) { 43050901Ssklower IFTRACE(D_XPD) 43150901Ssklower tptraceTPCB( TPPTmisc, 43250901Ssklower "tp_send XPD mark low high tpcb.Xuna", 43350901Ssklower lowseq, highseq, tpcb->tp_Xsnd.sb_mb, 0); 43450901Ssklower ENDTRACE 43550901Ssklower /* stop sending here because there are unacked XPD present 43650901Ssklower */ 43750901Ssklower IncStat(ts_xpd_intheway); 43850901Ssklower goto done; 43950901Ssklower } 44036413Ssklower IFTRACE(D_DATA) 44136413Ssklower tptraceTPCB( TPPTmisc, "tp_send 2 low high fcredit congwin", 44236413Ssklower lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); 44336413Ssklower ENDTRACE 44436413Ssklower 44550901Ssklower if (m = tpcb->tp_sndhiwat_m) 44650901Ssklower mb = m->m_nextpkt; 44750901Ssklower else 44850901Ssklower mb = sb->sb_mb; 44950901Ssklower while ((SEQ_LT(tpcb, lowseq, highseq)) && mb ) { 45036413Ssklower 45150901Ssklower /* 45236413Ssklower * In all cases, m points to mbuf containing first octet to be 45336413Ssklower * sent in the tpdu AFTER the one we're going to send now, 45436413Ssklower * or else m is null. 45536413Ssklower * 45636413Ssklower * The chain we're working on now begins at mb and has length <len>. 45736413Ssklower */ 45836413Ssklower 45950901Ssklower eotsdu_reached = (mb->m_flags & M_EOR) != 0; 46050901Ssklower len = mb->m_pkthdr.len; 46136413Ssklower IFTRACE(D_STASH) 46236413Ssklower tptraceTPCB( TPPTmisc, 46336413Ssklower "tp_send mcopy low high eotsdu_reached len", 46436413Ssklower lowseq, highseq, eotsdu_reached, len); 46536413Ssklower ENDTRACE 46636413Ssklower 46736413Ssklower /* make a copy - mb goes into the retransmission list 46836413Ssklower * while m gets emitted. m_copy won't copy a zero-length mbuf. 46936413Ssklower */ 47050901Ssklower m = m_copy(mb, 0, M_COPYALL); 47150901Ssklower if (m == MNULL) 47236413Ssklower goto done; 47336413Ssklower SEQ_INC(tpcb,lowseq); /* it was decremented at the beginning */ 47436413Ssklower IFTRACE(D_DATA) 47536413Ssklower tptraceTPCB( TPPTmisc, 47639196Ssklower "tp_send emitting DT lowseq eotsdu_reached len", 47739196Ssklower lowseq, eotsdu_reached, len, 0); 47836413Ssklower ENDTRACE 47950901Ssklower if (mb->m_nextpkt == 0 && tpcb->tp_oktonagle) { 48050901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 48150901Ssklower tpcb->tp_oktonagle = 0; 48250901Ssklower /* when headers are precomputed, may need to fill 48350901Ssklower in checksum here */ 48450901Ssklower } 48550901Ssklower if (tpcb->tp_sock->so_error = 48650901Ssklower tp_emit(DT_TPDU_type, tpcb, lowseq, eotsdu_reached, m)) { 48736413Ssklower /* error */ 48836413Ssklower SEQ_DEC(tpcb, lowseq); 48936413Ssklower goto done; 49036413Ssklower } 49150901Ssklower tpcb->tp_sndhiwat_m = mb; 49250901Ssklower mb = mb->m_nextpkt; 49336413Ssklower /* set the transmit-time for computation of round-trip times */ 49436413Ssklower bcopy( (caddr_t)&time, 49536413Ssklower (caddr_t)&( tpcb->tp_rttemit[ lowseq & TP_RTT_NUM ] ), 49636413Ssklower sizeof(struct timeval)); 49736413Ssklower 49836413Ssklower } 49936413Ssklower 50036413Ssklower done: 50150236Ssklower #ifdef TP_PERF_MEAS 50236413Ssklower IFPERF(tpcb) 50336413Ssklower { 50436413Ssklower register int npkts; 50536413Ssklower struct timeval send_end_time; 50636413Ssklower register struct timeval *t; 50736413Ssklower 50836413Ssklower npkts = lowseq; 50936413Ssklower SEQ_INC(tpcb, npkts); 51036413Ssklower npkts = SEQ_SUB(tpcb, npkts, lowsave); 51136413Ssklower 51236413Ssklower if(npkts > 0) 51336413Ssklower tpcb->tp_Nwindow++; 51436413Ssklower 51536413Ssklower if (npkts > TP_PM_MAX) 51636413Ssklower npkts = TP_PM_MAX; 51736413Ssklower 51836413Ssklower GET_TIME_SINCE(&send_start_time, &send_end_time); 51936413Ssklower t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); 52036413Ssklower t->tv_sec = 52136413Ssklower SMOOTH( long, TP_RTT_ALPHA, t->tv_sec, send_end_time.tv_sec); 52236413Ssklower t->tv_usec = 52336413Ssklower SMOOTH( long, TP_RTT_ALPHA, t->tv_usec, send_end_time.tv_usec); 52436413Ssklower 52536413Ssklower if ( SEQ_LT(tpcb, lowseq, highseq) ) { 52636413Ssklower IncPStat(tpcb, tps_win_lim_by_data[npkts] ); 52736413Ssklower } else { 52836413Ssklower IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); 52936413Ssklower /* not true with congestion-window being used */ 53036413Ssklower } 53136413Ssklower tpmeas( tpcb->tp_lref, 53236413Ssklower TPsbsend, &send_end_time, lowsave, tpcb->tp_Nwindow, npkts); 53336413Ssklower } 53436413Ssklower ENDPERF 53550236Ssklower #endif TP_PERF_MEAS 53636413Ssklower 53736413Ssklower tpcb->tp_sndhiwat = lowseq; 53836413Ssklower 53936413Ssklower if ( SEQ_LEQ(tpcb, lowsave, tpcb->tp_sndhiwat) && 54036413Ssklower (tpcb->tp_class != TP_CLASS_0) ) 54136413Ssklower tp_etimeout(tpcb->tp_refp, TM_data_retrans, lowsave, 54236413Ssklower tpcb->tp_sndhiwat, 54336413Ssklower (u_int)tpcb->tp_Nretrans, (int)tpcb->tp_dt_ticks); 54436413Ssklower IFTRACE(D_DATA) 54536413Ssklower tptraceTPCB( TPPTmisc, 54636413Ssklower "tp_send at end: sndhiwat lowseq eotsdu_reached error", 54736413Ssklower tpcb->tp_sndhiwat, lowseq, eotsdu_reached, tpcb->tp_sock->so_error); 54836413Ssklower 54936413Ssklower ENDTRACE 55036413Ssklower } 55136413Ssklower 55250901Ssklower int TPNagleok; 55350901Ssklower int TPNagled; 55450901Ssklower 55550901Ssklower tp_packetize(tpcb, m, eotsdu) 55650901Ssklower register struct tp_pcb *tpcb; 55750901Ssklower register struct mbuf *m; 55850901Ssklower int eotsdu; 55950901Ssklower { 56050901Ssklower register struct mbuf *n; 56150901Ssklower register struct sockbuf *sb = &tpcb->tp_sock->so_snd; 56250901Ssklower int maxsize = tpcb->tp_l_tpdusize 56350901Ssklower - tp_headersize(DT_TPDU_type, tpcb) 56450901Ssklower - (tpcb->tp_use_checksum?4:0) ; 56550901Ssklower int totlen = m->m_pkthdr.len; 56650901Ssklower struct mbuf *m_split(); 56750901Ssklower /* 56850901Ssklower * Pre-packetize the data in the sockbuf 56950901Ssklower * according to negotiated mtu. Do it here 57050901Ssklower * where we can safely wait for mbufs. 57150901Ssklower * 57250901Ssklower * This presumes knowledge of sockbuf conventions. 57350901Ssklower * TODO: allocate space for header and fill it in (once!). 57450901Ssklower */ 57550901Ssklower IFTRACE(D_DATA) 57650901Ssklower tptraceTPCB(TPPTmisc, 57750901Ssklower "SEND BF: maxsize totlen eotsdu", 57850901Ssklower maxsize, totlen, eotsdu, 0); 57950901Ssklower ENDTRACE 58050901Ssklower if (tpcb->tp_oktonagle) { 58150901Ssklower if ((n = sb->sb_mb) == 0) 58250901Ssklower panic("tp_packetize"); 58350901Ssklower while (n->m_act) 58450901Ssklower n = n->m_act; 58550901Ssklower if (n->m_flags & M_EOR) 58650901Ssklower panic("tp_packetize 2"); 58750901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 58850901Ssklower if (totlen + n->m_pkthdr.len < maxsize) { 58950901Ssklower /* There is an unsent packet with space, combine data */ 59050901Ssklower struct mbuf *old_n = n; 59150901Ssklower tpsbcheck(tpcb,3); 59250901Ssklower n->m_pkthdr.len += totlen; 59350901Ssklower while (n->m_next) 59450901Ssklower n = n->m_next; 59550901Ssklower sbcompress(sb, m, n); 59650901Ssklower tpsbcheck(tpcb,4); 59750901Ssklower n = old_n; 59850901Ssklower TPNagled++; 59950901Ssklower goto out; 60050901Ssklower } 60150901Ssklower } 60250901Ssklower while (m) { 60350901Ssklower n = m; 60450901Ssklower if (totlen > maxsize) { 60550901Ssklower if ((m = m_split(n, maxsize, M_WAIT)) == 0) 60650901Ssklower panic("tp_packetize"); 60750901Ssklower } else 60850901Ssklower m = 0; 60950901Ssklower totlen -= maxsize; 61050901Ssklower tpsbcheck(tpcb, 5); 61150901Ssklower sbappendrecord(sb, n); 61250901Ssklower tpsbcheck(tpcb, 6); 61350901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 61450901Ssklower } 61550901Ssklower out: 61650901Ssklower if (eotsdu) { 61750901Ssklower n->m_flags |= M_EOR; /* XXX belongs at end */ 61850901Ssklower tpcb->tp_oktonagle = 0; 61950901Ssklower } else { 62050901Ssklower SEQ_DEC(tpcb, tpcb->tp_sndnum); 62150901Ssklower tpcb->tp_oktonagle = 1; 62250901Ssklower TPNagleok++; 62350901Ssklower } 62450901Ssklower return 0; 62550901Ssklower } 62650901Ssklower 62750901Ssklower 62836413Ssklower /* 62936413Ssklower * NAME: tp_stash() 63036413Ssklower * CALLED FROM: 63136413Ssklower * tp.trans on arrival of a DT tpdu 63236413Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 63336413Ssklower * Returns 1 if 63436413Ssklower * a) something new arrived and it's got eotsdu_reached bit on, 63536413Ssklower * b) this arrival was caused other out-of-sequence things to be 63636413Ssklower * accepted, or 63736413Ssklower * c) this arrival is the highest seq # for which we last gave credit 63836413Ssklower * (sender just sent a whole window) 63936413Ssklower * In other words, returns 1 if tp should send an ack immediately, 0 if 64036413Ssklower * the ack can wait a while. 64136413Ssklower * 64236413Ssklower * Note: this implementation no longer renegs on credit, (except 64336413Ssklower * when debugging option D_RENEG is on, for the purpose of testing 64436413Ssklower * ack subsequencing), so we don't need to check for incoming tpdus 64536413Ssklower * being in a reneged portion of the window. 64636413Ssklower */ 64736413Ssklower 64836413Ssklower tp_stash( tpcb, e ) 64936413Ssklower register struct tp_pcb *tpcb; 65036413Ssklower register struct tp_event *e; 65136413Ssklower { 65236413Ssklower register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; 65336413Ssklower /* 0--> delay acks until full window */ 65436413Ssklower /* 1--> ack each tpdu */ 65536413Ssklower #ifndef lint 65636413Ssklower #define E e->ATTR(DT_TPDU) 65736413Ssklower #else lint 65836413Ssklower #define E e->ev_union.EV_DT_TPDU 65936413Ssklower #endif lint 66036413Ssklower 66136413Ssklower if ( E.e_eot ) { 66236413Ssklower register struct mbuf *n = E.e_data; 66337469Ssklower n->m_flags |= M_EOR; 66438841Ssklower n->m_act = 0; 66537469Ssklower } 66636413Ssklower IFDEBUG(D_STASH) 66736413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 66836413Ssklower "stash: so_rcv before appending"); 66936413Ssklower dump_mbuf(E.e_data, 67036413Ssklower "stash: e_data before appending"); 67136413Ssklower ENDDEBUG 67236413Ssklower 67336413Ssklower IFPERF(tpcb) 67436413Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen; 67536413Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 67637469Ssklower E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); 67736413Ssklower ENDPERF 67836413Ssklower 679*51024Ssklower if (E.e_seq == tpcb->tp_rcvnxt) { 68036413Ssklower 68136413Ssklower IFDEBUG(D_STASH) 68236413Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", 68336413Ssklower E.e_seq, E.e_datalen, E.e_eot); 68436413Ssklower ENDDEBUG 68536413Ssklower 68636413Ssklower IFTRACE(D_STASH) 68736413Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 68836413Ssklower E.e_seq, E.e_datalen, E.e_eot, 0); 68936413Ssklower ENDTRACE 69036413Ssklower 691*51024Ssklower SET_DELACK(tpcb); 692*51024Ssklower 69337469Ssklower sbappend(&tpcb->tp_sock->so_rcv, E.e_data); 69437469Ssklower 69536413Ssklower SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 69636413Ssklower /* 69750901Ssklower * move chains from the reassembly queue to the socket buffer 69836413Ssklower */ 69950901Ssklower if (tpcb->tp_rsycnt) { 70050901Ssklower register struct mbuf **mp; 70150901Ssklower struct mbuf **mplim; 70236413Ssklower 70350901Ssklower mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit); 70450901Ssklower mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit; 70536413Ssklower 70650901Ssklower while (tpcb->tp_rsycnt && *mp) { 70750901Ssklower sbappend(&tpcb->tp_sock->so_rcv, *mp); 70850901Ssklower tpcb->tp_rsycnt--; 70950901Ssklower *mp = 0; 71050901Ssklower SEQ_INC(tpcb, tpcb->tp_rcvnxt); 71136413Ssklower ack_reason |= ACK_REORDER; 71250901Ssklower if (++mp == mplim) 71350901Ssklower mp = tpcb->tp_rsyq; 71436413Ssklower } 71536413Ssklower } 71636413Ssklower IFDEBUG(D_STASH) 71736413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 71836413Ssklower "stash: so_rcv after appending"); 71936413Ssklower ENDDEBUG 72036413Ssklower 72136413Ssklower } else { 72250901Ssklower register struct mbuf **mp; 72350901Ssklower SeqNum uwe; 72436413Ssklower 72536413Ssklower IFTRACE(D_STASH) 72636413Ssklower tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", 72736413Ssklower E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); 72836413Ssklower ENDTRACE 72936413Ssklower 73050975Ssklower if (tpcb->tp_rsyq == 0) 73150975Ssklower tp_rsyset(tpcb); 73250901Ssklower uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit); 73350901Ssklower if (tpcb->tp_rsyq == 0 || 73450901Ssklower !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) { 73536413Ssklower ack_reason = ACK_DONT; 73650901Ssklower m_freem(E.e_data); 73750901Ssklower } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) { 73836413Ssklower IFDEBUG(D_STASH) 73936413Ssklower printf("tp_stash - drop & ack\n"); 74036413Ssklower ENDDEBUG 74136413Ssklower 74236413Ssklower /* retransmission - drop it and force an ack */ 74336413Ssklower IncStat(ts_dt_dup); 74436413Ssklower IFPERF(tpcb) 74536413Ssklower IncPStat(tpcb, tps_n_ack_cuz_dup); 74636413Ssklower ENDPERF 74736413Ssklower 74850901Ssklower m_freem(E.e_data); 74936413Ssklower ack_reason |= ACK_DUP; 75050901Ssklower } else { 75150901Ssklower *mp = E.e_data; 75250901Ssklower tpcb->tp_rsycnt++; 75350901Ssklower ack_reason = ACK_DONT; 75436413Ssklower } 75536413Ssklower } 756*51024Ssklower /* there were some comments of historical interest here. */ 75736413Ssklower { 75836413Ssklower LOCAL_CREDIT(tpcb); 75936413Ssklower 76036413Ssklower if ( E.e_seq == tpcb->tp_sent_uwe ) 76136413Ssklower ack_reason |= ACK_STRAT_FULLWIN; 76236413Ssklower 76336413Ssklower IFTRACE(D_STASH) 76436413Ssklower tptraceTPCB(TPPTmisc, 76536413Ssklower "end of stash, eot, ack_reason, sent_uwe ", 76636413Ssklower E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); 76736413Ssklower ENDTRACE 76836413Ssklower 76936413Ssklower if ( ack_reason == ACK_DONT ) { 77036413Ssklower IncStat( ts_ackreason[ACK_DONT] ); 77136413Ssklower return 0; 77236413Ssklower } else { 77336413Ssklower IFPERF(tpcb) 77436413Ssklower if(ack_reason & ACK_STRAT_EACH) { 77536413Ssklower IncPStat(tpcb, tps_n_ack_cuz_strat); 77636413Ssklower } else if(ack_reason & ACK_STRAT_FULLWIN) { 77736413Ssklower IncPStat(tpcb, tps_n_ack_cuz_fullwin); 77836413Ssklower } else if(ack_reason & ACK_REORDER) { 77936413Ssklower IncPStat(tpcb, tps_n_ack_cuz_reorder); 78036413Ssklower } 78136413Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, 78236413Ssklower SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); 78336413Ssklower ENDPERF 78436413Ssklower { 78536413Ssklower register int i; 78636413Ssklower 78736413Ssklower /* keep track of all reasons that apply */ 78836413Ssklower for( i=1; i<_ACK_NUM_REASONS_ ;i++) { 78936413Ssklower if( ack_reason & (1<<i) ) 79036413Ssklower IncStat( ts_ackreason[i] ); 79136413Ssklower } 79236413Ssklower } 79336413Ssklower return 1; 79436413Ssklower } 79536413Ssklower } 79636413Ssklower } 79750901Ssklower 79850901Ssklower /* 79950901Ssklower * tp_rsyflush - drop all the packets on the reassembly queue. 80050901Ssklower * Do this when closing the socket, or when somebody has changed 80150901Ssklower * the space avaible in the receive socket (XXX). 80250901Ssklower */ 80350901Ssklower tp_rsyflush(tpcb) 80450901Ssklower register struct tp_pcb *tpcb; 80550901Ssklower { 80650901Ssklower register struct mbuf *m, **mp; 80750901Ssklower if (tpcb->tp_rsycnt) { 80850901Ssklower for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit; 80950901Ssklower --mp >= tpcb->tp_rsyq; ) 81050901Ssklower if (*mp) { 81150901Ssklower tpcb->tp_rsycnt--; 81250901Ssklower m_freem(*mp); 81350901Ssklower } 81450901Ssklower if (tpcb->tp_rsycnt) 81550901Ssklower panic("tp_rsyflush"); 81650901Ssklower } 81750901Ssklower free((caddr_t)tpcb->tp_rsyq, M_PCB); 81850901Ssklower tpcb->tp_rsyq = 0; 81950901Ssklower } 82050901Ssklower 82150901Ssklower tp_rsyset(tpcb) 82250901Ssklower register struct tp_pcb *tpcb; 82350901Ssklower { 82450901Ssklower register struct socket *so = tpcb->tp_sock; 82550901Ssklower int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf; 82650975Ssklower int old_credit = tpcb->tp_maxlcredit; 82750975Ssklower caddr_t rsyq; 82850901Ssklower 82950901Ssklower tpcb->tp_maxlcredit = maxcredit = min(maxcredit, 83050901Ssklower (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize); 83150901Ssklower 83250975Ssklower if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0) 83350975Ssklower return; 83450901Ssklower maxcredit *= sizeof(struct mbuf *); 83550901Ssklower if (tpcb->tp_rsyq) 83650901Ssklower tp_rsyflush(tpcb); 83750901Ssklower if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT)) 83850901Ssklower bzero(rsyq, maxcredit); 83950901Ssklower tpcb->tp_rsyq = (struct mbuf **)rsyq; 84050901Ssklower } 84150901Ssklower 84250901Ssklower tpsbcheck(tpcb, i) 84350901Ssklower struct tp_pcb *tpcb; 84450901Ssklower { 84550901Ssklower register struct mbuf *n, *m; 84650901Ssklower register int len = 0, mbcnt = 0, pktlen; 84750901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 84850901Ssklower 84950901Ssklower for (n = sb->sb_mb; n; n = n->m_nextpkt) { 85050901Ssklower if ((n->m_flags & M_PKTHDR) == 0) 85150901Ssklower panic("tpsbcheck nohdr"); 85250901Ssklower pktlen = len + n->m_pkthdr.len; 85350901Ssklower for (m = n; m; m = m->m_next) { 85450901Ssklower len += m->m_len; 85550901Ssklower mbcnt += MSIZE; 85650901Ssklower if (m->m_flags & M_EXT) 85750901Ssklower mbcnt += m->m_ext.ext_size; 85850901Ssklower } 85950901Ssklower if (len != pktlen) { 86050901Ssklower printf("test %d; len %d != pktlen %d on mbuf 0x%x\n", 86150901Ssklower i, len, pktlen, n); 86250901Ssklower panic("tpsbcheck short"); 86350901Ssklower } 86450901Ssklower } 86550901Ssklower if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { 86650901Ssklower printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc, 86750901Ssklower mbcnt, sb->sb_mbcnt); 86850901Ssklower panic("tpsbcheck"); 86950901Ssklower } 87050901Ssklower } 871