149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*56533Sbostic * @(#)tp_subr.c 7.20 (Berkeley) 10/11/92 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 51*56533Sbostic #include <sys/param.h> 52*56533Sbostic #include <sys/systm.h> 53*56533Sbostic #include <sys/mbuf.h> 54*56533Sbostic #include <sys/socket.h> 55*56533Sbostic #include <sys/socketvar.h> 56*56533Sbostic #include <sys/protosw.h> 57*56533Sbostic #include <sys/errno.h> 58*56533Sbostic #include <sys/time.h> 59*56533Sbostic #include <sys/kernel.h> 6036413Ssklower 61*56533Sbostic #include <netiso/tp_ip.h> 62*56533Sbostic #include <netiso/iso.h> 63*56533Sbostic #include <netiso/argo_debug.h> 64*56533Sbostic #include <netiso/tp_timer.h> 65*56533Sbostic #include <netiso/tp_param.h> 66*56533Sbostic #include <netiso/tp_stat.h> 67*56533Sbostic #include <netiso/tp_pcb.h> 68*56533Sbostic #include <netiso/tp_tpdu.h> 69*56533Sbostic #include <netiso/tp_trace.h> 70*56533Sbostic #include <netiso/tp_meas.h> 71*56533Sbostic #include <netiso/tp_seq.h> 7236413Ssklower 7351204Ssklower int tp_emit(), tp_sbdrop(); 7451204Ssklower int tprexmtthresh = 3; 7551341Ssklower 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 { 14351341Ssklower int old = tpcb->tp_rtt; 14451341Ssklower 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 */); 19251341Ssklower IFDEBUG(D_RTT) 19351341Ssklower printf("%s tpcb 0x%x, elapsed %d, delta %d, rtt %d, rtv %d, old %d\n", 19451341Ssklower "tp_rtt_rtv:",tpcb,elapsed,delta,tpcb->tp_rtt,tpcb->tp_rtv,old); 19551341Ssklower 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; 26551341Ssklower IFDEBUG(D_ACKRECV) 26651341Ssklower printf("%s tpcb 0x%x seq 0x%x rttseq 0x%x onxt 0x%x\n", 26751341Ssklower "goodack dupacks:", tpcb, seq, tpcb->tp_rttseq, onxt); 26851341Ssklower 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 */ 32753689Ssklower if (tpcb->tp_class != TP_CLASS_0) 32853689Ssklower tpcb->tp_timer[TM_data_retrans] = 32953689Ssklower (seq == tpcb->tp_sndnew) ? 0 : tpcb->tp_rxtcur; 33051204Ssklower /* 33151204Ssklower * When new data is acked, open the congestion window. 33251204Ssklower * If the window gives us less than ssthresh packets 33351204Ssklower * in flight, open exponentially (maxseg per packet). 33451204Ssklower * Otherwise open linearly: maxseg per window 33551204Ssklower * (maxseg^2 / cwnd per packet), plus a constant 33651204Ssklower * fraction of a packet (maxseg/8) to help larger windows 33751204Ssklower * open quickly enough. 33851204Ssklower */ 33951204Ssklower { 34051204Ssklower u_int cw = tpcb->tp_cong_win, incr = tpcb->tp_l_tpdusize; 34136413Ssklower 34251204Ssklower incr = min(incr, bytes_acked); 34351204Ssklower if (cw > tpcb->tp_ssthresh) 34451204Ssklower incr = incr * incr / cw + incr / 8; 34551204Ssklower tpcb->tp_cong_win = 34651204Ssklower min(cw + incr, tpcb->tp_sock->so_snd.sb_hiwat); 34736413Ssklower } 34836413Ssklower tpcb->tp_snduna = seq; 34951204Ssklower if (SEQ_LT(tpcb, tpcb->tp_sndnxt, seq)) { 35051204Ssklower tpcb->tp_sndnxt = seq; 35151204Ssklower tpcb->tp_sndnxt_m = 0; 35251204Ssklower } 35336413Ssklower bang++; 35436413Ssklower } 35536413Ssklower 35636413Ssklower if( cdt != 0 && old_fcredit == 0 ) { 35736413Ssklower tpcb->tp_sendfcc = 1; 35836413Ssklower } 35951249Ssklower if (cdt == 0) { 36051249Ssklower if (old_fcredit != 0) 36151249Ssklower IncStat(ts_zfcdt); 36251249Ssklower /* The following might mean that the window shrunk */ 36351249Ssklower if (tpcb->tp_timer[TM_data_retrans]) { 36451249Ssklower tpcb->tp_timer[TM_data_retrans] = 0; 36551249Ssklower tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks; 36651249Ssklower if (tpcb->tp_sndnxt != tpcb->tp_snduna) { 36751249Ssklower tpcb->tp_sndnxt = tpcb->tp_snduna; 36851249Ssklower tpcb->tp_sndnxt_m = 0; 36951249Ssklower } 37051249Ssklower } 37136413Ssklower } 37236413Ssklower tpcb->tp_fcredit = cdt; 37351204Ssklower bang |= (old_fcredit < cdt); 37436413Ssklower 37551204Ssklower done: 37636413Ssklower IFDEBUG(D_ACKRECV) 37751204Ssklower printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n", 37851204Ssklower bang, cdt, old_fcredit, tpcb->tp_cong_win); 37936413Ssklower ENDDEBUG 38051204Ssklower /* if (bang) XXXXX Very bad to remove this test, but somethings broken */ 38151204Ssklower tp_send(tpcb); 38251204Ssklower return (bang); 38336413Ssklower } 38436413Ssklower 38536413Ssklower /* 38636413Ssklower * CALLED FROM: 38736413Ssklower * tp_goodack() 38836413Ssklower * FUNCTION and ARGUMENTS: 38950901Ssklower * drops everything up TO but not INCLUDING seq # (seq) 39036413Ssklower * from the retransmission queue. 39136413Ssklower */ 39236413Ssklower tp_sbdrop(tpcb, seq) 39350901Ssklower register struct tp_pcb *tpcb; 39436413Ssklower SeqNum seq; 39536413Ssklower { 39650901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 39751204Ssklower register int i = SEQ_SUB(tpcb, seq, tpcb->tp_snduna); 39851204Ssklower int oldcc = sb->sb_cc, oldi = i; 39936413Ssklower 40051204Ssklower if (i >= tpcb->tp_seqhalf) 40151204Ssklower printf("tp_spdropping too much -- should panic"); 40251204Ssklower while (i-- > 0) 40351204Ssklower sbdroprecord(sb); 40436413Ssklower IFDEBUG(D_ACKRECV) 40551204Ssklower printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n", 40651204Ssklower oldi, oldcc - sb->sb_cc, tpcb, seq); 40736413Ssklower ENDDEBUG 40851204Ssklower if (sb->sb_flags & SB_NOTIFY) 40951204Ssklower sowwakeup(tpcb->tp_sock); 41051138Ssklower return (oldcc - sb->sb_cc); 41136413Ssklower } 41236413Ssklower 41336413Ssklower /* 41436413Ssklower * CALLED FROM: 41536413Ssklower * tp.trans on user send request, arrival of AK and arrival of XAK 41636413Ssklower * FUNCTION and ARGUMENTS: 41751204Ssklower * Emits tpdus starting at sequence number (tpcb->tp_sndnxt). 41836413Ssklower * Emits until a) runs out of data, or b) runs into an XPD mark, or 41951204Ssklower * c) it hits seq number (highseq) limited by cong or credit. 42036413Ssklower * 42136413Ssklower * If you want XPD to buffer > 1 du per socket buffer, you can 42236413Ssklower * modifiy this to issue XPD tpdus also, but then it'll have 42336413Ssklower * to take some argument(s) to distinguish between the type of DU to 42450901Ssklower * hand tp_emit. 42536413Ssklower * 42636413Ssklower * When something is sent for the first time, its time-of-send 42751204Ssklower * is stashed (in system clock ticks rather than pf_slowtimo ticks). 42851204Ssklower * When the ack arrives, the smoothed round-trip time is figured 42951204Ssklower * using this value. 43036413Ssklower */ 43151204Ssklower void 43236413Ssklower tp_send(tpcb) 43336413Ssklower register struct tp_pcb *tpcb; 43436413Ssklower { 43536413Ssklower register int len; 43651204Ssklower register struct mbuf *m; 43751204Ssklower struct mbuf *mb = 0; 43836413Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 43951204Ssklower unsigned int eotsdu = 0; 44051204Ssklower SeqNum highseq, checkseq; 44151204Ssklower int idle, idleticks, off, cong_win; 44236413Ssklower #ifdef TP_PERF_MEAS 44351341Ssklower int send_start_time = ticks; 44451204Ssklower SeqNum oldnxt = tpcb->tp_sndnxt; 44536413Ssklower #endif TP_PERF_MEAS 44636413Ssklower 44751204Ssklower idle = (tpcb->tp_snduna == tpcb->tp_sndnew); 44851204Ssklower if (idle) { 44951204Ssklower idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact]; 45051204Ssklower if (idleticks > tpcb->tp_dt_ticks) 45151204Ssklower /* 45251204Ssklower * We have been idle for "a while" and no acks are 45351204Ssklower * expected to clock out any data we send -- 45451204Ssklower * slow start to get ack "clock" running again. 45551204Ssklower */ 45651204Ssklower tpcb->tp_cong_win = tpcb->tp_l_tpdusize; 45751204Ssklower } 45836413Ssklower 45951204Ssklower cong_win = tpcb->tp_cong_win; 46051204Ssklower highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna); 46151204Ssklower if (tpcb->tp_Xsnd.sb_mb) 46251204Ssklower highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew); 46336413Ssklower 46436413Ssklower IFDEBUG(D_DATA) 46551204Ssklower printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n", 46651204Ssklower tpcb, tpcb->tp_sndnxt, cong_win, highseq); 46736413Ssklower ENDDEBUG 46836413Ssklower IFTRACE(D_DATA) 46951204Ssklower tptraceTPCB( TPPTmisc, "tp_send sndnew snduna", 47051204Ssklower tpcb->tp_sndnew, tpcb->tp_snduna, 0, 0); 47151204Ssklower tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin", 47251204Ssklower tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win); 47336413Ssklower ENDTRACE 47436413Ssklower IFTRACE(D_DATA) 47551204Ssklower tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin", 47651204Ssklower tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win); 47736413Ssklower ENDTRACE 47836413Ssklower 47951204Ssklower if (tpcb->tp_sndnxt_m) 48051204Ssklower m = tpcb->tp_sndnxt_m; 48151204Ssklower else { 48251204Ssklower off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna); 48351204Ssklower for (m = sb->sb_mb; m && off > 0; m = m->m_next) 48451204Ssklower off--; 48551204Ssklower } 48651204Ssklower send: 48751204Ssklower /* 48851204Ssklower * Avoid silly window syndrome here . . . figure out how! 48951204Ssklower */ 49051204Ssklower checkseq = tpcb->tp_sndnum; 49151204Ssklower if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq)) 49251249Ssklower checkseq = highseq; /* i.e. DON'T retain highest assigned packet */ 49336413Ssklower 49451204Ssklower while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) { 49536413Ssklower 49651204Ssklower eotsdu = (m->m_flags & M_EOR) != 0; 49751204Ssklower len = m->m_pkthdr.len; 49851204Ssklower if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 && 49951204Ssklower len < (tpcb->tp_l_tpdusize / 2)) 50051204Ssklower break; /* Nagle . . . . . */ 50151204Ssklower cong_win -= len; 50236413Ssklower /* make a copy - mb goes into the retransmission list 50336413Ssklower * while m gets emitted. m_copy won't copy a zero-length mbuf. 50436413Ssklower */ 50551204Ssklower mb = m; 50650901Ssklower m = m_copy(mb, 0, M_COPYALL); 50750901Ssklower if (m == MNULL) 50851204Ssklower break; 50951204Ssklower IFTRACE(D_STASH) 51036413Ssklower tptraceTPCB( TPPTmisc, 51151204Ssklower "tp_send mcopy nxt high eotsdu len", 51251204Ssklower tpcb->tp_sndnxt, highseq, eotsdu, len); 51336413Ssklower ENDTRACE 51451204Ssklower 51551204Ssklower IFDEBUG(D_DATA) 51651204Ssklower printf("tp_sending tpcb 0x%x nxt 0x%x\n", 51751204Ssklower tpcb, tpcb->tp_sndnxt); 51851204Ssklower ENDDEBUG 51951204Ssklower /* when headers are precomputed, may need to fill 52050901Ssklower in checksum here */ 52150901Ssklower if (tpcb->tp_sock->so_error = 52251204Ssklower tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) { 52336413Ssklower /* error */ 52451204Ssklower break; 52536413Ssklower } 52651204Ssklower m = mb->m_nextpkt; 52751204Ssklower tpcb->tp_sndnxt_m = m; 52851204Ssklower if (tpcb->tp_sndnxt == tpcb->tp_sndnew) { 52951204Ssklower SEQ_INC(tpcb, tpcb->tp_sndnew); 53051204Ssklower /* 53151204Ssklower * Time this transmission if not a retransmission and 53251204Ssklower * not currently timing anything. 53351204Ssklower */ 53451204Ssklower if (tpcb->tp_rttemit == 0) { 53551341Ssklower tpcb->tp_rttemit = ticks; 53651204Ssklower tpcb->tp_rttseq = tpcb->tp_sndnxt; 53751204Ssklower } 53851204Ssklower tpcb->tp_sndnxt = tpcb->tp_sndnew; 53951204Ssklower } else 54051204Ssklower SEQ_INC(tpcb, tpcb->tp_sndnxt); 54151204Ssklower /* 54251204Ssklower * Set retransmit timer if not currently set. 54351204Ssklower * Initial value for retransmit timer is smoothed 54451204Ssklower * round-trip time + 2 * round-trip time variance. 54551204Ssklower * Initialize shift counter which is used for backoff 54651204Ssklower * of retransmit time. 54751204Ssklower */ 54853689Ssklower if (tpcb->tp_timer[TM_data_retrans] == 0 && 54953689Ssklower tpcb->tp_class != TP_CLASS_0) { 55051204Ssklower tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks; 55151204Ssklower tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks; 55251204Ssklower tpcb->tp_rxtshift = 0; 55351138Ssklower } 55436413Ssklower } 55551204Ssklower if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum)) 55651204Ssklower tpcb->tp_oktonagle = 0; 55750236Ssklower #ifdef TP_PERF_MEAS 55836413Ssklower IFPERF(tpcb) 55936413Ssklower { 56036413Ssklower register int npkts; 56151341Ssklower int elapsed = ticks - send_start_time, *t; 56251138Ssklower struct timeval now; 56336413Ssklower 56451204Ssklower npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt); 56536413Ssklower 56651204Ssklower if (npkts > 0) 56736413Ssklower tpcb->tp_Nwindow++; 56836413Ssklower 56936413Ssklower if (npkts > TP_PM_MAX) 57036413Ssklower npkts = TP_PM_MAX; 57136413Ssklower 57236413Ssklower t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); 57351138Ssklower *t += (t - elapsed) >> TP_RTT_ALPHA; 57436413Ssklower 57551204Ssklower if (mb == 0) { 57636413Ssklower IncPStat(tpcb, tps_win_lim_by_data[npkts] ); 57736413Ssklower } else { 57836413Ssklower IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); 57936413Ssklower /* not true with congestion-window being used */ 58036413Ssklower } 58151138Ssklower now.tv_sec = elapsed / hz; 58251138Ssklower now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz; 58336413Ssklower tpmeas( tpcb->tp_lref, 58451204Ssklower TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts); 58536413Ssklower } 58636413Ssklower ENDPERF 58750236Ssklower #endif TP_PERF_MEAS 58836413Ssklower 58936413Ssklower 59036413Ssklower IFTRACE(D_DATA) 59136413Ssklower tptraceTPCB( TPPTmisc, 59251204Ssklower "tp_send at end: new nxt eotsdu error", 59351204Ssklower tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error); 59436413Ssklower 59536413Ssklower ENDTRACE 59636413Ssklower } 59736413Ssklower 59850901Ssklower int TPNagleok; 59950901Ssklower int TPNagled; 60050901Ssklower 60150901Ssklower tp_packetize(tpcb, m, eotsdu) 60250901Ssklower register struct tp_pcb *tpcb; 60350901Ssklower register struct mbuf *m; 60450901Ssklower int eotsdu; 60550901Ssklower { 60650901Ssklower register struct mbuf *n; 60750901Ssklower register struct sockbuf *sb = &tpcb->tp_sock->so_snd; 60850901Ssklower int maxsize = tpcb->tp_l_tpdusize 60950901Ssklower - tp_headersize(DT_TPDU_type, tpcb) 61050901Ssklower - (tpcb->tp_use_checksum?4:0) ; 61150901Ssklower int totlen = m->m_pkthdr.len; 61250901Ssklower struct mbuf *m_split(); 61350901Ssklower /* 61450901Ssklower * Pre-packetize the data in the sockbuf 61550901Ssklower * according to negotiated mtu. Do it here 61650901Ssklower * where we can safely wait for mbufs. 61750901Ssklower * 61850901Ssklower * This presumes knowledge of sockbuf conventions. 61950901Ssklower * TODO: allocate space for header and fill it in (once!). 62050901Ssklower */ 62151204Ssklower IFDEBUG(D_DATA) 62251204Ssklower printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n", 62351204Ssklower maxsize, totlen, eotsdu, tpcb->tp_sndnum); 62450901Ssklower ENDTRACE 62550901Ssklower if (tpcb->tp_oktonagle) { 62650901Ssklower if ((n = sb->sb_mb) == 0) 62750901Ssklower panic("tp_packetize"); 62850901Ssklower while (n->m_act) 62950901Ssklower n = n->m_act; 63050901Ssklower if (n->m_flags & M_EOR) 63150901Ssklower panic("tp_packetize 2"); 63250901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 63350901Ssklower if (totlen + n->m_pkthdr.len < maxsize) { 63450901Ssklower /* There is an unsent packet with space, combine data */ 63550901Ssklower struct mbuf *old_n = n; 63650901Ssklower tpsbcheck(tpcb,3); 63750901Ssklower n->m_pkthdr.len += totlen; 63850901Ssklower while (n->m_next) 63950901Ssklower n = n->m_next; 64050901Ssklower sbcompress(sb, m, n); 64150901Ssklower tpsbcheck(tpcb,4); 64250901Ssklower n = old_n; 64350901Ssklower TPNagled++; 64450901Ssklower goto out; 64550901Ssklower } 64650901Ssklower } 64750901Ssklower while (m) { 64850901Ssklower n = m; 64950901Ssklower if (totlen > maxsize) { 65050901Ssklower if ((m = m_split(n, maxsize, M_WAIT)) == 0) 65150901Ssklower panic("tp_packetize"); 65250901Ssklower } else 65350901Ssklower m = 0; 65450901Ssklower totlen -= maxsize; 65550901Ssklower tpsbcheck(tpcb, 5); 65650901Ssklower sbappendrecord(sb, n); 65750901Ssklower tpsbcheck(tpcb, 6); 65850901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 65950901Ssklower } 66050901Ssklower out: 66150901Ssklower if (eotsdu) { 66250901Ssklower n->m_flags |= M_EOR; /* XXX belongs at end */ 66350901Ssklower tpcb->tp_oktonagle = 0; 66450901Ssklower } else { 66550901Ssklower SEQ_DEC(tpcb, tpcb->tp_sndnum); 66650901Ssklower tpcb->tp_oktonagle = 1; 66750901Ssklower TPNagleok++; 66850901Ssklower } 66951204Ssklower IFDEBUG(D_DATA) 67051204Ssklower printf("SEND out: oktonagle %d sndnum 0x%x\n", 67151204Ssklower tpcb->tp_oktonagle, tpcb->tp_sndnum); 67251204Ssklower ENDTRACE 67350901Ssklower return 0; 67450901Ssklower } 67550901Ssklower 67650901Ssklower 67736413Ssklower /* 67836413Ssklower * NAME: tp_stash() 67936413Ssklower * CALLED FROM: 68036413Ssklower * tp.trans on arrival of a DT tpdu 68136413Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 68236413Ssklower * Returns 1 if 68336413Ssklower * a) something new arrived and it's got eotsdu_reached bit on, 68436413Ssklower * b) this arrival was caused other out-of-sequence things to be 68536413Ssklower * accepted, or 68636413Ssklower * c) this arrival is the highest seq # for which we last gave credit 68736413Ssklower * (sender just sent a whole window) 68836413Ssklower * In other words, returns 1 if tp should send an ack immediately, 0 if 68936413Ssklower * the ack can wait a while. 69036413Ssklower * 69136413Ssklower * Note: this implementation no longer renegs on credit, (except 69236413Ssklower * when debugging option D_RENEG is on, for the purpose of testing 69336413Ssklower * ack subsequencing), so we don't need to check for incoming tpdus 69436413Ssklower * being in a reneged portion of the window. 69536413Ssklower */ 69636413Ssklower 69751204Ssklower tp_stash(tpcb, e) 69836413Ssklower register struct tp_pcb *tpcb; 69936413Ssklower register struct tp_event *e; 70036413Ssklower { 70136413Ssklower register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; 70236413Ssklower /* 0--> delay acks until full window */ 70336413Ssklower /* 1--> ack each tpdu */ 70436413Ssklower #ifndef lint 70536413Ssklower #define E e->ATTR(DT_TPDU) 70636413Ssklower #else lint 70736413Ssklower #define E e->ev_union.EV_DT_TPDU 70836413Ssklower #endif lint 70936413Ssklower 71036413Ssklower if ( E.e_eot ) { 71136413Ssklower register struct mbuf *n = E.e_data; 71237469Ssklower n->m_flags |= M_EOR; 71338841Ssklower n->m_act = 0; 71437469Ssklower } 71536413Ssklower IFDEBUG(D_STASH) 71636413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 71736413Ssklower "stash: so_rcv before appending"); 71836413Ssklower dump_mbuf(E.e_data, 71936413Ssklower "stash: e_data before appending"); 72036413Ssklower ENDDEBUG 72136413Ssklower 72236413Ssklower IFPERF(tpcb) 72336413Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen; 72436413Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 72537469Ssklower E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); 72636413Ssklower ENDPERF 72736413Ssklower 72851024Ssklower if (E.e_seq == tpcb->tp_rcvnxt) { 72936413Ssklower 73036413Ssklower IFDEBUG(D_STASH) 73136413Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", 73236413Ssklower E.e_seq, E.e_datalen, E.e_eot); 73336413Ssklower ENDDEBUG 73436413Ssklower 73536413Ssklower IFTRACE(D_STASH) 73636413Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 73736413Ssklower E.e_seq, E.e_datalen, E.e_eot, 0); 73836413Ssklower ENDTRACE 73936413Ssklower 74051024Ssklower SET_DELACK(tpcb); 74151024Ssklower 74237469Ssklower sbappend(&tpcb->tp_sock->so_rcv, E.e_data); 74337469Ssklower 74436413Ssklower SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 74536413Ssklower /* 74650901Ssklower * move chains from the reassembly queue to the socket buffer 74736413Ssklower */ 74850901Ssklower if (tpcb->tp_rsycnt) { 74950901Ssklower register struct mbuf **mp; 75050901Ssklower struct mbuf **mplim; 75136413Ssklower 75250901Ssklower mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit); 75350901Ssklower mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit; 75436413Ssklower 75550901Ssklower while (tpcb->tp_rsycnt && *mp) { 75650901Ssklower sbappend(&tpcb->tp_sock->so_rcv, *mp); 75750901Ssklower tpcb->tp_rsycnt--; 75850901Ssklower *mp = 0; 75950901Ssklower SEQ_INC(tpcb, tpcb->tp_rcvnxt); 76036413Ssklower ack_reason |= ACK_REORDER; 76150901Ssklower if (++mp == mplim) 76250901Ssklower mp = tpcb->tp_rsyq; 76336413Ssklower } 76436413Ssklower } 76536413Ssklower IFDEBUG(D_STASH) 76636413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 76736413Ssklower "stash: so_rcv after appending"); 76836413Ssklower ENDDEBUG 76936413Ssklower 77036413Ssklower } else { 77150901Ssklower register struct mbuf **mp; 77250901Ssklower SeqNum uwe; 77336413Ssklower 77436413Ssklower IFTRACE(D_STASH) 77536413Ssklower tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", 77636413Ssklower E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); 77736413Ssklower ENDTRACE 77836413Ssklower 77950975Ssklower if (tpcb->tp_rsyq == 0) 78050975Ssklower tp_rsyset(tpcb); 78150901Ssklower uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit); 78250901Ssklower if (tpcb->tp_rsyq == 0 || 78350901Ssklower !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) { 78436413Ssklower ack_reason = ACK_DONT; 78550901Ssklower m_freem(E.e_data); 78650901Ssklower } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) { 78736413Ssklower IFDEBUG(D_STASH) 78836413Ssklower printf("tp_stash - drop & ack\n"); 78936413Ssklower ENDDEBUG 79036413Ssklower 79136413Ssklower /* retransmission - drop it and force an ack */ 79236413Ssklower IncStat(ts_dt_dup); 79336413Ssklower IFPERF(tpcb) 79436413Ssklower IncPStat(tpcb, tps_n_ack_cuz_dup); 79536413Ssklower ENDPERF 79636413Ssklower 79750901Ssklower m_freem(E.e_data); 79836413Ssklower ack_reason |= ACK_DUP; 79950901Ssklower } else { 80050901Ssklower *mp = E.e_data; 80150901Ssklower tpcb->tp_rsycnt++; 80250901Ssklower ack_reason = ACK_DONT; 80336413Ssklower } 80436413Ssklower } 80551024Ssklower /* there were some comments of historical interest here. */ 80636413Ssklower { 80736413Ssklower LOCAL_CREDIT(tpcb); 80836413Ssklower 80936413Ssklower if ( E.e_seq == tpcb->tp_sent_uwe ) 81036413Ssklower ack_reason |= ACK_STRAT_FULLWIN; 81136413Ssklower 81236413Ssklower IFTRACE(D_STASH) 81336413Ssklower tptraceTPCB(TPPTmisc, 81436413Ssklower "end of stash, eot, ack_reason, sent_uwe ", 81536413Ssklower E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); 81636413Ssklower ENDTRACE 81736413Ssklower 81836413Ssklower if ( ack_reason == ACK_DONT ) { 81936413Ssklower IncStat( ts_ackreason[ACK_DONT] ); 82036413Ssklower return 0; 82136413Ssklower } else { 82236413Ssklower IFPERF(tpcb) 82336413Ssklower if(ack_reason & ACK_STRAT_EACH) { 82436413Ssklower IncPStat(tpcb, tps_n_ack_cuz_strat); 82536413Ssklower } else if(ack_reason & ACK_STRAT_FULLWIN) { 82636413Ssklower IncPStat(tpcb, tps_n_ack_cuz_fullwin); 82736413Ssklower } else if(ack_reason & ACK_REORDER) { 82836413Ssklower IncPStat(tpcb, tps_n_ack_cuz_reorder); 82936413Ssklower } 83036413Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, 83136413Ssklower SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); 83236413Ssklower ENDPERF 83336413Ssklower { 83436413Ssklower register int i; 83536413Ssklower 83636413Ssklower /* keep track of all reasons that apply */ 83736413Ssklower for( i=1; i<_ACK_NUM_REASONS_ ;i++) { 83836413Ssklower if( ack_reason & (1<<i) ) 83936413Ssklower IncStat( ts_ackreason[i] ); 84036413Ssklower } 84136413Ssklower } 84236413Ssklower return 1; 84336413Ssklower } 84436413Ssklower } 84536413Ssklower } 84650901Ssklower 84750901Ssklower /* 84850901Ssklower * tp_rsyflush - drop all the packets on the reassembly queue. 84950901Ssklower * Do this when closing the socket, or when somebody has changed 85050901Ssklower * the space avaible in the receive socket (XXX). 85150901Ssklower */ 85250901Ssklower tp_rsyflush(tpcb) 85350901Ssklower register struct tp_pcb *tpcb; 85450901Ssklower { 85550901Ssklower register struct mbuf *m, **mp; 85650901Ssklower if (tpcb->tp_rsycnt) { 85750901Ssklower for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit; 85850901Ssklower --mp >= tpcb->tp_rsyq; ) 85950901Ssklower if (*mp) { 86050901Ssklower tpcb->tp_rsycnt--; 86150901Ssklower m_freem(*mp); 86250901Ssklower } 86353689Ssklower if (tpcb->tp_rsycnt) { 86453689Ssklower printf("tp_rsyflush %x\n", tpcb); 86553689Ssklower tpcb->tp_rsycnt = 0; 86653689Ssklower } 86750901Ssklower } 86850901Ssklower free((caddr_t)tpcb->tp_rsyq, M_PCB); 86950901Ssklower tpcb->tp_rsyq = 0; 87050901Ssklower } 87150901Ssklower 87250901Ssklower tp_rsyset(tpcb) 87350901Ssklower register struct tp_pcb *tpcb; 87450901Ssklower { 87550901Ssklower register struct socket *so = tpcb->tp_sock; 87650901Ssklower int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf; 87750975Ssklower int old_credit = tpcb->tp_maxlcredit; 87850975Ssklower caddr_t rsyq; 87950901Ssklower 88050901Ssklower tpcb->tp_maxlcredit = maxcredit = min(maxcredit, 88150901Ssklower (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize); 88250901Ssklower 88350975Ssklower if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0) 88450975Ssklower return; 88550901Ssklower maxcredit *= sizeof(struct mbuf *); 88650901Ssklower if (tpcb->tp_rsyq) 88750901Ssklower tp_rsyflush(tpcb); 88850901Ssklower if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT)) 88950901Ssklower bzero(rsyq, maxcredit); 89050901Ssklower tpcb->tp_rsyq = (struct mbuf **)rsyq; 89150901Ssklower } 89250901Ssklower 89350901Ssklower tpsbcheck(tpcb, i) 89450901Ssklower struct tp_pcb *tpcb; 89550901Ssklower { 89650901Ssklower register struct mbuf *n, *m; 89750901Ssklower register int len = 0, mbcnt = 0, pktlen; 89850901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 89950901Ssklower 90050901Ssklower for (n = sb->sb_mb; n; n = n->m_nextpkt) { 90150901Ssklower if ((n->m_flags & M_PKTHDR) == 0) 90250901Ssklower panic("tpsbcheck nohdr"); 90350901Ssklower pktlen = len + n->m_pkthdr.len; 90450901Ssklower for (m = n; m; m = m->m_next) { 90550901Ssklower len += m->m_len; 90650901Ssklower mbcnt += MSIZE; 90750901Ssklower if (m->m_flags & M_EXT) 90850901Ssklower mbcnt += m->m_ext.ext_size; 90950901Ssklower } 91050901Ssklower if (len != pktlen) { 91150901Ssklower printf("test %d; len %d != pktlen %d on mbuf 0x%x\n", 91250901Ssklower i, len, pktlen, n); 91350901Ssklower panic("tpsbcheck short"); 91450901Ssklower } 91550901Ssklower } 91650901Ssklower if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { 91750901Ssklower printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc, 91850901Ssklower mbcnt, sb->sb_mbcnt); 91950901Ssklower panic("tpsbcheck"); 92050901Ssklower } 92150901Ssklower } 922