149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*51249Ssklower * @(#)tp_subr.c 7.16 (Berkeley) 10/02/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" 5951138Ssklower #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 7351204Ssklower int tp_emit(), tp_sbdrop(); 7451204Ssklower int tprexmtthresh = 3; 7551204Ssklower void tp_send(); 7636413Ssklower 7736413Ssklower /* 7836413Ssklower * CALLED FROM: 7936413Ssklower * tp.trans, when an XAK arrives 8036413Ssklower * FUNCTION and ARGUMENTS: 8136413Ssklower * Determines if the sequence number (seq) from the XAK 8236413Ssklower * acks anything new. If so, drop the appropriate tpdu 8336413Ssklower * from the XPD send queue. 8436413Ssklower * RETURN VALUE: 8536413Ssklower * Returns 1 if it did this, 0 if the ack caused no action. 8636413Ssklower */ 8736413Ssklower int 8836413Ssklower tp_goodXack(tpcb, seq) 8936413Ssklower struct tp_pcb *tpcb; 9036413Ssklower SeqNum seq; 9136413Ssklower { 9236413Ssklower 9336413Ssklower IFTRACE(D_XPD) 9436413Ssklower tptraceTPCB(TPPTgotXack, 9551204Ssklower seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndnew, 9636413Ssklower tpcb->tp_snduna); 9736413Ssklower ENDTRACE 9836413Ssklower 9936413Ssklower if ( seq == tpcb->tp_Xuna ) { 10036413Ssklower tpcb->tp_Xuna = tpcb->tp_Xsndnxt; 10136413Ssklower 10236413Ssklower /* DROP 1 packet from the Xsnd socket buf - just so happens 10336413Ssklower * that only one packet can be there at any time 10436413Ssklower * so drop the whole thing. If you allow > 1 packet 10536413Ssklower * the socket buffer, then you'll have to keep 10636413Ssklower * track of how many characters went w/ each XPD tpdu, so this 10736413Ssklower * will get messier 10836413Ssklower */ 10936413Ssklower IFDEBUG(D_XPD) 11036413Ssklower dump_mbuf(tpcb->tp_Xsnd.sb_mb, 11136413Ssklower "tp_goodXack Xsnd before sbdrop"); 11236413Ssklower ENDDEBUG 11336413Ssklower 11436413Ssklower IFTRACE(D_XPD) 11536413Ssklower tptraceTPCB(TPPTmisc, 11636413Ssklower "goodXack: dropping cc ", 11736413Ssklower (int)(tpcb->tp_Xsnd.sb_cc), 11836413Ssklower 0,0,0); 11936413Ssklower ENDTRACE 12051204Ssklower sbdroprecord(&tpcb->tp_Xsnd); 12136413Ssklower return 1; 12236413Ssklower } 12336413Ssklower return 0; 12436413Ssklower } 12536413Ssklower 12636413Ssklower /* 12736413Ssklower * CALLED FROM: 12836413Ssklower * tp_good_ack() 12936413Ssklower * FUNCTION and ARGUMENTS: 13036413Ssklower * updates 13151138Ssklower * smoothed average round trip time (*rtt) 13251138Ssklower * roundtrip time variance (*rtv) - actually deviation, not variance 13336413Ssklower * given the new value (diff) 13436413Ssklower * RETURN VALUE: 13536413Ssklower * void 13636413Ssklower */ 13736413Ssklower 13836413Ssklower void 13951204Ssklower tp_rtt_rtv(tpcb) 14051204Ssklower register struct tp_pcb *tpcb; 14136413Ssklower { 14251204Ssklower int new, old = tpcb->tp_dt_ticks; 14351204Ssklower int delta, elapsed = tick - tpcb->tp_rttemit; 14436413Ssklower 14551204Ssklower if (tpcb->tp_rtt != 0) { 14651204Ssklower /* 14751204Ssklower * rtt is the smoothed round trip time in machine clock ticks (hz). 148*51249Ssklower * It is stored as a fixed point number, unscaled (unlike the tcp 149*51249Ssklower * srtt). The rationale here is that it is only significant to the 15051204Ssklower * nearest unit of slowtimo, which is at least 8 machine clock ticks 15151204Ssklower * so there is no need to scale. The smoothing is done according 15251204Ssklower * to the same formula as TCP (rtt = rtt*7/8 + measured_rtt/8). 15351204Ssklower */ 15451204Ssklower delta = elapsed - tpcb->tp_rtt; 15551204Ssklower if ((tpcb->tp_rtt += (delta >> TP_RTT_ALPHA)) <= 0) 15651204Ssklower tpcb->tp_rtt = 1; 15751204Ssklower /* 15851204Ssklower * rtv is a smoothed accumulated mean difference, unscaled 15951204Ssklower * for reasons expressed above. 16051204Ssklower * It is smoothed with an alpha of .75, and the round trip timer 16151204Ssklower * will be set to rtt + 4*rtv, also as TCP does. 16251204Ssklower */ 16351204Ssklower if (delta < 0) 16451204Ssklower delta = -delta; 16551204Ssklower if ((tpcb->tp_rtv += ((delta - tpcb->tp_rtv) >> TP_RTV_ALPHA)) <= 0) 16651204Ssklower tpcb->tp_rtv = 1; 16751204Ssklower } else { 16851204Ssklower /* 16951204Ssklower * No rtt measurement yet - use the unsmoothed rtt. 17051204Ssklower * Set the variance to half the rtt (so our first 17151204Ssklower * retransmit happens at 3*rtt) 17251204Ssklower */ 17351204Ssklower tpcb->tp_rtt = elapsed; 17451204Ssklower tpcb->tp_rtv = elapsed >> 1; 17551204Ssklower } 17651204Ssklower tpcb->tp_rttemit = 0; 17751204Ssklower tpcb->tp_rxtshift = 0; 17851204Ssklower /* 17951204Ssklower * Quoting TCP: "the retransmit should happen at rtt + 4 * rttvar. 18051204Ssklower * Because of the way we do the smoothing, srtt and rttvar 18151204Ssklower * will each average +1/2 tick of bias. When we compute 18251204Ssklower * the retransmit timer, we want 1/2 tick of rounding and 18351204Ssklower * 1 extra tick because of +-1/2 tick uncertainty in the 18451204Ssklower * firing of the timer. The bias will give us exactly the 18551204Ssklower * 1.5 tick we need. But, because the bias is 18651204Ssklower * statistical, we have to test that we don't drop below 18751204Ssklower * the minimum feasible timer (which is 2 ticks)." 18851204Ssklower */ 189*51249Ssklower TP_RANGESET(tpcb->tp_dt_ticks, TP_REXMTVAL(tpcb), 190*51249Ssklower tpcb->tp_peer_acktime, 128 /* XXX */); 19151204Ssklower IFTRACE(D_RTT) 19251204Ssklower tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks", 19351204Ssklower old, rtv, rtt, new); 19451204Ssklower ENDTRACE 195*51249Ssklower tpcb->tp_rxtcur = tpcb->tp_dt_ticks; 19636413Ssklower } 19736413Ssklower 19836413Ssklower /* 19936413Ssklower * CALLED FROM: 20036413Ssklower * tp.trans when an AK arrives 20136413Ssklower * FUNCTION and ARGUMENTS: 20236413Ssklower * Given (cdt), the credit from the AK tpdu, and 20336413Ssklower * (seq), the sequence number from the AK tpdu, 20436413Ssklower * tp_goodack() determines if the AK acknowledges something in the send 20536413Ssklower * window, and if so, drops the appropriate packets from the retransmission 20636413Ssklower * list, computes the round trip time, and updates the retransmission timer 20736413Ssklower * based on the new smoothed round trip time. 20836413Ssklower * RETURN VALUE: 20936413Ssklower * Returns 1 if 21036413Ssklower * EITHER it actually acked something heretofore unacknowledged 21136413Ssklower * OR no news but the credit should be processed. 21236413Ssklower * If something heretofore unacked was acked with this sequence number, 21336413Ssklower * the appropriate tpdus are dropped from the retransmission control list, 21436413Ssklower * by calling tp_sbdrop(). 21536413Ssklower * No need to see the tpdu itself. 21636413Ssklower */ 21736413Ssklower int 21836413Ssklower tp_goodack(tpcb, cdt, seq, subseq) 21936413Ssklower register struct tp_pcb *tpcb; 22036413Ssklower u_int cdt; 22151204Ssklower register SeqNum seq; 22251204Ssklower u_int subseq; 22336413Ssklower { 22451204Ssklower int old_fcredit; 22536413Ssklower int bang = 0; /* bang --> ack for something heretofore unacked */ 22651204Ssklower u_int bytes_acked; 22736413Ssklower 22836413Ssklower IFDEBUG(D_ACKRECV) 22951204Ssklower printf("goodack tpcb 0x%x seq 0x%x cdt %d una 0x%x new 0x%x nxt 0x%x\n", 23051204Ssklower tpcb, seq, cdt, tpcb->tp_snduna, tpcb->tp_sndnew, tpcb->tp_sndnxt); 23136413Ssklower ENDDEBUG 23236413Ssklower IFTRACE(D_ACKRECV) 23336413Ssklower tptraceTPCB(TPPTgotack, 23451204Ssklower seq,cdt, tpcb->tp_snduna,tpcb->tp_sndnew,subseq); 23536413Ssklower ENDTRACE 23636413Ssklower 23736413Ssklower IFPERF(tpcb) 23837469Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0); 23936413Ssklower ENDPERF 24036413Ssklower 24151204Ssklower if (seq == tpcb->tp_snduna) { 24251204Ssklower if (subseq < tpcb->tp_r_subseq || 24351204Ssklower (subseq == tpcb->tp_r_subseq && cdt <= tpcb->tp_fcredit)) { 24451204Ssklower discard_the_ack: 24551204Ssklower IFDEBUG(D_ACKRECV) 24651204Ssklower printf("goodack discard : tpcb 0x%x subseq %d r_subseq %d\n", 24751204Ssklower tpcb, subseq, tpcb->tp_r_subseq); 24851204Ssklower ENDDEBUG 24951204Ssklower goto done; 25036413Ssklower } 25151204Ssklower if (cdt == tpcb->tp_fcredit /*&& thus subseq > tpcb->tp_r_subseq */) { 25251204Ssklower tpcb->tp_r_subseq = subseq; 25351204Ssklower if (tpcb->tp_timer[TM_data_retrans] == 0) 25451204Ssklower tpcb->tp_dupacks = 0; 25551204Ssklower else if (++tpcb->tp_dupacks == tprexmtthresh) { 25651204Ssklower /* partner went out of his way to signal with different 25751204Ssklower subsequences that he has the same lack of an expected 25851204Ssklower packet. This may be an early indiciation of a loss */ 25936413Ssklower 26051204Ssklower SeqNum onxt = tpcb->tp_sndnxt; 26151204Ssklower struct mbuf *onxt_m = tpcb->tp_sndnxt_m; 26251204Ssklower u_int win = min(tpcb->tp_fcredit, 26351204Ssklower tpcb->tp_cong_win / tpcb->tp_l_tpdusize) / 2; 26451204Ssklower if (win < 2) 26551204Ssklower win = 2; 26651204Ssklower tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize; 26751204Ssklower tpcb->tp_timer[TM_data_retrans] = 0; 26851204Ssklower tpcb->tp_rttemit = 0; 26951204Ssklower tpcb->tp_sndnxt = tpcb->tp_snduna; 27051204Ssklower tpcb->tp_sndnxt_m = 0; 27151204Ssklower tpcb->tp_cong_win = tpcb->tp_l_tpdusize; 27251204Ssklower tp_send(tpcb); 27351204Ssklower tpcb->tp_cong_win = tpcb->tp_ssthresh + 27451204Ssklower tpcb->tp_dupacks * tpcb->tp_l_tpdusize; 27551204Ssklower if (SEQ_GT(tpcb, onxt, tpcb->tp_sndnxt)) { 27651204Ssklower tpcb->tp_sndnxt = onxt; 27751204Ssklower tpcb->tp_sndnxt_m = onxt_m; 27851204Ssklower } 27936413Ssklower 28051204Ssklower } else if (tpcb->tp_dupacks > tprexmtthresh) { 28151204Ssklower tpcb->tp_cong_win += tpcb->tp_l_tpdusize; 28251138Ssklower } 28351204Ssklower goto done; 28451204Ssklower } 28551204Ssklower } else if (SEQ_LT(tpcb, seq, tpcb->tp_snduna)) 28651204Ssklower goto discard_the_ack; 28751204Ssklower /* 28851204Ssklower * If the congestion window was inflated to account 28951204Ssklower * for the other side's cached packets, retract it. 29051204Ssklower */ 29151204Ssklower if (tpcb->tp_dupacks > tprexmtthresh && 29251204Ssklower tpcb->tp_cong_win > tpcb->tp_ssthresh) 29351204Ssklower tpcb->tp_cong_win = tpcb->tp_ssthresh; 29451204Ssklower tpcb->tp_r_subseq = subseq; 29551204Ssklower old_fcredit = tpcb->tp_fcredit; 29651204Ssklower tpcb->tp_fcredit = cdt; 29751204Ssklower if (cdt > tpcb->tp_maxfcredit) 29851204Ssklower tpcb->tp_maxfcredit = cdt; 29951204Ssklower tpcb->tp_dupacks = 0; 30036413Ssklower 30151204Ssklower if (IN_SWINDOW(tpcb, seq, tpcb->tp_snduna, tpcb->tp_sndnew)) { 30236413Ssklower 30351204Ssklower tpsbcheck(tpcb, 0); 30451204Ssklower bytes_acked = tp_sbdrop(tpcb, seq); 30551204Ssklower tpsbcheck(tpcb, 1); 30651204Ssklower /* 30751204Ssklower * If transmit timer is running and timed sequence 30851204Ssklower * number was acked, update smoothed round trip time. 30951204Ssklower * Since we now have an rtt measurement, cancel the 31051204Ssklower * timer backoff (cf., Phil Karn's retransmit alg.). 31151204Ssklower * Recompute the initial retransmit timer. 31251204Ssklower */ 31351204Ssklower if (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq)) 31451204Ssklower tp_rtt_rtv(tpcb); 31551204Ssklower /* 31651204Ssklower * If all outstanding data is acked, stop retransmit timer. 31751204Ssklower * If there is more data to be acked, restart retransmit 31851204Ssklower * timer, using current (possibly backed-off) value. 31951204Ssklower * OSI combines the keepalive and persistance functions. 32051204Ssklower * So, there is no persistance timer per se, to restart. 32151204Ssklower */ 32251204Ssklower tpcb->tp_timer[TM_data_retrans] = 32351204Ssklower (seq == tpcb->tp_sndnew) ? 0 : tpcb->tp_rxtcur; 32451204Ssklower /* 32551204Ssklower * When new data is acked, open the congestion window. 32651204Ssklower * If the window gives us less than ssthresh packets 32751204Ssklower * in flight, open exponentially (maxseg per packet). 32851204Ssklower * Otherwise open linearly: maxseg per window 32951204Ssklower * (maxseg^2 / cwnd per packet), plus a constant 33051204Ssklower * fraction of a packet (maxseg/8) to help larger windows 33151204Ssklower * open quickly enough. 33251204Ssklower */ 33351204Ssklower { 33451204Ssklower u_int cw = tpcb->tp_cong_win, incr = tpcb->tp_l_tpdusize; 33536413Ssklower 33651204Ssklower incr = min(incr, bytes_acked); 33751204Ssklower if (cw > tpcb->tp_ssthresh) 33851204Ssklower incr = incr * incr / cw + incr / 8; 33951204Ssklower tpcb->tp_cong_win = 34051204Ssklower min(cw + incr, tpcb->tp_sock->so_snd.sb_hiwat); 34136413Ssklower } 34236413Ssklower tpcb->tp_snduna = seq; 34351204Ssklower if (SEQ_LT(tpcb, tpcb->tp_sndnxt, seq)) { 34451204Ssklower tpcb->tp_sndnxt = seq; 34551204Ssklower tpcb->tp_sndnxt_m = 0; 34651204Ssklower } 34736413Ssklower bang++; 34836413Ssklower } 34936413Ssklower 35036413Ssklower if( cdt != 0 && old_fcredit == 0 ) { 35136413Ssklower tpcb->tp_sendfcc = 1; 35236413Ssklower } 353*51249Ssklower if (cdt == 0) { 354*51249Ssklower if (old_fcredit != 0) 355*51249Ssklower IncStat(ts_zfcdt); 356*51249Ssklower /* The following might mean that the window shrunk */ 357*51249Ssklower if (tpcb->tp_timer[TM_data_retrans]) { 358*51249Ssklower tpcb->tp_timer[TM_data_retrans] = 0; 359*51249Ssklower tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks; 360*51249Ssklower if (tpcb->tp_sndnxt != tpcb->tp_snduna) { 361*51249Ssklower tpcb->tp_sndnxt = tpcb->tp_snduna; 362*51249Ssklower tpcb->tp_sndnxt_m = 0; 363*51249Ssklower } 364*51249Ssklower } 36536413Ssklower } 36636413Ssklower tpcb->tp_fcredit = cdt; 36751204Ssklower bang |= (old_fcredit < cdt); 36836413Ssklower 36951204Ssklower done: 37036413Ssklower IFDEBUG(D_ACKRECV) 37151204Ssklower printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n", 37251204Ssklower bang, cdt, old_fcredit, tpcb->tp_cong_win); 37336413Ssklower ENDDEBUG 37451204Ssklower /* if (bang) XXXXX Very bad to remove this test, but somethings broken */ 37551204Ssklower tp_send(tpcb); 37651204Ssklower return (bang); 37736413Ssklower } 37836413Ssklower 37936413Ssklower /* 38036413Ssklower * CALLED FROM: 38136413Ssklower * tp_goodack() 38236413Ssklower * FUNCTION and ARGUMENTS: 38350901Ssklower * drops everything up TO but not INCLUDING seq # (seq) 38436413Ssklower * from the retransmission queue. 38536413Ssklower */ 38636413Ssklower tp_sbdrop(tpcb, seq) 38750901Ssklower register struct tp_pcb *tpcb; 38836413Ssklower SeqNum seq; 38936413Ssklower { 39050901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 39151204Ssklower register int i = SEQ_SUB(tpcb, seq, tpcb->tp_snduna); 39251204Ssklower int oldcc = sb->sb_cc, oldi = i; 39336413Ssklower 39451204Ssklower if (i >= tpcb->tp_seqhalf) 39551204Ssklower printf("tp_spdropping too much -- should panic"); 39651204Ssklower while (i-- > 0) 39751204Ssklower sbdroprecord(sb); 39836413Ssklower IFDEBUG(D_ACKRECV) 39951204Ssklower printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n", 40051204Ssklower oldi, oldcc - sb->sb_cc, tpcb, seq); 40136413Ssklower ENDDEBUG 40251204Ssklower if (sb->sb_flags & SB_NOTIFY) 40351204Ssklower sowwakeup(tpcb->tp_sock); 40451138Ssklower return (oldcc - sb->sb_cc); 40536413Ssklower } 40636413Ssklower 40736413Ssklower /* 40836413Ssklower * CALLED FROM: 40936413Ssklower * tp.trans on user send request, arrival of AK and arrival of XAK 41036413Ssklower * FUNCTION and ARGUMENTS: 41151204Ssklower * Emits tpdus starting at sequence number (tpcb->tp_sndnxt). 41236413Ssklower * Emits until a) runs out of data, or b) runs into an XPD mark, or 41351204Ssklower * c) it hits seq number (highseq) limited by cong or credit. 41436413Ssklower * 41536413Ssklower * If you want XPD to buffer > 1 du per socket buffer, you can 41636413Ssklower * modifiy this to issue XPD tpdus also, but then it'll have 41736413Ssklower * to take some argument(s) to distinguish between the type of DU to 41850901Ssklower * hand tp_emit. 41936413Ssklower * 42036413Ssklower * When something is sent for the first time, its time-of-send 42151204Ssklower * is stashed (in system clock ticks rather than pf_slowtimo ticks). 42251204Ssklower * When the ack arrives, the smoothed round-trip time is figured 42351204Ssklower * using this value. 42436413Ssklower */ 42551204Ssklower void 42636413Ssklower tp_send(tpcb) 42736413Ssklower register struct tp_pcb *tpcb; 42836413Ssklower { 42936413Ssklower register int len; 43051204Ssklower register struct mbuf *m; 43151204Ssklower struct mbuf *mb = 0; 43236413Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 43351204Ssklower unsigned int eotsdu = 0; 43451204Ssklower SeqNum highseq, checkseq; 43551204Ssklower int idle, idleticks, off, cong_win; 43636413Ssklower #ifdef TP_PERF_MEAS 43751138Ssklower int send_start_time = tick; 43851204Ssklower SeqNum oldnxt = tpcb->tp_sndnxt; 43936413Ssklower #endif TP_PERF_MEAS 44036413Ssklower 44151204Ssklower idle = (tpcb->tp_snduna == tpcb->tp_sndnew); 44251204Ssklower if (idle) { 44351204Ssklower idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact]; 44451204Ssklower if (idleticks > tpcb->tp_dt_ticks) 44551204Ssklower /* 44651204Ssklower * We have been idle for "a while" and no acks are 44751204Ssklower * expected to clock out any data we send -- 44851204Ssklower * slow start to get ack "clock" running again. 44951204Ssklower */ 45051204Ssklower tpcb->tp_cong_win = tpcb->tp_l_tpdusize; 45151204Ssklower } 45236413Ssklower 45351204Ssklower cong_win = tpcb->tp_cong_win; 45451204Ssklower highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna); 45551204Ssklower if (tpcb->tp_Xsnd.sb_mb) 45651204Ssklower highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew); 45736413Ssklower 45836413Ssklower IFDEBUG(D_DATA) 45951204Ssklower printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n", 46051204Ssklower tpcb, tpcb->tp_sndnxt, cong_win, highseq); 46136413Ssklower ENDDEBUG 46236413Ssklower IFTRACE(D_DATA) 46351204Ssklower tptraceTPCB( TPPTmisc, "tp_send sndnew snduna", 46451204Ssklower tpcb->tp_sndnew, tpcb->tp_snduna, 0, 0); 46551204Ssklower tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin", 46651204Ssklower tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win); 46736413Ssklower ENDTRACE 46836413Ssklower IFTRACE(D_DATA) 46951204Ssklower tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin", 47051204Ssklower tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win); 47136413Ssklower ENDTRACE 47236413Ssklower 47351204Ssklower if (tpcb->tp_sndnxt_m) 47451204Ssklower m = tpcb->tp_sndnxt_m; 47551204Ssklower else { 47651204Ssklower off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna); 47751204Ssklower for (m = sb->sb_mb; m && off > 0; m = m->m_next) 47851204Ssklower off--; 47951204Ssklower } 48051204Ssklower send: 48151204Ssklower /* 48251204Ssklower * Avoid silly window syndrome here . . . figure out how! 48351204Ssklower */ 48451204Ssklower checkseq = tpcb->tp_sndnum; 48551204Ssklower if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq)) 486*51249Ssklower checkseq = highseq; /* i.e. DON'T retain highest assigned packet */ 48736413Ssklower 48851204Ssklower while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) { 48936413Ssklower 49051204Ssklower eotsdu = (m->m_flags & M_EOR) != 0; 49151204Ssklower len = m->m_pkthdr.len; 49251204Ssklower if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 && 49351204Ssklower len < (tpcb->tp_l_tpdusize / 2)) 49451204Ssklower break; /* Nagle . . . . . */ 49551204Ssklower cong_win -= len; 49636413Ssklower /* make a copy - mb goes into the retransmission list 49736413Ssklower * while m gets emitted. m_copy won't copy a zero-length mbuf. 49836413Ssklower */ 49951204Ssklower mb = m; 50050901Ssklower m = m_copy(mb, 0, M_COPYALL); 50150901Ssklower if (m == MNULL) 50251204Ssklower break; 50351204Ssklower IFTRACE(D_STASH) 50436413Ssklower tptraceTPCB( TPPTmisc, 50551204Ssklower "tp_send mcopy nxt high eotsdu len", 50651204Ssklower tpcb->tp_sndnxt, highseq, eotsdu, len); 50736413Ssklower ENDTRACE 50851204Ssklower 50951204Ssklower IFDEBUG(D_DATA) 51051204Ssklower printf("tp_sending tpcb 0x%x nxt 0x%x\n", 51151204Ssklower tpcb, tpcb->tp_sndnxt); 51251204Ssklower ENDDEBUG 51351204Ssklower /* when headers are precomputed, may need to fill 51450901Ssklower in checksum here */ 51550901Ssklower if (tpcb->tp_sock->so_error = 51651204Ssklower tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) { 51736413Ssklower /* error */ 51851204Ssklower break; 51936413Ssklower } 52051204Ssklower m = mb->m_nextpkt; 52151204Ssklower tpcb->tp_sndnxt_m = m; 52251204Ssklower if (tpcb->tp_sndnxt == tpcb->tp_sndnew) { 52351204Ssklower SEQ_INC(tpcb, tpcb->tp_sndnew); 52451204Ssklower /* 52551204Ssklower * Time this transmission if not a retransmission and 52651204Ssklower * not currently timing anything. 52751204Ssklower */ 52851204Ssklower if (tpcb->tp_rttemit == 0) { 52951204Ssklower tpcb->tp_rttemit = tick; 53051204Ssklower tpcb->tp_rttseq = tpcb->tp_sndnxt; 53151204Ssklower } 53251204Ssklower tpcb->tp_sndnxt = tpcb->tp_sndnew; 53351204Ssklower } else 53451204Ssklower SEQ_INC(tpcb, tpcb->tp_sndnxt); 53551204Ssklower /* 53651204Ssklower * Set retransmit timer if not currently set. 53751204Ssklower * Initial value for retransmit timer is smoothed 53851204Ssklower * round-trip time + 2 * round-trip time variance. 53951204Ssklower * Initialize shift counter which is used for backoff 54051204Ssklower * of retransmit time. 54151204Ssklower */ 54251204Ssklower if (tpcb->tp_timer[TM_data_retrans] == 0) { 54351204Ssklower tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks; 54451204Ssklower tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks; 54551204Ssklower tpcb->tp_rxtshift = 0; 54651138Ssklower } 54736413Ssklower } 54851204Ssklower if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum)) 54951204Ssklower tpcb->tp_oktonagle = 0; 55050236Ssklower #ifdef TP_PERF_MEAS 55136413Ssklower IFPERF(tpcb) 55236413Ssklower { 55336413Ssklower register int npkts; 55451138Ssklower int elapsed = tick - send_start_time, *t; 55551138Ssklower struct timeval now; 55636413Ssklower 55751204Ssklower npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt); 55836413Ssklower 55951204Ssklower if (npkts > 0) 56036413Ssklower tpcb->tp_Nwindow++; 56136413Ssklower 56236413Ssklower if (npkts > TP_PM_MAX) 56336413Ssklower npkts = TP_PM_MAX; 56436413Ssklower 56536413Ssklower t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); 56651138Ssklower *t += (t - elapsed) >> TP_RTT_ALPHA; 56736413Ssklower 56851204Ssklower if (mb == 0) { 56936413Ssklower IncPStat(tpcb, tps_win_lim_by_data[npkts] ); 57036413Ssklower } else { 57136413Ssklower IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); 57236413Ssklower /* not true with congestion-window being used */ 57336413Ssklower } 57451138Ssklower now.tv_sec = elapsed / hz; 57551138Ssklower now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz; 57636413Ssklower tpmeas( tpcb->tp_lref, 57751204Ssklower TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts); 57836413Ssklower } 57936413Ssklower ENDPERF 58050236Ssklower #endif TP_PERF_MEAS 58136413Ssklower 58236413Ssklower 58336413Ssklower IFTRACE(D_DATA) 58436413Ssklower tptraceTPCB( TPPTmisc, 58551204Ssklower "tp_send at end: new nxt eotsdu error", 58651204Ssklower tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error); 58736413Ssklower 58836413Ssklower ENDTRACE 58936413Ssklower } 59036413Ssklower 59150901Ssklower int TPNagleok; 59250901Ssklower int TPNagled; 59350901Ssklower 59450901Ssklower tp_packetize(tpcb, m, eotsdu) 59550901Ssklower register struct tp_pcb *tpcb; 59650901Ssklower register struct mbuf *m; 59750901Ssklower int eotsdu; 59850901Ssklower { 59950901Ssklower register struct mbuf *n; 60050901Ssklower register struct sockbuf *sb = &tpcb->tp_sock->so_snd; 60150901Ssklower int maxsize = tpcb->tp_l_tpdusize 60250901Ssklower - tp_headersize(DT_TPDU_type, tpcb) 60350901Ssklower - (tpcb->tp_use_checksum?4:0) ; 60450901Ssklower int totlen = m->m_pkthdr.len; 60550901Ssklower struct mbuf *m_split(); 60650901Ssklower /* 60750901Ssklower * Pre-packetize the data in the sockbuf 60850901Ssklower * according to negotiated mtu. Do it here 60950901Ssklower * where we can safely wait for mbufs. 61050901Ssklower * 61150901Ssklower * This presumes knowledge of sockbuf conventions. 61250901Ssklower * TODO: allocate space for header and fill it in (once!). 61350901Ssklower */ 61451204Ssklower IFDEBUG(D_DATA) 61551204Ssklower printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n", 61651204Ssklower maxsize, totlen, eotsdu, tpcb->tp_sndnum); 61750901Ssklower ENDTRACE 61850901Ssklower if (tpcb->tp_oktonagle) { 61950901Ssklower if ((n = sb->sb_mb) == 0) 62050901Ssklower panic("tp_packetize"); 62150901Ssklower while (n->m_act) 62250901Ssklower n = n->m_act; 62350901Ssklower if (n->m_flags & M_EOR) 62450901Ssklower panic("tp_packetize 2"); 62550901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 62650901Ssklower if (totlen + n->m_pkthdr.len < maxsize) { 62750901Ssklower /* There is an unsent packet with space, combine data */ 62850901Ssklower struct mbuf *old_n = n; 62950901Ssklower tpsbcheck(tpcb,3); 63050901Ssklower n->m_pkthdr.len += totlen; 63150901Ssklower while (n->m_next) 63250901Ssklower n = n->m_next; 63350901Ssklower sbcompress(sb, m, n); 63450901Ssklower tpsbcheck(tpcb,4); 63550901Ssklower n = old_n; 63650901Ssklower TPNagled++; 63750901Ssklower goto out; 63850901Ssklower } 63950901Ssklower } 64050901Ssklower while (m) { 64150901Ssklower n = m; 64250901Ssklower if (totlen > maxsize) { 64350901Ssklower if ((m = m_split(n, maxsize, M_WAIT)) == 0) 64450901Ssklower panic("tp_packetize"); 64550901Ssklower } else 64650901Ssklower m = 0; 64750901Ssklower totlen -= maxsize; 64850901Ssklower tpsbcheck(tpcb, 5); 64950901Ssklower sbappendrecord(sb, n); 65050901Ssklower tpsbcheck(tpcb, 6); 65150901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 65250901Ssklower } 65350901Ssklower out: 65450901Ssklower if (eotsdu) { 65550901Ssklower n->m_flags |= M_EOR; /* XXX belongs at end */ 65650901Ssklower tpcb->tp_oktonagle = 0; 65750901Ssklower } else { 65850901Ssklower SEQ_DEC(tpcb, tpcb->tp_sndnum); 65950901Ssklower tpcb->tp_oktonagle = 1; 66050901Ssklower TPNagleok++; 66150901Ssklower } 66251204Ssklower IFDEBUG(D_DATA) 66351204Ssklower printf("SEND out: oktonagle %d sndnum 0x%x\n", 66451204Ssklower tpcb->tp_oktonagle, tpcb->tp_sndnum); 66551204Ssklower ENDTRACE 66650901Ssklower return 0; 66750901Ssklower } 66850901Ssklower 66950901Ssklower 67036413Ssklower /* 67136413Ssklower * NAME: tp_stash() 67236413Ssklower * CALLED FROM: 67336413Ssklower * tp.trans on arrival of a DT tpdu 67436413Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 67536413Ssklower * Returns 1 if 67636413Ssklower * a) something new arrived and it's got eotsdu_reached bit on, 67736413Ssklower * b) this arrival was caused other out-of-sequence things to be 67836413Ssklower * accepted, or 67936413Ssklower * c) this arrival is the highest seq # for which we last gave credit 68036413Ssklower * (sender just sent a whole window) 68136413Ssklower * In other words, returns 1 if tp should send an ack immediately, 0 if 68236413Ssklower * the ack can wait a while. 68336413Ssklower * 68436413Ssklower * Note: this implementation no longer renegs on credit, (except 68536413Ssklower * when debugging option D_RENEG is on, for the purpose of testing 68636413Ssklower * ack subsequencing), so we don't need to check for incoming tpdus 68736413Ssklower * being in a reneged portion of the window. 68836413Ssklower */ 68936413Ssklower 69051204Ssklower tp_stash(tpcb, e) 69136413Ssklower register struct tp_pcb *tpcb; 69236413Ssklower register struct tp_event *e; 69336413Ssklower { 69436413Ssklower register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; 69536413Ssklower /* 0--> delay acks until full window */ 69636413Ssklower /* 1--> ack each tpdu */ 69736413Ssklower #ifndef lint 69836413Ssklower #define E e->ATTR(DT_TPDU) 69936413Ssklower #else lint 70036413Ssklower #define E e->ev_union.EV_DT_TPDU 70136413Ssklower #endif lint 70236413Ssklower 70336413Ssklower if ( E.e_eot ) { 70436413Ssklower register struct mbuf *n = E.e_data; 70537469Ssklower n->m_flags |= M_EOR; 70638841Ssklower n->m_act = 0; 70737469Ssklower } 70836413Ssklower IFDEBUG(D_STASH) 70936413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 71036413Ssklower "stash: so_rcv before appending"); 71136413Ssklower dump_mbuf(E.e_data, 71236413Ssklower "stash: e_data before appending"); 71336413Ssklower ENDDEBUG 71436413Ssklower 71536413Ssklower IFPERF(tpcb) 71636413Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen; 71736413Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 71837469Ssklower E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); 71936413Ssklower ENDPERF 72036413Ssklower 72151024Ssklower if (E.e_seq == tpcb->tp_rcvnxt) { 72236413Ssklower 72336413Ssklower IFDEBUG(D_STASH) 72436413Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", 72536413Ssklower E.e_seq, E.e_datalen, E.e_eot); 72636413Ssklower ENDDEBUG 72736413Ssklower 72836413Ssklower IFTRACE(D_STASH) 72936413Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 73036413Ssklower E.e_seq, E.e_datalen, E.e_eot, 0); 73136413Ssklower ENDTRACE 73236413Ssklower 73351024Ssklower SET_DELACK(tpcb); 73451024Ssklower 73537469Ssklower sbappend(&tpcb->tp_sock->so_rcv, E.e_data); 73637469Ssklower 73736413Ssklower SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 73836413Ssklower /* 73950901Ssklower * move chains from the reassembly queue to the socket buffer 74036413Ssklower */ 74150901Ssklower if (tpcb->tp_rsycnt) { 74250901Ssklower register struct mbuf **mp; 74350901Ssklower struct mbuf **mplim; 74436413Ssklower 74550901Ssklower mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit); 74650901Ssklower mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit; 74736413Ssklower 74850901Ssklower while (tpcb->tp_rsycnt && *mp) { 74950901Ssklower sbappend(&tpcb->tp_sock->so_rcv, *mp); 75050901Ssklower tpcb->tp_rsycnt--; 75150901Ssklower *mp = 0; 75250901Ssklower SEQ_INC(tpcb, tpcb->tp_rcvnxt); 75336413Ssklower ack_reason |= ACK_REORDER; 75450901Ssklower if (++mp == mplim) 75550901Ssklower mp = tpcb->tp_rsyq; 75636413Ssklower } 75736413Ssklower } 75836413Ssklower IFDEBUG(D_STASH) 75936413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 76036413Ssklower "stash: so_rcv after appending"); 76136413Ssklower ENDDEBUG 76236413Ssklower 76336413Ssklower } else { 76450901Ssklower register struct mbuf **mp; 76550901Ssklower SeqNum uwe; 76636413Ssklower 76736413Ssklower IFTRACE(D_STASH) 76836413Ssklower tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", 76936413Ssklower E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); 77036413Ssklower ENDTRACE 77136413Ssklower 77250975Ssklower if (tpcb->tp_rsyq == 0) 77350975Ssklower tp_rsyset(tpcb); 77450901Ssklower uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit); 77550901Ssklower if (tpcb->tp_rsyq == 0 || 77650901Ssklower !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) { 77736413Ssklower ack_reason = ACK_DONT; 77850901Ssklower m_freem(E.e_data); 77950901Ssklower } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) { 78036413Ssklower IFDEBUG(D_STASH) 78136413Ssklower printf("tp_stash - drop & ack\n"); 78236413Ssklower ENDDEBUG 78336413Ssklower 78436413Ssklower /* retransmission - drop it and force an ack */ 78536413Ssklower IncStat(ts_dt_dup); 78636413Ssklower IFPERF(tpcb) 78736413Ssklower IncPStat(tpcb, tps_n_ack_cuz_dup); 78836413Ssklower ENDPERF 78936413Ssklower 79050901Ssklower m_freem(E.e_data); 79136413Ssklower ack_reason |= ACK_DUP; 79250901Ssklower } else { 79350901Ssklower *mp = E.e_data; 79450901Ssklower tpcb->tp_rsycnt++; 79550901Ssklower ack_reason = ACK_DONT; 79636413Ssklower } 79736413Ssklower } 79851024Ssklower /* there were some comments of historical interest here. */ 79936413Ssklower { 80036413Ssklower LOCAL_CREDIT(tpcb); 80136413Ssklower 80236413Ssklower if ( E.e_seq == tpcb->tp_sent_uwe ) 80336413Ssklower ack_reason |= ACK_STRAT_FULLWIN; 80436413Ssklower 80536413Ssklower IFTRACE(D_STASH) 80636413Ssklower tptraceTPCB(TPPTmisc, 80736413Ssklower "end of stash, eot, ack_reason, sent_uwe ", 80836413Ssklower E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); 80936413Ssklower ENDTRACE 81036413Ssklower 81136413Ssklower if ( ack_reason == ACK_DONT ) { 81236413Ssklower IncStat( ts_ackreason[ACK_DONT] ); 81336413Ssklower return 0; 81436413Ssklower } else { 81536413Ssklower IFPERF(tpcb) 81636413Ssklower if(ack_reason & ACK_STRAT_EACH) { 81736413Ssklower IncPStat(tpcb, tps_n_ack_cuz_strat); 81836413Ssklower } else if(ack_reason & ACK_STRAT_FULLWIN) { 81936413Ssklower IncPStat(tpcb, tps_n_ack_cuz_fullwin); 82036413Ssklower } else if(ack_reason & ACK_REORDER) { 82136413Ssklower IncPStat(tpcb, tps_n_ack_cuz_reorder); 82236413Ssklower } 82336413Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, 82436413Ssklower SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); 82536413Ssklower ENDPERF 82636413Ssklower { 82736413Ssklower register int i; 82836413Ssklower 82936413Ssklower /* keep track of all reasons that apply */ 83036413Ssklower for( i=1; i<_ACK_NUM_REASONS_ ;i++) { 83136413Ssklower if( ack_reason & (1<<i) ) 83236413Ssklower IncStat( ts_ackreason[i] ); 83336413Ssklower } 83436413Ssklower } 83536413Ssklower return 1; 83636413Ssklower } 83736413Ssklower } 83836413Ssklower } 83950901Ssklower 84050901Ssklower /* 84150901Ssklower * tp_rsyflush - drop all the packets on the reassembly queue. 84250901Ssklower * Do this when closing the socket, or when somebody has changed 84350901Ssklower * the space avaible in the receive socket (XXX). 84450901Ssklower */ 84550901Ssklower tp_rsyflush(tpcb) 84650901Ssklower register struct tp_pcb *tpcb; 84750901Ssklower { 84850901Ssklower register struct mbuf *m, **mp; 84950901Ssklower if (tpcb->tp_rsycnt) { 85050901Ssklower for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit; 85150901Ssklower --mp >= tpcb->tp_rsyq; ) 85250901Ssklower if (*mp) { 85350901Ssklower tpcb->tp_rsycnt--; 85450901Ssklower m_freem(*mp); 85550901Ssklower } 85650901Ssklower if (tpcb->tp_rsycnt) 85750901Ssklower panic("tp_rsyflush"); 85850901Ssklower } 85950901Ssklower free((caddr_t)tpcb->tp_rsyq, M_PCB); 86050901Ssklower tpcb->tp_rsyq = 0; 86150901Ssklower } 86250901Ssklower 86350901Ssklower tp_rsyset(tpcb) 86450901Ssklower register struct tp_pcb *tpcb; 86550901Ssklower { 86650901Ssklower register struct socket *so = tpcb->tp_sock; 86750901Ssklower int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf; 86850975Ssklower int old_credit = tpcb->tp_maxlcredit; 86950975Ssklower caddr_t rsyq; 87050901Ssklower 87150901Ssklower tpcb->tp_maxlcredit = maxcredit = min(maxcredit, 87250901Ssklower (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize); 87350901Ssklower 87450975Ssklower if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0) 87550975Ssklower return; 87650901Ssklower maxcredit *= sizeof(struct mbuf *); 87750901Ssklower if (tpcb->tp_rsyq) 87850901Ssklower tp_rsyflush(tpcb); 87950901Ssklower if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT)) 88050901Ssklower bzero(rsyq, maxcredit); 88150901Ssklower tpcb->tp_rsyq = (struct mbuf **)rsyq; 88250901Ssklower } 88350901Ssklower 88450901Ssklower tpsbcheck(tpcb, i) 88550901Ssklower struct tp_pcb *tpcb; 88650901Ssklower { 88750901Ssklower register struct mbuf *n, *m; 88850901Ssklower register int len = 0, mbcnt = 0, pktlen; 88950901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 89050901Ssklower 89150901Ssklower for (n = sb->sb_mb; n; n = n->m_nextpkt) { 89250901Ssklower if ((n->m_flags & M_PKTHDR) == 0) 89350901Ssklower panic("tpsbcheck nohdr"); 89450901Ssklower pktlen = len + n->m_pkthdr.len; 89550901Ssklower for (m = n; m; m = m->m_next) { 89650901Ssklower len += m->m_len; 89750901Ssklower mbcnt += MSIZE; 89850901Ssklower if (m->m_flags & M_EXT) 89950901Ssklower mbcnt += m->m_ext.ext_size; 90050901Ssklower } 90150901Ssklower if (len != pktlen) { 90250901Ssklower printf("test %d; len %d != pktlen %d on mbuf 0x%x\n", 90350901Ssklower i, len, pktlen, n); 90450901Ssklower panic("tpsbcheck short"); 90550901Ssklower } 90650901Ssklower } 90750901Ssklower if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { 90850901Ssklower printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc, 90950901Ssklower mbcnt, sb->sb_mbcnt); 91050901Ssklower panic("tpsbcheck"); 91150901Ssklower } 91250901Ssklower } 913