149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*51341Ssklower * @(#)tp_subr.c 7.17 (Berkeley) 10/08/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; 75*51341Ssklower extern int ticks; 7651204Ssklower void tp_send(); 7736413Ssklower 7836413Ssklower /* 7936413Ssklower * CALLED FROM: 8036413Ssklower * tp.trans, when an XAK arrives 8136413Ssklower * FUNCTION and ARGUMENTS: 8236413Ssklower * Determines if the sequence number (seq) from the XAK 8336413Ssklower * acks anything new. If so, drop the appropriate tpdu 8436413Ssklower * from the XPD send queue. 8536413Ssklower * RETURN VALUE: 8636413Ssklower * Returns 1 if it did this, 0 if the ack caused no action. 8736413Ssklower */ 8836413Ssklower int 8936413Ssklower tp_goodXack(tpcb, seq) 9036413Ssklower struct tp_pcb *tpcb; 9136413Ssklower SeqNum seq; 9236413Ssklower { 9336413Ssklower 9436413Ssklower IFTRACE(D_XPD) 9536413Ssklower tptraceTPCB(TPPTgotXack, 9651204Ssklower seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndnew, 9736413Ssklower tpcb->tp_snduna); 9836413Ssklower ENDTRACE 9936413Ssklower 10036413Ssklower if ( seq == tpcb->tp_Xuna ) { 10136413Ssklower tpcb->tp_Xuna = tpcb->tp_Xsndnxt; 10236413Ssklower 10336413Ssklower /* DROP 1 packet from the Xsnd socket buf - just so happens 10436413Ssklower * that only one packet can be there at any time 10536413Ssklower * so drop the whole thing. If you allow > 1 packet 10636413Ssklower * the socket buffer, then you'll have to keep 10736413Ssklower * track of how many characters went w/ each XPD tpdu, so this 10836413Ssklower * will get messier 10936413Ssklower */ 11036413Ssklower IFDEBUG(D_XPD) 11136413Ssklower dump_mbuf(tpcb->tp_Xsnd.sb_mb, 11236413Ssklower "tp_goodXack Xsnd before sbdrop"); 11336413Ssklower ENDDEBUG 11436413Ssklower 11536413Ssklower IFTRACE(D_XPD) 11636413Ssklower tptraceTPCB(TPPTmisc, 11736413Ssklower "goodXack: dropping cc ", 11836413Ssklower (int)(tpcb->tp_Xsnd.sb_cc), 11936413Ssklower 0,0,0); 12036413Ssklower ENDTRACE 12151204Ssklower sbdroprecord(&tpcb->tp_Xsnd); 12236413Ssklower return 1; 12336413Ssklower } 12436413Ssklower return 0; 12536413Ssklower } 12636413Ssklower 12736413Ssklower /* 12836413Ssklower * CALLED FROM: 12936413Ssklower * tp_good_ack() 13036413Ssklower * FUNCTION and ARGUMENTS: 13136413Ssklower * updates 13251138Ssklower * smoothed average round trip time (*rtt) 13351138Ssklower * roundtrip time variance (*rtv) - actually deviation, not variance 13436413Ssklower * given the new value (diff) 13536413Ssklower * RETURN VALUE: 13636413Ssklower * void 13736413Ssklower */ 13836413Ssklower 13936413Ssklower void 14051204Ssklower tp_rtt_rtv(tpcb) 14151204Ssklower register struct tp_pcb *tpcb; 14236413Ssklower { 143*51341Ssklower int old = tpcb->tp_rtt; 144*51341Ssklower int delta, elapsed = ticks - tpcb->tp_rttemit; 14536413Ssklower 14651204Ssklower if (tpcb->tp_rtt != 0) { 14751204Ssklower /* 14851204Ssklower * rtt is the smoothed round trip time in machine clock ticks (hz). 14951249Ssklower * It is stored as a fixed point number, unscaled (unlike the tcp 15051249Ssklower * srtt). The rationale here is that it is only significant to the 15151204Ssklower * nearest unit of slowtimo, which is at least 8 machine clock ticks 15251204Ssklower * so there is no need to scale. The smoothing is done according 15351204Ssklower * to the same formula as TCP (rtt = rtt*7/8 + measured_rtt/8). 15451204Ssklower */ 15551204Ssklower delta = elapsed - tpcb->tp_rtt; 15651204Ssklower if ((tpcb->tp_rtt += (delta >> TP_RTT_ALPHA)) <= 0) 15751204Ssklower tpcb->tp_rtt = 1; 15851204Ssklower /* 15951204Ssklower * rtv is a smoothed accumulated mean difference, unscaled 16051204Ssklower * for reasons expressed above. 16151204Ssklower * It is smoothed with an alpha of .75, and the round trip timer 16251204Ssklower * will be set to rtt + 4*rtv, also as TCP does. 16351204Ssklower */ 16451204Ssklower if (delta < 0) 16551204Ssklower delta = -delta; 16651204Ssklower if ((tpcb->tp_rtv += ((delta - tpcb->tp_rtv) >> TP_RTV_ALPHA)) <= 0) 16751204Ssklower tpcb->tp_rtv = 1; 16851204Ssklower } else { 16951204Ssklower /* 17051204Ssklower * No rtt measurement yet - use the unsmoothed rtt. 17151204Ssklower * Set the variance to half the rtt (so our first 17251204Ssklower * retransmit happens at 3*rtt) 17351204Ssklower */ 17451204Ssklower tpcb->tp_rtt = elapsed; 17551204Ssklower tpcb->tp_rtv = elapsed >> 1; 17651204Ssklower } 17751204Ssklower tpcb->tp_rttemit = 0; 17851204Ssklower tpcb->tp_rxtshift = 0; 17951204Ssklower /* 18051204Ssklower * Quoting TCP: "the retransmit should happen at rtt + 4 * rttvar. 18151204Ssklower * Because of the way we do the smoothing, srtt and rttvar 18251204Ssklower * will each average +1/2 tick of bias. When we compute 18351204Ssklower * the retransmit timer, we want 1/2 tick of rounding and 18451204Ssklower * 1 extra tick because of +-1/2 tick uncertainty in the 18551204Ssklower * firing of the timer. The bias will give us exactly the 18651204Ssklower * 1.5 tick we need. But, because the bias is 18751204Ssklower * statistical, we have to test that we don't drop below 18851204Ssklower * the minimum feasible timer (which is 2 ticks)." 18951204Ssklower */ 19051249Ssklower TP_RANGESET(tpcb->tp_dt_ticks, TP_REXMTVAL(tpcb), 19151249Ssklower tpcb->tp_peer_acktime, 128 /* XXX */); 192*51341Ssklower IFDEBUG(D_RTT) 193*51341Ssklower printf("%s tpcb 0x%x, elapsed %d, delta %d, rtt %d, rtv %d, old %d\n", 194*51341Ssklower "tp_rtt_rtv:",tpcb,elapsed,delta,tpcb->tp_rtt,tpcb->tp_rtv,old); 195*51341Ssklower ENDDEBUG 19651249Ssklower tpcb->tp_rxtcur = tpcb->tp_dt_ticks; 19736413Ssklower } 19836413Ssklower 19936413Ssklower /* 20036413Ssklower * CALLED FROM: 20136413Ssklower * tp.trans when an AK arrives 20236413Ssklower * FUNCTION and ARGUMENTS: 20336413Ssklower * Given (cdt), the credit from the AK tpdu, and 20436413Ssklower * (seq), the sequence number from the AK tpdu, 20536413Ssklower * tp_goodack() determines if the AK acknowledges something in the send 20636413Ssklower * window, and if so, drops the appropriate packets from the retransmission 20736413Ssklower * list, computes the round trip time, and updates the retransmission timer 20836413Ssklower * based on the new smoothed round trip time. 20936413Ssklower * RETURN VALUE: 21036413Ssklower * Returns 1 if 21136413Ssklower * EITHER it actually acked something heretofore unacknowledged 21236413Ssklower * OR no news but the credit should be processed. 21336413Ssklower * If something heretofore unacked was acked with this sequence number, 21436413Ssklower * the appropriate tpdus are dropped from the retransmission control list, 21536413Ssklower * by calling tp_sbdrop(). 21636413Ssklower * No need to see the tpdu itself. 21736413Ssklower */ 21836413Ssklower int 21936413Ssklower tp_goodack(tpcb, cdt, seq, subseq) 22036413Ssklower register struct tp_pcb *tpcb; 22136413Ssklower u_int cdt; 22251204Ssklower register SeqNum seq; 22351204Ssklower u_int subseq; 22436413Ssklower { 22551204Ssklower int old_fcredit; 22636413Ssklower int bang = 0; /* bang --> ack for something heretofore unacked */ 22751204Ssklower u_int bytes_acked; 22836413Ssklower 22936413Ssklower IFDEBUG(D_ACKRECV) 23051204Ssklower printf("goodack tpcb 0x%x seq 0x%x cdt %d una 0x%x new 0x%x nxt 0x%x\n", 23151204Ssklower tpcb, seq, cdt, tpcb->tp_snduna, tpcb->tp_sndnew, tpcb->tp_sndnxt); 23236413Ssklower ENDDEBUG 23336413Ssklower IFTRACE(D_ACKRECV) 23436413Ssklower tptraceTPCB(TPPTgotack, 23551204Ssklower seq,cdt, tpcb->tp_snduna,tpcb->tp_sndnew,subseq); 23636413Ssklower ENDTRACE 23736413Ssklower 23836413Ssklower IFPERF(tpcb) 23937469Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0); 24036413Ssklower ENDPERF 24136413Ssklower 24251204Ssklower if (seq == tpcb->tp_snduna) { 24351204Ssklower if (subseq < tpcb->tp_r_subseq || 24451204Ssklower (subseq == tpcb->tp_r_subseq && cdt <= tpcb->tp_fcredit)) { 24551204Ssklower discard_the_ack: 24651204Ssklower IFDEBUG(D_ACKRECV) 24751204Ssklower printf("goodack discard : tpcb 0x%x subseq %d r_subseq %d\n", 24851204Ssklower tpcb, subseq, tpcb->tp_r_subseq); 24951204Ssklower ENDDEBUG 25051204Ssklower goto done; 25136413Ssklower } 25251204Ssklower if (cdt == tpcb->tp_fcredit /*&& thus subseq > tpcb->tp_r_subseq */) { 25351204Ssklower tpcb->tp_r_subseq = subseq; 25451204Ssklower if (tpcb->tp_timer[TM_data_retrans] == 0) 25551204Ssklower tpcb->tp_dupacks = 0; 25651204Ssklower else if (++tpcb->tp_dupacks == tprexmtthresh) { 25751204Ssklower /* partner went out of his way to signal with different 25851204Ssklower subsequences that he has the same lack of an expected 25951204Ssklower packet. This may be an early indiciation of a loss */ 26036413Ssklower 26151204Ssklower SeqNum onxt = tpcb->tp_sndnxt; 26251204Ssklower struct mbuf *onxt_m = tpcb->tp_sndnxt_m; 26351204Ssklower u_int win = min(tpcb->tp_fcredit, 26451204Ssklower tpcb->tp_cong_win / tpcb->tp_l_tpdusize) / 2; 265*51341Ssklower IFDEBUG(D_ACKRECV) 266*51341Ssklower printf("%s tpcb 0x%x seq 0x%x rttseq 0x%x onxt 0x%x\n", 267*51341Ssklower "goodack dupacks:", tpcb, seq, tpcb->tp_rttseq, onxt); 268*51341Ssklower ENDDEBUG 26951204Ssklower if (win < 2) 27051204Ssklower win = 2; 27151204Ssklower tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize; 27251204Ssklower tpcb->tp_timer[TM_data_retrans] = 0; 27351204Ssklower tpcb->tp_rttemit = 0; 27451204Ssklower tpcb->tp_sndnxt = tpcb->tp_snduna; 27551204Ssklower tpcb->tp_sndnxt_m = 0; 27651204Ssklower tpcb->tp_cong_win = tpcb->tp_l_tpdusize; 27751204Ssklower tp_send(tpcb); 27851204Ssklower tpcb->tp_cong_win = tpcb->tp_ssthresh + 27951204Ssklower tpcb->tp_dupacks * tpcb->tp_l_tpdusize; 28051204Ssklower if (SEQ_GT(tpcb, onxt, tpcb->tp_sndnxt)) { 28151204Ssklower tpcb->tp_sndnxt = onxt; 28251204Ssklower tpcb->tp_sndnxt_m = onxt_m; 28351204Ssklower } 28436413Ssklower 28551204Ssklower } else if (tpcb->tp_dupacks > tprexmtthresh) { 28651204Ssklower tpcb->tp_cong_win += tpcb->tp_l_tpdusize; 28751138Ssklower } 28851204Ssklower goto done; 28951204Ssklower } 29051204Ssklower } else if (SEQ_LT(tpcb, seq, tpcb->tp_snduna)) 29151204Ssklower goto discard_the_ack; 29251204Ssklower /* 29351204Ssklower * If the congestion window was inflated to account 29451204Ssklower * for the other side's cached packets, retract it. 29551204Ssklower */ 29651204Ssklower if (tpcb->tp_dupacks > tprexmtthresh && 29751204Ssklower tpcb->tp_cong_win > tpcb->tp_ssthresh) 29851204Ssklower tpcb->tp_cong_win = tpcb->tp_ssthresh; 29951204Ssklower tpcb->tp_r_subseq = subseq; 30051204Ssklower old_fcredit = tpcb->tp_fcredit; 30151204Ssklower tpcb->tp_fcredit = cdt; 30251204Ssklower if (cdt > tpcb->tp_maxfcredit) 30351204Ssklower tpcb->tp_maxfcredit = cdt; 30451204Ssklower tpcb->tp_dupacks = 0; 30536413Ssklower 30651204Ssklower if (IN_SWINDOW(tpcb, seq, tpcb->tp_snduna, tpcb->tp_sndnew)) { 30736413Ssklower 30851204Ssklower tpsbcheck(tpcb, 0); 30951204Ssklower bytes_acked = tp_sbdrop(tpcb, seq); 31051204Ssklower tpsbcheck(tpcb, 1); 31151204Ssklower /* 31251204Ssklower * If transmit timer is running and timed sequence 31351204Ssklower * number was acked, update smoothed round trip time. 31451204Ssklower * Since we now have an rtt measurement, cancel the 31551204Ssklower * timer backoff (cf., Phil Karn's retransmit alg.). 31651204Ssklower * Recompute the initial retransmit timer. 31751204Ssklower */ 31851204Ssklower if (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq)) 31951204Ssklower tp_rtt_rtv(tpcb); 32051204Ssklower /* 32151204Ssklower * If all outstanding data is acked, stop retransmit timer. 32251204Ssklower * If there is more data to be acked, restart retransmit 32351204Ssklower * timer, using current (possibly backed-off) value. 32451204Ssklower * OSI combines the keepalive and persistance functions. 32551204Ssklower * So, there is no persistance timer per se, to restart. 32651204Ssklower */ 32751204Ssklower tpcb->tp_timer[TM_data_retrans] = 32851204Ssklower (seq == tpcb->tp_sndnew) ? 0 : tpcb->tp_rxtcur; 32951204Ssklower /* 33051204Ssklower * When new data is acked, open the congestion window. 33151204Ssklower * If the window gives us less than ssthresh packets 33251204Ssklower * in flight, open exponentially (maxseg per packet). 33351204Ssklower * Otherwise open linearly: maxseg per window 33451204Ssklower * (maxseg^2 / cwnd per packet), plus a constant 33551204Ssklower * fraction of a packet (maxseg/8) to help larger windows 33651204Ssklower * open quickly enough. 33751204Ssklower */ 33851204Ssklower { 33951204Ssklower u_int cw = tpcb->tp_cong_win, incr = tpcb->tp_l_tpdusize; 34036413Ssklower 34151204Ssklower incr = min(incr, bytes_acked); 34251204Ssklower if (cw > tpcb->tp_ssthresh) 34351204Ssklower incr = incr * incr / cw + incr / 8; 34451204Ssklower tpcb->tp_cong_win = 34551204Ssklower min(cw + incr, tpcb->tp_sock->so_snd.sb_hiwat); 34636413Ssklower } 34736413Ssklower tpcb->tp_snduna = seq; 34851204Ssklower if (SEQ_LT(tpcb, tpcb->tp_sndnxt, seq)) { 34951204Ssklower tpcb->tp_sndnxt = seq; 35051204Ssklower tpcb->tp_sndnxt_m = 0; 35151204Ssklower } 35236413Ssklower bang++; 35336413Ssklower } 35436413Ssklower 35536413Ssklower if( cdt != 0 && old_fcredit == 0 ) { 35636413Ssklower tpcb->tp_sendfcc = 1; 35736413Ssklower } 35851249Ssklower if (cdt == 0) { 35951249Ssklower if (old_fcredit != 0) 36051249Ssklower IncStat(ts_zfcdt); 36151249Ssklower /* The following might mean that the window shrunk */ 36251249Ssklower if (tpcb->tp_timer[TM_data_retrans]) { 36351249Ssklower tpcb->tp_timer[TM_data_retrans] = 0; 36451249Ssklower tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks; 36551249Ssklower if (tpcb->tp_sndnxt != tpcb->tp_snduna) { 36651249Ssklower tpcb->tp_sndnxt = tpcb->tp_snduna; 36751249Ssklower tpcb->tp_sndnxt_m = 0; 36851249Ssklower } 36951249Ssklower } 37036413Ssklower } 37136413Ssklower tpcb->tp_fcredit = cdt; 37251204Ssklower bang |= (old_fcredit < cdt); 37336413Ssklower 37451204Ssklower done: 37536413Ssklower IFDEBUG(D_ACKRECV) 37651204Ssklower printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n", 37751204Ssklower bang, cdt, old_fcredit, tpcb->tp_cong_win); 37836413Ssklower ENDDEBUG 37951204Ssklower /* if (bang) XXXXX Very bad to remove this test, but somethings broken */ 38051204Ssklower tp_send(tpcb); 38151204Ssklower return (bang); 38236413Ssklower } 38336413Ssklower 38436413Ssklower /* 38536413Ssklower * CALLED FROM: 38636413Ssklower * tp_goodack() 38736413Ssklower * FUNCTION and ARGUMENTS: 38850901Ssklower * drops everything up TO but not INCLUDING seq # (seq) 38936413Ssklower * from the retransmission queue. 39036413Ssklower */ 39136413Ssklower tp_sbdrop(tpcb, seq) 39250901Ssklower register struct tp_pcb *tpcb; 39336413Ssklower SeqNum seq; 39436413Ssklower { 39550901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 39651204Ssklower register int i = SEQ_SUB(tpcb, seq, tpcb->tp_snduna); 39751204Ssklower int oldcc = sb->sb_cc, oldi = i; 39836413Ssklower 39951204Ssklower if (i >= tpcb->tp_seqhalf) 40051204Ssklower printf("tp_spdropping too much -- should panic"); 40151204Ssklower while (i-- > 0) 40251204Ssklower sbdroprecord(sb); 40336413Ssklower IFDEBUG(D_ACKRECV) 40451204Ssklower printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n", 40551204Ssklower oldi, oldcc - sb->sb_cc, tpcb, seq); 40636413Ssklower ENDDEBUG 40751204Ssklower if (sb->sb_flags & SB_NOTIFY) 40851204Ssklower sowwakeup(tpcb->tp_sock); 40951138Ssklower return (oldcc - sb->sb_cc); 41036413Ssklower } 41136413Ssklower 41236413Ssklower /* 41336413Ssklower * CALLED FROM: 41436413Ssklower * tp.trans on user send request, arrival of AK and arrival of XAK 41536413Ssklower * FUNCTION and ARGUMENTS: 41651204Ssklower * Emits tpdus starting at sequence number (tpcb->tp_sndnxt). 41736413Ssklower * Emits until a) runs out of data, or b) runs into an XPD mark, or 41851204Ssklower * c) it hits seq number (highseq) limited by cong or credit. 41936413Ssklower * 42036413Ssklower * If you want XPD to buffer > 1 du per socket buffer, you can 42136413Ssklower * modifiy this to issue XPD tpdus also, but then it'll have 42236413Ssklower * to take some argument(s) to distinguish between the type of DU to 42350901Ssklower * hand tp_emit. 42436413Ssklower * 42536413Ssklower * When something is sent for the first time, its time-of-send 42651204Ssklower * is stashed (in system clock ticks rather than pf_slowtimo ticks). 42751204Ssklower * When the ack arrives, the smoothed round-trip time is figured 42851204Ssklower * using this value. 42936413Ssklower */ 43051204Ssklower void 43136413Ssklower tp_send(tpcb) 43236413Ssklower register struct tp_pcb *tpcb; 43336413Ssklower { 43436413Ssklower register int len; 43551204Ssklower register struct mbuf *m; 43651204Ssklower struct mbuf *mb = 0; 43736413Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 43851204Ssklower unsigned int eotsdu = 0; 43951204Ssklower SeqNum highseq, checkseq; 44051204Ssklower int idle, idleticks, off, cong_win; 44136413Ssklower #ifdef TP_PERF_MEAS 442*51341Ssklower int send_start_time = ticks; 44351204Ssklower SeqNum oldnxt = tpcb->tp_sndnxt; 44436413Ssklower #endif TP_PERF_MEAS 44536413Ssklower 44651204Ssklower idle = (tpcb->tp_snduna == tpcb->tp_sndnew); 44751204Ssklower if (idle) { 44851204Ssklower idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact]; 44951204Ssklower if (idleticks > tpcb->tp_dt_ticks) 45051204Ssklower /* 45151204Ssklower * We have been idle for "a while" and no acks are 45251204Ssklower * expected to clock out any data we send -- 45351204Ssklower * slow start to get ack "clock" running again. 45451204Ssklower */ 45551204Ssklower tpcb->tp_cong_win = tpcb->tp_l_tpdusize; 45651204Ssklower } 45736413Ssklower 45851204Ssklower cong_win = tpcb->tp_cong_win; 45951204Ssklower highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna); 46051204Ssklower if (tpcb->tp_Xsnd.sb_mb) 46151204Ssklower highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew); 46236413Ssklower 46336413Ssklower IFDEBUG(D_DATA) 46451204Ssklower printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n", 46551204Ssklower tpcb, tpcb->tp_sndnxt, cong_win, highseq); 46636413Ssklower ENDDEBUG 46736413Ssklower IFTRACE(D_DATA) 46851204Ssklower tptraceTPCB( TPPTmisc, "tp_send sndnew snduna", 46951204Ssklower tpcb->tp_sndnew, tpcb->tp_snduna, 0, 0); 47051204Ssklower tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin", 47151204Ssklower tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win); 47236413Ssklower ENDTRACE 47336413Ssklower IFTRACE(D_DATA) 47451204Ssklower tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin", 47551204Ssklower tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win); 47636413Ssklower ENDTRACE 47736413Ssklower 47851204Ssklower if (tpcb->tp_sndnxt_m) 47951204Ssklower m = tpcb->tp_sndnxt_m; 48051204Ssklower else { 48151204Ssklower off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna); 48251204Ssklower for (m = sb->sb_mb; m && off > 0; m = m->m_next) 48351204Ssklower off--; 48451204Ssklower } 48551204Ssklower send: 48651204Ssklower /* 48751204Ssklower * Avoid silly window syndrome here . . . figure out how! 48851204Ssklower */ 48951204Ssklower checkseq = tpcb->tp_sndnum; 49051204Ssklower if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq)) 49151249Ssklower checkseq = highseq; /* i.e. DON'T retain highest assigned packet */ 49236413Ssklower 49351204Ssklower while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) { 49436413Ssklower 49551204Ssklower eotsdu = (m->m_flags & M_EOR) != 0; 49651204Ssklower len = m->m_pkthdr.len; 49751204Ssklower if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 && 49851204Ssklower len < (tpcb->tp_l_tpdusize / 2)) 49951204Ssklower break; /* Nagle . . . . . */ 50051204Ssklower cong_win -= len; 50136413Ssklower /* make a copy - mb goes into the retransmission list 50236413Ssklower * while m gets emitted. m_copy won't copy a zero-length mbuf. 50336413Ssklower */ 50451204Ssklower mb = m; 50550901Ssklower m = m_copy(mb, 0, M_COPYALL); 50650901Ssklower if (m == MNULL) 50751204Ssklower break; 50851204Ssklower IFTRACE(D_STASH) 50936413Ssklower tptraceTPCB( TPPTmisc, 51051204Ssklower "tp_send mcopy nxt high eotsdu len", 51151204Ssklower tpcb->tp_sndnxt, highseq, eotsdu, len); 51236413Ssklower ENDTRACE 51351204Ssklower 51451204Ssklower IFDEBUG(D_DATA) 51551204Ssklower printf("tp_sending tpcb 0x%x nxt 0x%x\n", 51651204Ssklower tpcb, tpcb->tp_sndnxt); 51751204Ssklower ENDDEBUG 51851204Ssklower /* when headers are precomputed, may need to fill 51950901Ssklower in checksum here */ 52050901Ssklower if (tpcb->tp_sock->so_error = 52151204Ssklower tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) { 52236413Ssklower /* error */ 52351204Ssklower break; 52436413Ssklower } 52551204Ssklower m = mb->m_nextpkt; 52651204Ssklower tpcb->tp_sndnxt_m = m; 52751204Ssklower if (tpcb->tp_sndnxt == tpcb->tp_sndnew) { 52851204Ssklower SEQ_INC(tpcb, tpcb->tp_sndnew); 52951204Ssklower /* 53051204Ssklower * Time this transmission if not a retransmission and 53151204Ssklower * not currently timing anything. 53251204Ssklower */ 53351204Ssklower if (tpcb->tp_rttemit == 0) { 534*51341Ssklower tpcb->tp_rttemit = ticks; 53551204Ssklower tpcb->tp_rttseq = tpcb->tp_sndnxt; 53651204Ssklower } 53751204Ssklower tpcb->tp_sndnxt = tpcb->tp_sndnew; 53851204Ssklower } else 53951204Ssklower SEQ_INC(tpcb, tpcb->tp_sndnxt); 54051204Ssklower /* 54151204Ssklower * Set retransmit timer if not currently set. 54251204Ssklower * Initial value for retransmit timer is smoothed 54351204Ssklower * round-trip time + 2 * round-trip time variance. 54451204Ssklower * Initialize shift counter which is used for backoff 54551204Ssklower * of retransmit time. 54651204Ssklower */ 54751204Ssklower if (tpcb->tp_timer[TM_data_retrans] == 0) { 54851204Ssklower tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks; 54951204Ssklower tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks; 55051204Ssklower tpcb->tp_rxtshift = 0; 55151138Ssklower } 55236413Ssklower } 55351204Ssklower if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum)) 55451204Ssklower tpcb->tp_oktonagle = 0; 55550236Ssklower #ifdef TP_PERF_MEAS 55636413Ssklower IFPERF(tpcb) 55736413Ssklower { 55836413Ssklower register int npkts; 559*51341Ssklower int elapsed = ticks - send_start_time, *t; 56051138Ssklower struct timeval now; 56136413Ssklower 56251204Ssklower npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt); 56336413Ssklower 56451204Ssklower if (npkts > 0) 56536413Ssklower tpcb->tp_Nwindow++; 56636413Ssklower 56736413Ssklower if (npkts > TP_PM_MAX) 56836413Ssklower npkts = TP_PM_MAX; 56936413Ssklower 57036413Ssklower t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); 57151138Ssklower *t += (t - elapsed) >> TP_RTT_ALPHA; 57236413Ssklower 57351204Ssklower if (mb == 0) { 57436413Ssklower IncPStat(tpcb, tps_win_lim_by_data[npkts] ); 57536413Ssklower } else { 57636413Ssklower IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); 57736413Ssklower /* not true with congestion-window being used */ 57836413Ssklower } 57951138Ssklower now.tv_sec = elapsed / hz; 58051138Ssklower now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz; 58136413Ssklower tpmeas( tpcb->tp_lref, 58251204Ssklower TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts); 58336413Ssklower } 58436413Ssklower ENDPERF 58550236Ssklower #endif TP_PERF_MEAS 58636413Ssklower 58736413Ssklower 58836413Ssklower IFTRACE(D_DATA) 58936413Ssklower tptraceTPCB( TPPTmisc, 59051204Ssklower "tp_send at end: new nxt eotsdu error", 59151204Ssklower tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error); 59236413Ssklower 59336413Ssklower ENDTRACE 59436413Ssklower } 59536413Ssklower 59650901Ssklower int TPNagleok; 59750901Ssklower int TPNagled; 59850901Ssklower 59950901Ssklower tp_packetize(tpcb, m, eotsdu) 60050901Ssklower register struct tp_pcb *tpcb; 60150901Ssklower register struct mbuf *m; 60250901Ssklower int eotsdu; 60350901Ssklower { 60450901Ssklower register struct mbuf *n; 60550901Ssklower register struct sockbuf *sb = &tpcb->tp_sock->so_snd; 60650901Ssklower int maxsize = tpcb->tp_l_tpdusize 60750901Ssklower - tp_headersize(DT_TPDU_type, tpcb) 60850901Ssklower - (tpcb->tp_use_checksum?4:0) ; 60950901Ssklower int totlen = m->m_pkthdr.len; 61050901Ssklower struct mbuf *m_split(); 61150901Ssklower /* 61250901Ssklower * Pre-packetize the data in the sockbuf 61350901Ssklower * according to negotiated mtu. Do it here 61450901Ssklower * where we can safely wait for mbufs. 61550901Ssklower * 61650901Ssklower * This presumes knowledge of sockbuf conventions. 61750901Ssklower * TODO: allocate space for header and fill it in (once!). 61850901Ssklower */ 61951204Ssklower IFDEBUG(D_DATA) 62051204Ssklower printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n", 62151204Ssklower maxsize, totlen, eotsdu, tpcb->tp_sndnum); 62250901Ssklower ENDTRACE 62350901Ssklower if (tpcb->tp_oktonagle) { 62450901Ssklower if ((n = sb->sb_mb) == 0) 62550901Ssklower panic("tp_packetize"); 62650901Ssklower while (n->m_act) 62750901Ssklower n = n->m_act; 62850901Ssklower if (n->m_flags & M_EOR) 62950901Ssklower panic("tp_packetize 2"); 63050901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 63150901Ssklower if (totlen + n->m_pkthdr.len < maxsize) { 63250901Ssklower /* There is an unsent packet with space, combine data */ 63350901Ssklower struct mbuf *old_n = n; 63450901Ssklower tpsbcheck(tpcb,3); 63550901Ssklower n->m_pkthdr.len += totlen; 63650901Ssklower while (n->m_next) 63750901Ssklower n = n->m_next; 63850901Ssklower sbcompress(sb, m, n); 63950901Ssklower tpsbcheck(tpcb,4); 64050901Ssklower n = old_n; 64150901Ssklower TPNagled++; 64250901Ssklower goto out; 64350901Ssklower } 64450901Ssklower } 64550901Ssklower while (m) { 64650901Ssklower n = m; 64750901Ssklower if (totlen > maxsize) { 64850901Ssklower if ((m = m_split(n, maxsize, M_WAIT)) == 0) 64950901Ssklower panic("tp_packetize"); 65050901Ssklower } else 65150901Ssklower m = 0; 65250901Ssklower totlen -= maxsize; 65350901Ssklower tpsbcheck(tpcb, 5); 65450901Ssklower sbappendrecord(sb, n); 65550901Ssklower tpsbcheck(tpcb, 6); 65650901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 65750901Ssklower } 65850901Ssklower out: 65950901Ssklower if (eotsdu) { 66050901Ssklower n->m_flags |= M_EOR; /* XXX belongs at end */ 66150901Ssklower tpcb->tp_oktonagle = 0; 66250901Ssklower } else { 66350901Ssklower SEQ_DEC(tpcb, tpcb->tp_sndnum); 66450901Ssklower tpcb->tp_oktonagle = 1; 66550901Ssklower TPNagleok++; 66650901Ssklower } 66751204Ssklower IFDEBUG(D_DATA) 66851204Ssklower printf("SEND out: oktonagle %d sndnum 0x%x\n", 66951204Ssklower tpcb->tp_oktonagle, tpcb->tp_sndnum); 67051204Ssklower ENDTRACE 67150901Ssklower return 0; 67250901Ssklower } 67350901Ssklower 67450901Ssklower 67536413Ssklower /* 67636413Ssklower * NAME: tp_stash() 67736413Ssklower * CALLED FROM: 67836413Ssklower * tp.trans on arrival of a DT tpdu 67936413Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 68036413Ssklower * Returns 1 if 68136413Ssklower * a) something new arrived and it's got eotsdu_reached bit on, 68236413Ssklower * b) this arrival was caused other out-of-sequence things to be 68336413Ssklower * accepted, or 68436413Ssklower * c) this arrival is the highest seq # for which we last gave credit 68536413Ssklower * (sender just sent a whole window) 68636413Ssklower * In other words, returns 1 if tp should send an ack immediately, 0 if 68736413Ssklower * the ack can wait a while. 68836413Ssklower * 68936413Ssklower * Note: this implementation no longer renegs on credit, (except 69036413Ssklower * when debugging option D_RENEG is on, for the purpose of testing 69136413Ssklower * ack subsequencing), so we don't need to check for incoming tpdus 69236413Ssklower * being in a reneged portion of the window. 69336413Ssklower */ 69436413Ssklower 69551204Ssklower tp_stash(tpcb, e) 69636413Ssklower register struct tp_pcb *tpcb; 69736413Ssklower register struct tp_event *e; 69836413Ssklower { 69936413Ssklower register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; 70036413Ssklower /* 0--> delay acks until full window */ 70136413Ssklower /* 1--> ack each tpdu */ 70236413Ssklower #ifndef lint 70336413Ssklower #define E e->ATTR(DT_TPDU) 70436413Ssklower #else lint 70536413Ssklower #define E e->ev_union.EV_DT_TPDU 70636413Ssklower #endif lint 70736413Ssklower 70836413Ssklower if ( E.e_eot ) { 70936413Ssklower register struct mbuf *n = E.e_data; 71037469Ssklower n->m_flags |= M_EOR; 71138841Ssklower n->m_act = 0; 71237469Ssklower } 71336413Ssklower IFDEBUG(D_STASH) 71436413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 71536413Ssklower "stash: so_rcv before appending"); 71636413Ssklower dump_mbuf(E.e_data, 71736413Ssklower "stash: e_data before appending"); 71836413Ssklower ENDDEBUG 71936413Ssklower 72036413Ssklower IFPERF(tpcb) 72136413Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen; 72236413Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 72337469Ssklower E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); 72436413Ssklower ENDPERF 72536413Ssklower 72651024Ssklower if (E.e_seq == tpcb->tp_rcvnxt) { 72736413Ssklower 72836413Ssklower IFDEBUG(D_STASH) 72936413Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", 73036413Ssklower E.e_seq, E.e_datalen, E.e_eot); 73136413Ssklower ENDDEBUG 73236413Ssklower 73336413Ssklower IFTRACE(D_STASH) 73436413Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 73536413Ssklower E.e_seq, E.e_datalen, E.e_eot, 0); 73636413Ssklower ENDTRACE 73736413Ssklower 73851024Ssklower SET_DELACK(tpcb); 73951024Ssklower 74037469Ssklower sbappend(&tpcb->tp_sock->so_rcv, E.e_data); 74137469Ssklower 74236413Ssklower SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 74336413Ssklower /* 74450901Ssklower * move chains from the reassembly queue to the socket buffer 74536413Ssklower */ 74650901Ssklower if (tpcb->tp_rsycnt) { 74750901Ssklower register struct mbuf **mp; 74850901Ssklower struct mbuf **mplim; 74936413Ssklower 75050901Ssklower mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit); 75150901Ssklower mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit; 75236413Ssklower 75350901Ssklower while (tpcb->tp_rsycnt && *mp) { 75450901Ssklower sbappend(&tpcb->tp_sock->so_rcv, *mp); 75550901Ssklower tpcb->tp_rsycnt--; 75650901Ssklower *mp = 0; 75750901Ssklower SEQ_INC(tpcb, tpcb->tp_rcvnxt); 75836413Ssklower ack_reason |= ACK_REORDER; 75950901Ssklower if (++mp == mplim) 76050901Ssklower mp = tpcb->tp_rsyq; 76136413Ssklower } 76236413Ssklower } 76336413Ssklower IFDEBUG(D_STASH) 76436413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 76536413Ssklower "stash: so_rcv after appending"); 76636413Ssklower ENDDEBUG 76736413Ssklower 76836413Ssklower } else { 76950901Ssklower register struct mbuf **mp; 77050901Ssklower SeqNum uwe; 77136413Ssklower 77236413Ssklower IFTRACE(D_STASH) 77336413Ssklower tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", 77436413Ssklower E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); 77536413Ssklower ENDTRACE 77636413Ssklower 77750975Ssklower if (tpcb->tp_rsyq == 0) 77850975Ssklower tp_rsyset(tpcb); 77950901Ssklower uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit); 78050901Ssklower if (tpcb->tp_rsyq == 0 || 78150901Ssklower !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) { 78236413Ssklower ack_reason = ACK_DONT; 78350901Ssklower m_freem(E.e_data); 78450901Ssklower } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) { 78536413Ssklower IFDEBUG(D_STASH) 78636413Ssklower printf("tp_stash - drop & ack\n"); 78736413Ssklower ENDDEBUG 78836413Ssklower 78936413Ssklower /* retransmission - drop it and force an ack */ 79036413Ssklower IncStat(ts_dt_dup); 79136413Ssklower IFPERF(tpcb) 79236413Ssklower IncPStat(tpcb, tps_n_ack_cuz_dup); 79336413Ssklower ENDPERF 79436413Ssklower 79550901Ssklower m_freem(E.e_data); 79636413Ssklower ack_reason |= ACK_DUP; 79750901Ssklower } else { 79850901Ssklower *mp = E.e_data; 79950901Ssklower tpcb->tp_rsycnt++; 80050901Ssklower ack_reason = ACK_DONT; 80136413Ssklower } 80236413Ssklower } 80351024Ssklower /* there were some comments of historical interest here. */ 80436413Ssklower { 80536413Ssklower LOCAL_CREDIT(tpcb); 80636413Ssklower 80736413Ssklower if ( E.e_seq == tpcb->tp_sent_uwe ) 80836413Ssklower ack_reason |= ACK_STRAT_FULLWIN; 80936413Ssklower 81036413Ssklower IFTRACE(D_STASH) 81136413Ssklower tptraceTPCB(TPPTmisc, 81236413Ssklower "end of stash, eot, ack_reason, sent_uwe ", 81336413Ssklower E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); 81436413Ssklower ENDTRACE 81536413Ssklower 81636413Ssklower if ( ack_reason == ACK_DONT ) { 81736413Ssklower IncStat( ts_ackreason[ACK_DONT] ); 81836413Ssklower return 0; 81936413Ssklower } else { 82036413Ssklower IFPERF(tpcb) 82136413Ssklower if(ack_reason & ACK_STRAT_EACH) { 82236413Ssklower IncPStat(tpcb, tps_n_ack_cuz_strat); 82336413Ssklower } else if(ack_reason & ACK_STRAT_FULLWIN) { 82436413Ssklower IncPStat(tpcb, tps_n_ack_cuz_fullwin); 82536413Ssklower } else if(ack_reason & ACK_REORDER) { 82636413Ssklower IncPStat(tpcb, tps_n_ack_cuz_reorder); 82736413Ssklower } 82836413Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, 82936413Ssklower SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); 83036413Ssklower ENDPERF 83136413Ssklower { 83236413Ssklower register int i; 83336413Ssklower 83436413Ssklower /* keep track of all reasons that apply */ 83536413Ssklower for( i=1; i<_ACK_NUM_REASONS_ ;i++) { 83636413Ssklower if( ack_reason & (1<<i) ) 83736413Ssklower IncStat( ts_ackreason[i] ); 83836413Ssklower } 83936413Ssklower } 84036413Ssklower return 1; 84136413Ssklower } 84236413Ssklower } 84336413Ssklower } 84450901Ssklower 84550901Ssklower /* 84650901Ssklower * tp_rsyflush - drop all the packets on the reassembly queue. 84750901Ssklower * Do this when closing the socket, or when somebody has changed 84850901Ssklower * the space avaible in the receive socket (XXX). 84950901Ssklower */ 85050901Ssklower tp_rsyflush(tpcb) 85150901Ssklower register struct tp_pcb *tpcb; 85250901Ssklower { 85350901Ssklower register struct mbuf *m, **mp; 85450901Ssklower if (tpcb->tp_rsycnt) { 85550901Ssklower for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit; 85650901Ssklower --mp >= tpcb->tp_rsyq; ) 85750901Ssklower if (*mp) { 85850901Ssklower tpcb->tp_rsycnt--; 85950901Ssklower m_freem(*mp); 86050901Ssklower } 86150901Ssklower if (tpcb->tp_rsycnt) 86250901Ssklower panic("tp_rsyflush"); 86350901Ssklower } 86450901Ssklower free((caddr_t)tpcb->tp_rsyq, M_PCB); 86550901Ssklower tpcb->tp_rsyq = 0; 86650901Ssklower } 86750901Ssklower 86850901Ssklower tp_rsyset(tpcb) 86950901Ssklower register struct tp_pcb *tpcb; 87050901Ssklower { 87150901Ssklower register struct socket *so = tpcb->tp_sock; 87250901Ssklower int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf; 87350975Ssklower int old_credit = tpcb->tp_maxlcredit; 87450975Ssklower caddr_t rsyq; 87550901Ssklower 87650901Ssklower tpcb->tp_maxlcredit = maxcredit = min(maxcredit, 87750901Ssklower (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize); 87850901Ssklower 87950975Ssklower if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0) 88050975Ssklower return; 88150901Ssklower maxcredit *= sizeof(struct mbuf *); 88250901Ssklower if (tpcb->tp_rsyq) 88350901Ssklower tp_rsyflush(tpcb); 88450901Ssklower if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT)) 88550901Ssklower bzero(rsyq, maxcredit); 88650901Ssklower tpcb->tp_rsyq = (struct mbuf **)rsyq; 88750901Ssklower } 88850901Ssklower 88950901Ssklower tpsbcheck(tpcb, i) 89050901Ssklower struct tp_pcb *tpcb; 89150901Ssklower { 89250901Ssklower register struct mbuf *n, *m; 89350901Ssklower register int len = 0, mbcnt = 0, pktlen; 89450901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 89550901Ssklower 89650901Ssklower for (n = sb->sb_mb; n; n = n->m_nextpkt) { 89750901Ssklower if ((n->m_flags & M_PKTHDR) == 0) 89850901Ssklower panic("tpsbcheck nohdr"); 89950901Ssklower pktlen = len + n->m_pkthdr.len; 90050901Ssklower for (m = n; m; m = m->m_next) { 90150901Ssklower len += m->m_len; 90250901Ssklower mbcnt += MSIZE; 90350901Ssklower if (m->m_flags & M_EXT) 90450901Ssklower mbcnt += m->m_ext.ext_size; 90550901Ssklower } 90650901Ssklower if (len != pktlen) { 90750901Ssklower printf("test %d; len %d != pktlen %d on mbuf 0x%x\n", 90850901Ssklower i, len, pktlen, n); 90950901Ssklower panic("tpsbcheck short"); 91050901Ssklower } 91150901Ssklower } 91250901Ssklower if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { 91350901Ssklower printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc, 91450901Ssklower mbcnt, sb->sb_mbcnt); 91550901Ssklower panic("tpsbcheck"); 91650901Ssklower } 91750901Ssklower } 918