149268Sbostic /*-
2*63222Sbostic * Copyright (c) 1991, 1993
3*63222Sbostic * The Regents of the University of California. All rights reserved.
449268Sbostic *
549268Sbostic * %sccs.include.redist.c%
649268Sbostic *
7*63222Sbostic * @(#)tp_subr.c 8.1 (Berkeley) 06/10/93
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
5156533Sbostic #include <sys/param.h>
5256533Sbostic #include <sys/systm.h>
5356533Sbostic #include <sys/mbuf.h>
5456533Sbostic #include <sys/socket.h>
5556533Sbostic #include <sys/socketvar.h>
5656533Sbostic #include <sys/protosw.h>
5756533Sbostic #include <sys/errno.h>
5856533Sbostic #include <sys/time.h>
5956533Sbostic #include <sys/kernel.h>
6036413Ssklower
6156533Sbostic #include <netiso/tp_ip.h>
6256533Sbostic #include <netiso/iso.h>
6356533Sbostic #include <netiso/argo_debug.h>
6456533Sbostic #include <netiso/tp_timer.h>
6556533Sbostic #include <netiso/tp_param.h>
6656533Sbostic #include <netiso/tp_stat.h>
6756533Sbostic #include <netiso/tp_pcb.h>
6856533Sbostic #include <netiso/tp_tpdu.h>
6956533Sbostic #include <netiso/tp_trace.h>
7056533Sbostic #include <netiso/tp_meas.h>
7156533Sbostic #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
tp_goodXack(tpcb,seq)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
tp_rtt_rtv(tpcb)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
tp_goodack(tpcb,cdt,seq,subseq)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 */
tp_sbdrop(tpcb,seq)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
tp_send(tpcb)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;
44560359Sbostic #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
58760359Sbostic #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
tp_packetize(tpcb,m,eotsdu)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
tp_stash(tpcb,e)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)
70660359Sbostic #else /* lint */
70736413Ssklower #define E e->ev_union.EV_DT_TPDU
70860359Sbostic #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 */
tp_rsyflush(tpcb)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
tp_rsyset(tpcb)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