149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*51138Ssklower * @(#)tp_subr.c 7.14 (Berkeley) 09/17/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" 59*51138Ssklower #include "kernel.h" 6036413Ssklower 6137469Ssklower #include "tp_ip.h" 6237469Ssklower #include "iso.h" 6337469Ssklower #include "argo_debug.h" 6437469Ssklower #include "tp_timer.h" 6537469Ssklower #include "tp_param.h" 6637469Ssklower #include "tp_stat.h" 6737469Ssklower #include "tp_pcb.h" 6837469Ssklower #include "tp_tpdu.h" 6937469Ssklower #include "tp_trace.h" 7037469Ssklower #include "tp_meas.h" 7137469Ssklower #include "tp_seq.h" 7236413Ssklower 73*51138Ssklower int tp_emit(), tp_sbdrop(); 7436413Ssklower 7536413Ssklower /* 7636413Ssklower * CALLED FROM: 7736413Ssklower * tp.trans, when an XAK arrives 7836413Ssklower * FUNCTION and ARGUMENTS: 7936413Ssklower * Determines if the sequence number (seq) from the XAK 8036413Ssklower * acks anything new. If so, drop the appropriate tpdu 8136413Ssklower * from the XPD send queue. 8236413Ssklower * RETURN VALUE: 8336413Ssklower * Returns 1 if it did this, 0 if the ack caused no action. 8436413Ssklower */ 8536413Ssklower int 8636413Ssklower tp_goodXack(tpcb, seq) 8736413Ssklower struct tp_pcb *tpcb; 8836413Ssklower SeqNum seq; 8936413Ssklower { 9036413Ssklower 9136413Ssklower IFTRACE(D_XPD) 9236413Ssklower tptraceTPCB(TPPTgotXack, 9336413Ssklower seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndhiwat, 9436413Ssklower tpcb->tp_snduna); 9536413Ssklower ENDTRACE 9636413Ssklower 9736413Ssklower if ( seq == tpcb->tp_Xuna ) { 9836413Ssklower tpcb->tp_Xuna = tpcb->tp_Xsndnxt; 9936413Ssklower 10036413Ssklower /* DROP 1 packet from the Xsnd socket buf - just so happens 10136413Ssklower * that only one packet can be there at any time 10236413Ssklower * so drop the whole thing. If you allow > 1 packet 10336413Ssklower * the socket buffer, then you'll have to keep 10436413Ssklower * track of how many characters went w/ each XPD tpdu, so this 10536413Ssklower * will get messier 10636413Ssklower */ 10736413Ssklower IFDEBUG(D_XPD) 10836413Ssklower dump_mbuf(tpcb->tp_Xsnd.sb_mb, 10936413Ssklower "tp_goodXack Xsnd before sbdrop"); 11036413Ssklower ENDDEBUG 11136413Ssklower 11236413Ssklower IFTRACE(D_XPD) 11336413Ssklower tptraceTPCB(TPPTmisc, 11436413Ssklower "goodXack: dropping cc ", 11536413Ssklower (int)(tpcb->tp_Xsnd.sb_cc), 11636413Ssklower 0,0,0); 11736413Ssklower ENDTRACE 11836413Ssklower sbdrop( &tpcb->tp_Xsnd, (int)(tpcb->tp_Xsnd.sb_cc)); 11939922Ssklower CONG_ACK(tpcb, seq); 12036413Ssklower return 1; 12136413Ssklower } 12236413Ssklower return 0; 12336413Ssklower } 12436413Ssklower 12536413Ssklower /* 12636413Ssklower * CALLED FROM: 12736413Ssklower * tp_good_ack() 12836413Ssklower * FUNCTION and ARGUMENTS: 12936413Ssklower * updates 130*51138Ssklower * smoothed average round trip time (*rtt) 131*51138Ssklower * roundtrip time variance (*rtv) - actually deviation, not variance 13236413Ssklower * given the new value (diff) 13336413Ssklower * RETURN VALUE: 13436413Ssklower * void 13536413Ssklower */ 13636413Ssklower 13736413Ssklower void 138*51138Ssklower tp_rtt_rtv( rtt, rtv, newmeas ) 139*51138Ssklower register int *rtt, *rtv; 140*51138Ssklower int newmeas; 14136413Ssklower { 142*51138Ssklower int delta = newmeas - *rtt; 14336413Ssklower 144*51138Ssklower if ((*rtt += (delta >> TP_RTT_ALPHA)) <= 0) 145*51138Ssklower *rtt = 1; 146*51138Ssklower if (delta < 0) 147*51138Ssklower delta = -delta; 148*51138Ssklower if (*rtv = ((delta - *rtv) >> TP_RTV_ALPHA) <= 0) 149*51138Ssklower *rtv = 1; 15036413Ssklower } 15136413Ssklower 15236413Ssklower /* 15336413Ssklower * CALLED FROM: 15436413Ssklower * tp.trans when an AK arrives 15536413Ssklower * FUNCTION and ARGUMENTS: 15636413Ssklower * Given (cdt), the credit from the AK tpdu, and 15736413Ssklower * (seq), the sequence number from the AK tpdu, 15836413Ssklower * tp_goodack() determines if the AK acknowledges something in the send 15936413Ssklower * window, and if so, drops the appropriate packets from the retransmission 16036413Ssklower * list, computes the round trip time, and updates the retransmission timer 16136413Ssklower * based on the new smoothed round trip time. 16236413Ssklower * RETURN VALUE: 16336413Ssklower * Returns 1 if 16436413Ssklower * EITHER it actually acked something heretofore unacknowledged 16536413Ssklower * OR no news but the credit should be processed. 16636413Ssklower * If something heretofore unacked was acked with this sequence number, 16736413Ssklower * the appropriate tpdus are dropped from the retransmission control list, 16836413Ssklower * by calling tp_sbdrop(). 16936413Ssklower * No need to see the tpdu itself. 17036413Ssklower */ 17136413Ssklower int 17236413Ssklower tp_goodack(tpcb, cdt, seq, subseq) 17336413Ssklower register struct tp_pcb *tpcb; 17436413Ssklower u_int cdt; 17536413Ssklower register SeqNum seq, subseq; 17636413Ssklower { 17736413Ssklower int old_fcredit = tpcb->tp_fcredit; 17836413Ssklower int bang = 0; /* bang --> ack for something heretofore unacked */ 17936413Ssklower 18036413Ssklower IFDEBUG(D_ACKRECV) 18136413Ssklower printf("goodack seq 0x%x cdt 0x%x snduna 0x%x sndhiwat 0x%x\n", 18236413Ssklower seq, cdt, tpcb->tp_snduna, tpcb->tp_sndhiwat); 18336413Ssklower ENDDEBUG 18436413Ssklower IFTRACE(D_ACKRECV) 18536413Ssklower tptraceTPCB(TPPTgotack, 18636413Ssklower seq,cdt, tpcb->tp_snduna,tpcb->tp_sndhiwat,subseq); 18736413Ssklower ENDTRACE 18836413Ssklower 18936413Ssklower IFPERF(tpcb) 19037469Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0); 19136413Ssklower ENDPERF 19236413Ssklower 19336413Ssklower if ( subseq != 0 && (subseq <= tpcb->tp_r_subseq) ) { 19436413Ssklower /* discard the ack */ 19536413Ssklower IFTRACE(D_ACKRECV) 19636413Ssklower tptraceTPCB(TPPTmisc, "goodack discard : subseq tp_r_subseq", 19736413Ssklower subseq, tpcb->tp_r_subseq, 0, 0); 19836413Ssklower ENDTRACE 19936413Ssklower return 0; 20036413Ssklower } else { 20136413Ssklower tpcb->tp_r_subseq = subseq; 20236413Ssklower } 20336413Ssklower 20436413Ssklower if ( IN_SWINDOW(tpcb, seq, 20536413Ssklower tpcb->tp_snduna, SEQ(tpcb, tpcb->tp_sndhiwat+1)) ) { 20636413Ssklower 20736413Ssklower IFDEBUG(D_XPD) 20836413Ssklower dump_mbuf(tpcb->tp_sock->so_snd.sb_mb, 20936413Ssklower "tp_goodack snd before sbdrop"); 21036413Ssklower ENDDEBUG 21150901Ssklower tpsbcheck(tpcb, 0); 212*51138Ssklower (void)tp_sbdrop(tpcb, seq); 21350901Ssklower tpsbcheck(tpcb, 1); 21436413Ssklower 21536413Ssklower /* increase congestion window but don't let it get too big */ 21636413Ssklower { 21736413Ssklower register int maxcdt = tpcb->tp_xtd_format?0xffff:0xf; 21839922Ssklower CONG_ACK(tpcb, seq); 21936413Ssklower } 22036413Ssklower 22136413Ssklower /* Compute smoothed round trip time. 222*51138Ssklower * Only measure rtt for tp_snduna if acked and the data 22339922Ssklower * were not retransmitted. 22436413Ssklower */ 225*51138Ssklower if (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq)) { 226*51138Ssklower int x = tick - tpcb->tp_rttemit; 22736413Ssklower 228*51138Ssklower if (tpcb->tp_rtt) 229*51138Ssklower tp_rtt_rtv(&(tpcb->tp_rtt), &(tpcb->tp_rtv), x); 230*51138Ssklower else { 231*51138Ssklower tpcb->tp_rtt = x; 232*51138Ssklower tpcb->tp_rtv = x >> 1; 233*51138Ssklower } 23436413Ssklower 23536413Ssklower { /* update the global rtt, rtv stats */ 236*51138Ssklower int i = tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN); 237*51138Ssklower tp_rtt_rtv(tp_stat.ts_rtt + i, tp_stat.ts_rtv + i, x); 23836413Ssklower 23936413Ssklower IFTRACE(D_RTT) 24036413Ssklower tptraceTPCB(TPPTmisc, "Global rtt, rtv: i", i, 0, 0, 0); 24136413Ssklower ENDTRACE 24236413Ssklower } 24336413Ssklower 24436413Ssklower IFTRACE(D_RTT) 24536413Ssklower tptraceTPCB(TPPTmisc, 24636413Ssklower "Smoothed rtt: tp_snduna, (time.sec, time.usec), peer_acktime", 24736413Ssklower tpcb->tp_snduna, time.tv_sec, time.tv_usec, 24836413Ssklower tpcb->tp_peer_acktime); 24936413Ssklower 25036413Ssklower tptraceTPCB(TPPTmisc, 251*51138Ssklower "(secs): emittime diff(x) rtt, rtv", 252*51138Ssklower tpcb->tp_rttemit, x, tpcb->tp_rtt, tpcb->tp_rtv); 25336413Ssklower ENDTRACE 25436413Ssklower 25536413Ssklower { 25636413Ssklower /* Update data retransmission timer based on the smoothed 25736413Ssklower * round trip time, peer ack time, and the pseudo-arbitrary 258*51138Ssklower * number 2. 259*51138Ssklower * new ticks: (avg rtt + 4*dev) 260*51138Ssklower * rtt, rtv are in hz-ticks, 261*51138Ssklower * and slowtimo-ticks are hz / 2; 262*51138Ssklower * We want no less than peer ack time and no less than 2 26336413Ssklower */ 26436413Ssklower 26536413Ssklower 266*51138Ssklower int rtt = tpcb->tp_rtt, rtv = tpcb->tp_rtv, 267*51138Ssklower old = tpcb->tp_dt_ticks, new; 268*51138Ssklower 269*51138Ssklower new = (((rtt + (rtv << 2)) << 1) + hz) / hz; 270*51138Ssklower new = MAX(new + 1, old); 271*51138Ssklower new = MAX(new, tpcb->tp_peer_acktime); 272*51138Ssklower new = MAX(new, 2); 27336413Ssklower IFTRACE(D_RTT) 27436413Ssklower tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks", 275*51138Ssklower old, rtv, rtt, new); 27636413Ssklower ENDTRACE 277*51138Ssklower tpcb->tp_dt_ticks = new; 27836413Ssklower } 279*51138Ssklower tpcb->tp_rxtcur = tpcb->tp_dt_ticks; 280*51138Ssklower tpcb->tp_rxtshift = 0; 281*51138Ssklower 28236413Ssklower } 28336413Ssklower tpcb->tp_snduna = seq; 28439922Ssklower tpcb->tp_retrans = tpcb->tp_Nretrans; /* CE_BIT */ 28536413Ssklower 28636413Ssklower bang++; 28736413Ssklower } 28836413Ssklower 28936413Ssklower if( cdt != 0 && old_fcredit == 0 ) { 29036413Ssklower tpcb->tp_sendfcc = 1; 29136413Ssklower } 29236413Ssklower if( cdt == 0 && old_fcredit != 0 ) { 29336413Ssklower IncStat(ts_zfcdt); 29436413Ssklower } 29536413Ssklower tpcb->tp_fcredit = cdt; 29636413Ssklower 29736413Ssklower IFDEBUG(D_ACKRECV) 29836413Ssklower printf("goodack returning 0x%x, bang 0x%x cdt 0x%x old_fcredit 0x%x\n", 29936413Ssklower (bang || (old_fcredit < cdt) ), bang, cdt, old_fcredit ); 30036413Ssklower ENDDEBUG 30136413Ssklower 30236413Ssklower return (bang || (old_fcredit < cdt)) ; 30336413Ssklower } 30436413Ssklower 30536413Ssklower /* 30636413Ssklower * CALLED FROM: 30736413Ssklower * tp_goodack() 30836413Ssklower * FUNCTION and ARGUMENTS: 30950901Ssklower * drops everything up TO but not INCLUDING seq # (seq) 31036413Ssklower * from the retransmission queue. 31136413Ssklower */ 31236413Ssklower tp_sbdrop(tpcb, seq) 31350901Ssklower register struct tp_pcb *tpcb; 31436413Ssklower SeqNum seq; 31536413Ssklower { 31650901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 31750901Ssklower register int i = ((int)seq)-((int)tpcb->tp_snduna); 318*51138Ssklower int oldcc = sb->sb_cc; 31936413Ssklower 32050901Ssklower if (i < 0) i += tpcb->tp_seqhalf; 32136413Ssklower IFDEBUG(D_ACKRECV) 32250901Ssklower printf("tp_sbdroping %d up through seq 0x%x\n", i, seq); 32336413Ssklower ENDDEBUG 32450901Ssklower while (i-- > 0) 32550901Ssklower sbdroprecord(sb); 32650901Ssklower if (SEQ_LT(tpcb, tpcb->tp_sndhiwat, seq)) 32750901Ssklower tpcb->tp_sndhiwat_m = 0; 328*51138Ssklower return (oldcc - sb->sb_cc); 32936413Ssklower } 33036413Ssklower 33136413Ssklower /* 33236413Ssklower * CALLED FROM: 33336413Ssklower * tp.trans on user send request, arrival of AK and arrival of XAK 33436413Ssklower * FUNCTION and ARGUMENTS: 33536413Ssklower * Emits tpdus starting at sequence number (lowseq). 33636413Ssklower * Emits until a) runs out of data, or b) runs into an XPD mark, or 33736413Ssklower * c) it hits seq number (highseq) 33836413Ssklower * 33936413Ssklower * If you want XPD to buffer > 1 du per socket buffer, you can 34036413Ssklower * modifiy this to issue XPD tpdus also, but then it'll have 34136413Ssklower * to take some argument(s) to distinguish between the type of DU to 34250901Ssklower * hand tp_emit. 34336413Ssklower * 34436413Ssklower * When something is sent for the first time, its time-of-send 34536413Ssklower * is stashed (the last RTT_NUM of them are stashed). When the 34636413Ssklower * ack arrives, the smoothed round-trip time is figured using this value. 34736413Ssklower * RETURN VALUE: 34836413Ssklower * the highest seq # sent successfully. 34936413Ssklower */ 35036413Ssklower tp_send(tpcb) 35136413Ssklower register struct tp_pcb *tpcb; 35236413Ssklower { 35336413Ssklower register int len; 35436413Ssklower register struct mbuf *m; /* the one we're inspecting now */ 35536413Ssklower struct mbuf *mb;/* beginning of this tpdu */ 35636413Ssklower struct mbuf *nextrecord; /* NOT next tpdu but next sb record */ 35736413Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 35836413Ssklower unsigned int eotsdu_reached=0; 35936413Ssklower SeqNum lowseq, highseq ; 36036413Ssklower SeqNum lowsave; 36136413Ssklower #ifdef TP_PERF_MEAS 36250236Ssklower 363*51138Ssklower int send_start_time = tick; 36436413Ssklower #endif TP_PERF_MEAS 36536413Ssklower 36636413Ssklower lowsave = lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1); 36736413Ssklower 36836413Ssklower ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff); 36936413Ssklower 37036413Ssklower if( tpcb->tp_rx_strat & TPRX_USE_CW ) { 37136413Ssklower /*first hiseq is temp vbl*/ 37236413Ssklower highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win); 37336413Ssklower } else { 37436413Ssklower highseq = tpcb->tp_fcredit; 37536413Ssklower } 37636413Ssklower highseq = SEQ(tpcb, tpcb->tp_snduna + highseq); 37736413Ssklower 37836413Ssklower SEQ_DEC(tpcb, highseq); 37936413Ssklower 38036413Ssklower IFDEBUG(D_DATA) 38136413Ssklower printf( 38236413Ssklower "tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n", 38336413Ssklower tpcb, lowseq, highseq); 38436413Ssklower dump_mbuf(sb->sb_mb, "sb_mb:"); 38536413Ssklower ENDDEBUG 38636413Ssklower IFTRACE(D_DATA) 38736413Ssklower tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna", 38836413Ssklower lowsave, tpcb->tp_sndhiwat, tpcb->tp_snduna, 0); 38936413Ssklower tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin", 39036413Ssklower lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); 39136413Ssklower ENDTRACE 39236413Ssklower 39336413Ssklower 39436413Ssklower if ( SEQ_GT(tpcb, lowseq, highseq) ) 39536413Ssklower return ; /* don't send, don't change hiwat, don't set timers */ 39636413Ssklower 39736413Ssklower ASSERT( SEQ_LEQ(tpcb, lowseq, highseq) ); 39836413Ssklower SEQ_DEC(tpcb, lowseq); 39936413Ssklower 40050901Ssklower if (tpcb->tp_Xsnd.sb_mb) { 40150901Ssklower IFTRACE(D_XPD) 40250901Ssklower tptraceTPCB( TPPTmisc, 40350901Ssklower "tp_send XPD mark low high tpcb.Xuna", 40450901Ssklower lowseq, highseq, tpcb->tp_Xsnd.sb_mb, 0); 40550901Ssklower ENDTRACE 40650901Ssklower /* stop sending here because there are unacked XPD present 40750901Ssklower */ 40850901Ssklower IncStat(ts_xpd_intheway); 40950901Ssklower goto done; 41050901Ssklower } 41136413Ssklower IFTRACE(D_DATA) 41236413Ssklower tptraceTPCB( TPPTmisc, "tp_send 2 low high fcredit congwin", 41336413Ssklower lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); 41436413Ssklower ENDTRACE 41536413Ssklower 41650901Ssklower if (m = tpcb->tp_sndhiwat_m) 41750901Ssklower mb = m->m_nextpkt; 41850901Ssklower else 41950901Ssklower mb = sb->sb_mb; 42050901Ssklower while ((SEQ_LT(tpcb, lowseq, highseq)) && mb ) { 42136413Ssklower 42250901Ssklower /* 42336413Ssklower * In all cases, m points to mbuf containing first octet to be 42436413Ssklower * sent in the tpdu AFTER the one we're going to send now, 42536413Ssklower * or else m is null. 42636413Ssklower * 42736413Ssklower * The chain we're working on now begins at mb and has length <len>. 42836413Ssklower */ 42936413Ssklower 43050901Ssklower eotsdu_reached = (mb->m_flags & M_EOR) != 0; 43150901Ssklower len = mb->m_pkthdr.len; 43236413Ssklower IFTRACE(D_STASH) 43336413Ssklower tptraceTPCB( TPPTmisc, 43436413Ssklower "tp_send mcopy low high eotsdu_reached len", 43536413Ssklower lowseq, highseq, eotsdu_reached, len); 43636413Ssklower ENDTRACE 43736413Ssklower 43836413Ssklower /* make a copy - mb goes into the retransmission list 43936413Ssklower * while m gets emitted. m_copy won't copy a zero-length mbuf. 44036413Ssklower */ 44150901Ssklower m = m_copy(mb, 0, M_COPYALL); 44250901Ssklower if (m == MNULL) 44336413Ssklower goto done; 44436413Ssklower SEQ_INC(tpcb,lowseq); /* it was decremented at the beginning */ 44536413Ssklower IFTRACE(D_DATA) 44636413Ssklower tptraceTPCB( TPPTmisc, 44739196Ssklower "tp_send emitting DT lowseq eotsdu_reached len", 44839196Ssklower lowseq, eotsdu_reached, len, 0); 44936413Ssklower ENDTRACE 45050901Ssklower if (mb->m_nextpkt == 0 && tpcb->tp_oktonagle) { 45150901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 45250901Ssklower tpcb->tp_oktonagle = 0; 45350901Ssklower /* when headers are precomputed, may need to fill 45450901Ssklower in checksum here */ 45550901Ssklower } 45650901Ssklower if (tpcb->tp_sock->so_error = 45750901Ssklower tp_emit(DT_TPDU_type, tpcb, lowseq, eotsdu_reached, m)) { 45836413Ssklower /* error */ 45936413Ssklower SEQ_DEC(tpcb, lowseq); 46036413Ssklower goto done; 46136413Ssklower } 462*51138Ssklower /* set the transmit-time for computation of round-trip times */ 463*51138Ssklower if (tpcb->tp_rttemit == 0) { 464*51138Ssklower tpcb->tp_rttemit = tick; 465*51138Ssklower tpcb->tp_rttseq = lowseq; 466*51138Ssklower } 46750901Ssklower tpcb->tp_sndhiwat_m = mb; 46850901Ssklower mb = mb->m_nextpkt; 46936413Ssklower } 47036413Ssklower 47136413Ssklower done: 47250236Ssklower #ifdef TP_PERF_MEAS 47336413Ssklower IFPERF(tpcb) 47436413Ssklower { 47536413Ssklower register int npkts; 476*51138Ssklower int elapsed = tick - send_start_time, *t; 477*51138Ssklower struct timeval now; 47836413Ssklower 47936413Ssklower npkts = lowseq; 48036413Ssklower SEQ_INC(tpcb, npkts); 48136413Ssklower npkts = SEQ_SUB(tpcb, npkts, lowsave); 48236413Ssklower 48336413Ssklower if(npkts > 0) 48436413Ssklower tpcb->tp_Nwindow++; 48536413Ssklower 48636413Ssklower if (npkts > TP_PM_MAX) 48736413Ssklower npkts = TP_PM_MAX; 48836413Ssklower 48936413Ssklower t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); 490*51138Ssklower *t += (t - elapsed) >> TP_RTT_ALPHA; 49136413Ssklower 49236413Ssklower if ( SEQ_LT(tpcb, lowseq, highseq) ) { 49336413Ssklower IncPStat(tpcb, tps_win_lim_by_data[npkts] ); 49436413Ssklower } else { 49536413Ssklower IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); 49636413Ssklower /* not true with congestion-window being used */ 49736413Ssklower } 498*51138Ssklower now.tv_sec = elapsed / hz; 499*51138Ssklower now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz; 50036413Ssklower tpmeas( tpcb->tp_lref, 501*51138Ssklower TPsbsend, &elapsed, lowsave, tpcb->tp_Nwindow, npkts); 50236413Ssklower } 50336413Ssklower ENDPERF 50450236Ssklower #endif TP_PERF_MEAS 50536413Ssklower 50636413Ssklower tpcb->tp_sndhiwat = lowseq; 50736413Ssklower 50836413Ssklower if ( SEQ_LEQ(tpcb, lowsave, tpcb->tp_sndhiwat) && 50936413Ssklower (tpcb->tp_class != TP_CLASS_0) ) 51036413Ssklower tp_etimeout(tpcb->tp_refp, TM_data_retrans, lowsave, 51136413Ssklower tpcb->tp_sndhiwat, 51236413Ssklower (u_int)tpcb->tp_Nretrans, (int)tpcb->tp_dt_ticks); 51336413Ssklower IFTRACE(D_DATA) 51436413Ssklower tptraceTPCB( TPPTmisc, 51536413Ssklower "tp_send at end: sndhiwat lowseq eotsdu_reached error", 51636413Ssklower tpcb->tp_sndhiwat, lowseq, eotsdu_reached, tpcb->tp_sock->so_error); 51736413Ssklower 51836413Ssklower ENDTRACE 51936413Ssklower } 52036413Ssklower 52150901Ssklower int TPNagleok; 52250901Ssklower int TPNagled; 52350901Ssklower 52450901Ssklower tp_packetize(tpcb, m, eotsdu) 52550901Ssklower register struct tp_pcb *tpcb; 52650901Ssklower register struct mbuf *m; 52750901Ssklower int eotsdu; 52850901Ssklower { 52950901Ssklower register struct mbuf *n; 53050901Ssklower register struct sockbuf *sb = &tpcb->tp_sock->so_snd; 53150901Ssklower int maxsize = tpcb->tp_l_tpdusize 53250901Ssklower - tp_headersize(DT_TPDU_type, tpcb) 53350901Ssklower - (tpcb->tp_use_checksum?4:0) ; 53450901Ssklower int totlen = m->m_pkthdr.len; 53550901Ssklower struct mbuf *m_split(); 53650901Ssklower /* 53750901Ssklower * Pre-packetize the data in the sockbuf 53850901Ssklower * according to negotiated mtu. Do it here 53950901Ssklower * where we can safely wait for mbufs. 54050901Ssklower * 54150901Ssklower * This presumes knowledge of sockbuf conventions. 54250901Ssklower * TODO: allocate space for header and fill it in (once!). 54350901Ssklower */ 54450901Ssklower IFTRACE(D_DATA) 54550901Ssklower tptraceTPCB(TPPTmisc, 54650901Ssklower "SEND BF: maxsize totlen eotsdu", 54750901Ssklower maxsize, totlen, eotsdu, 0); 54850901Ssklower ENDTRACE 54950901Ssklower if (tpcb->tp_oktonagle) { 55050901Ssklower if ((n = sb->sb_mb) == 0) 55150901Ssklower panic("tp_packetize"); 55250901Ssklower while (n->m_act) 55350901Ssklower n = n->m_act; 55450901Ssklower if (n->m_flags & M_EOR) 55550901Ssklower panic("tp_packetize 2"); 55650901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 55750901Ssklower if (totlen + n->m_pkthdr.len < maxsize) { 55850901Ssklower /* There is an unsent packet with space, combine data */ 55950901Ssklower struct mbuf *old_n = n; 56050901Ssklower tpsbcheck(tpcb,3); 56150901Ssklower n->m_pkthdr.len += totlen; 56250901Ssklower while (n->m_next) 56350901Ssklower n = n->m_next; 56450901Ssklower sbcompress(sb, m, n); 56550901Ssklower tpsbcheck(tpcb,4); 56650901Ssklower n = old_n; 56750901Ssklower TPNagled++; 56850901Ssklower goto out; 56950901Ssklower } 57050901Ssklower } 57150901Ssklower while (m) { 57250901Ssklower n = m; 57350901Ssklower if (totlen > maxsize) { 57450901Ssklower if ((m = m_split(n, maxsize, M_WAIT)) == 0) 57550901Ssklower panic("tp_packetize"); 57650901Ssklower } else 57750901Ssklower m = 0; 57850901Ssklower totlen -= maxsize; 57950901Ssklower tpsbcheck(tpcb, 5); 58050901Ssklower sbappendrecord(sb, n); 58150901Ssklower tpsbcheck(tpcb, 6); 58250901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 58350901Ssklower } 58450901Ssklower out: 58550901Ssklower if (eotsdu) { 58650901Ssklower n->m_flags |= M_EOR; /* XXX belongs at end */ 58750901Ssklower tpcb->tp_oktonagle = 0; 58850901Ssklower } else { 58950901Ssklower SEQ_DEC(tpcb, tpcb->tp_sndnum); 59050901Ssklower tpcb->tp_oktonagle = 1; 59150901Ssklower TPNagleok++; 59250901Ssklower } 59350901Ssklower return 0; 59450901Ssklower } 59550901Ssklower 59650901Ssklower 59736413Ssklower /* 59836413Ssklower * NAME: tp_stash() 59936413Ssklower * CALLED FROM: 60036413Ssklower * tp.trans on arrival of a DT tpdu 60136413Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 60236413Ssklower * Returns 1 if 60336413Ssklower * a) something new arrived and it's got eotsdu_reached bit on, 60436413Ssklower * b) this arrival was caused other out-of-sequence things to be 60536413Ssklower * accepted, or 60636413Ssklower * c) this arrival is the highest seq # for which we last gave credit 60736413Ssklower * (sender just sent a whole window) 60836413Ssklower * In other words, returns 1 if tp should send an ack immediately, 0 if 60936413Ssklower * the ack can wait a while. 61036413Ssklower * 61136413Ssklower * Note: this implementation no longer renegs on credit, (except 61236413Ssklower * when debugging option D_RENEG is on, for the purpose of testing 61336413Ssklower * ack subsequencing), so we don't need to check for incoming tpdus 61436413Ssklower * being in a reneged portion of the window. 61536413Ssklower */ 61636413Ssklower 61736413Ssklower tp_stash( tpcb, e ) 61836413Ssklower register struct tp_pcb *tpcb; 61936413Ssklower register struct tp_event *e; 62036413Ssklower { 62136413Ssklower register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; 62236413Ssklower /* 0--> delay acks until full window */ 62336413Ssklower /* 1--> ack each tpdu */ 62436413Ssklower #ifndef lint 62536413Ssklower #define E e->ATTR(DT_TPDU) 62636413Ssklower #else lint 62736413Ssklower #define E e->ev_union.EV_DT_TPDU 62836413Ssklower #endif lint 62936413Ssklower 63036413Ssklower if ( E.e_eot ) { 63136413Ssklower register struct mbuf *n = E.e_data; 63237469Ssklower n->m_flags |= M_EOR; 63338841Ssklower n->m_act = 0; 63437469Ssklower } 63536413Ssklower IFDEBUG(D_STASH) 63636413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 63736413Ssklower "stash: so_rcv before appending"); 63836413Ssklower dump_mbuf(E.e_data, 63936413Ssklower "stash: e_data before appending"); 64036413Ssklower ENDDEBUG 64136413Ssklower 64236413Ssklower IFPERF(tpcb) 64336413Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen; 64436413Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 64537469Ssklower E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); 64636413Ssklower ENDPERF 64736413Ssklower 64851024Ssklower if (E.e_seq == tpcb->tp_rcvnxt) { 64936413Ssklower 65036413Ssklower IFDEBUG(D_STASH) 65136413Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", 65236413Ssklower E.e_seq, E.e_datalen, E.e_eot); 65336413Ssklower ENDDEBUG 65436413Ssklower 65536413Ssklower IFTRACE(D_STASH) 65636413Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 65736413Ssklower E.e_seq, E.e_datalen, E.e_eot, 0); 65836413Ssklower ENDTRACE 65936413Ssklower 66051024Ssklower SET_DELACK(tpcb); 66151024Ssklower 66237469Ssklower sbappend(&tpcb->tp_sock->so_rcv, E.e_data); 66337469Ssklower 66436413Ssklower SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 66536413Ssklower /* 66650901Ssklower * move chains from the reassembly queue to the socket buffer 66736413Ssklower */ 66850901Ssklower if (tpcb->tp_rsycnt) { 66950901Ssklower register struct mbuf **mp; 67050901Ssklower struct mbuf **mplim; 67136413Ssklower 67250901Ssklower mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit); 67350901Ssklower mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit; 67436413Ssklower 67550901Ssklower while (tpcb->tp_rsycnt && *mp) { 67650901Ssklower sbappend(&tpcb->tp_sock->so_rcv, *mp); 67750901Ssklower tpcb->tp_rsycnt--; 67850901Ssklower *mp = 0; 67950901Ssklower SEQ_INC(tpcb, tpcb->tp_rcvnxt); 68036413Ssklower ack_reason |= ACK_REORDER; 68150901Ssklower if (++mp == mplim) 68250901Ssklower mp = tpcb->tp_rsyq; 68336413Ssklower } 68436413Ssklower } 68536413Ssklower IFDEBUG(D_STASH) 68636413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 68736413Ssklower "stash: so_rcv after appending"); 68836413Ssklower ENDDEBUG 68936413Ssklower 69036413Ssklower } else { 69150901Ssklower register struct mbuf **mp; 69250901Ssklower SeqNum uwe; 69336413Ssklower 69436413Ssklower IFTRACE(D_STASH) 69536413Ssklower tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", 69636413Ssklower E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); 69736413Ssklower ENDTRACE 69836413Ssklower 69950975Ssklower if (tpcb->tp_rsyq == 0) 70050975Ssklower tp_rsyset(tpcb); 70150901Ssklower uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit); 70250901Ssklower if (tpcb->tp_rsyq == 0 || 70350901Ssklower !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) { 70436413Ssklower ack_reason = ACK_DONT; 70550901Ssklower m_freem(E.e_data); 70650901Ssklower } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) { 70736413Ssklower IFDEBUG(D_STASH) 70836413Ssklower printf("tp_stash - drop & ack\n"); 70936413Ssklower ENDDEBUG 71036413Ssklower 71136413Ssklower /* retransmission - drop it and force an ack */ 71236413Ssklower IncStat(ts_dt_dup); 71336413Ssklower IFPERF(tpcb) 71436413Ssklower IncPStat(tpcb, tps_n_ack_cuz_dup); 71536413Ssklower ENDPERF 71636413Ssklower 71750901Ssklower m_freem(E.e_data); 71836413Ssklower ack_reason |= ACK_DUP; 71950901Ssklower } else { 72050901Ssklower *mp = E.e_data; 72150901Ssklower tpcb->tp_rsycnt++; 72250901Ssklower ack_reason = ACK_DONT; 72336413Ssklower } 72436413Ssklower } 72551024Ssklower /* there were some comments of historical interest here. */ 72636413Ssklower { 72736413Ssklower LOCAL_CREDIT(tpcb); 72836413Ssklower 72936413Ssklower if ( E.e_seq == tpcb->tp_sent_uwe ) 73036413Ssklower ack_reason |= ACK_STRAT_FULLWIN; 73136413Ssklower 73236413Ssklower IFTRACE(D_STASH) 73336413Ssklower tptraceTPCB(TPPTmisc, 73436413Ssklower "end of stash, eot, ack_reason, sent_uwe ", 73536413Ssklower E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); 73636413Ssklower ENDTRACE 73736413Ssklower 73836413Ssklower if ( ack_reason == ACK_DONT ) { 73936413Ssklower IncStat( ts_ackreason[ACK_DONT] ); 74036413Ssklower return 0; 74136413Ssklower } else { 74236413Ssklower IFPERF(tpcb) 74336413Ssklower if(ack_reason & ACK_STRAT_EACH) { 74436413Ssklower IncPStat(tpcb, tps_n_ack_cuz_strat); 74536413Ssklower } else if(ack_reason & ACK_STRAT_FULLWIN) { 74636413Ssklower IncPStat(tpcb, tps_n_ack_cuz_fullwin); 74736413Ssklower } else if(ack_reason & ACK_REORDER) { 74836413Ssklower IncPStat(tpcb, tps_n_ack_cuz_reorder); 74936413Ssklower } 75036413Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, 75136413Ssklower SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); 75236413Ssklower ENDPERF 75336413Ssklower { 75436413Ssklower register int i; 75536413Ssklower 75636413Ssklower /* keep track of all reasons that apply */ 75736413Ssklower for( i=1; i<_ACK_NUM_REASONS_ ;i++) { 75836413Ssklower if( ack_reason & (1<<i) ) 75936413Ssklower IncStat( ts_ackreason[i] ); 76036413Ssklower } 76136413Ssklower } 76236413Ssklower return 1; 76336413Ssklower } 76436413Ssklower } 76536413Ssklower } 76650901Ssklower 76750901Ssklower /* 76850901Ssklower * tp_rsyflush - drop all the packets on the reassembly queue. 76950901Ssklower * Do this when closing the socket, or when somebody has changed 77050901Ssklower * the space avaible in the receive socket (XXX). 77150901Ssklower */ 77250901Ssklower tp_rsyflush(tpcb) 77350901Ssklower register struct tp_pcb *tpcb; 77450901Ssklower { 77550901Ssklower register struct mbuf *m, **mp; 77650901Ssklower if (tpcb->tp_rsycnt) { 77750901Ssklower for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit; 77850901Ssklower --mp >= tpcb->tp_rsyq; ) 77950901Ssklower if (*mp) { 78050901Ssklower tpcb->tp_rsycnt--; 78150901Ssklower m_freem(*mp); 78250901Ssklower } 78350901Ssklower if (tpcb->tp_rsycnt) 78450901Ssklower panic("tp_rsyflush"); 78550901Ssklower } 78650901Ssklower free((caddr_t)tpcb->tp_rsyq, M_PCB); 78750901Ssklower tpcb->tp_rsyq = 0; 78850901Ssklower } 78950901Ssklower 79050901Ssklower tp_rsyset(tpcb) 79150901Ssklower register struct tp_pcb *tpcb; 79250901Ssklower { 79350901Ssklower register struct socket *so = tpcb->tp_sock; 79450901Ssklower int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf; 79550975Ssklower int old_credit = tpcb->tp_maxlcredit; 79650975Ssklower caddr_t rsyq; 79750901Ssklower 79850901Ssklower tpcb->tp_maxlcredit = maxcredit = min(maxcredit, 79950901Ssklower (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize); 80050901Ssklower 80150975Ssklower if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0) 80250975Ssklower return; 80350901Ssklower maxcredit *= sizeof(struct mbuf *); 80450901Ssklower if (tpcb->tp_rsyq) 80550901Ssklower tp_rsyflush(tpcb); 80650901Ssklower if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT)) 80750901Ssklower bzero(rsyq, maxcredit); 80850901Ssklower tpcb->tp_rsyq = (struct mbuf **)rsyq; 80950901Ssklower } 81050901Ssklower 81150901Ssklower tpsbcheck(tpcb, i) 81250901Ssklower struct tp_pcb *tpcb; 81350901Ssklower { 81450901Ssklower register struct mbuf *n, *m; 81550901Ssklower register int len = 0, mbcnt = 0, pktlen; 81650901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 81750901Ssklower 81850901Ssklower for (n = sb->sb_mb; n; n = n->m_nextpkt) { 81950901Ssklower if ((n->m_flags & M_PKTHDR) == 0) 82050901Ssklower panic("tpsbcheck nohdr"); 82150901Ssklower pktlen = len + n->m_pkthdr.len; 82250901Ssklower for (m = n; m; m = m->m_next) { 82350901Ssklower len += m->m_len; 82450901Ssklower mbcnt += MSIZE; 82550901Ssklower if (m->m_flags & M_EXT) 82650901Ssklower mbcnt += m->m_ext.ext_size; 82750901Ssklower } 82850901Ssklower if (len != pktlen) { 82950901Ssklower printf("test %d; len %d != pktlen %d on mbuf 0x%x\n", 83050901Ssklower i, len, pktlen, n); 83150901Ssklower panic("tpsbcheck short"); 83250901Ssklower } 83350901Ssklower } 83450901Ssklower if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { 83550901Ssklower printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc, 83650901Ssklower mbcnt, sb->sb_mbcnt); 83750901Ssklower panic("tpsbcheck"); 83850901Ssklower } 83950901Ssklower } 840