diff options
Diffstat (limited to 'sys/netiso/tp_subr.c')
| -rw-r--r-- | sys/netiso/tp_subr.c | 949 |
1 files changed, 0 insertions, 949 deletions
diff --git a/sys/netiso/tp_subr.c b/sys/netiso/tp_subr.c deleted file mode 100644 index 6125a0a60747..000000000000 --- a/sys/netiso/tp_subr.c +++ /dev/null @@ -1,949 +0,0 @@ -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)tp_subr.c 8.1 (Berkeley) 6/10/93 - * $Id: tp_subr.c,v 1.3 1995/04/26 21:32:40 pst Exp $ - */ - -/*********************************************************** - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ -/* - * ARGO TP - * - * $Header: /home/ncvs/src/sys/netiso/tp_subr.c,v 1.3 1995/04/26 21:32:40 pst Exp $ - * $Source: /home/ncvs/src/sys/netiso/tp_subr.c,v $ - * - * The main work of data transfer is done here. - * These routines are called from tp.trans. - * They include the routines that check the validity of acks and Xacks, - * (tp_goodack() and tp_goodXack() ) - * take packets from socket buffers and send them (tp_send()), - * drop the data from the socket buffers (tp_sbdrop()), - * and put incoming packet data into socket buffers (tp_stash()). - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/mbuf.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/protosw.h> -#include <sys/errno.h> -#include <sys/time.h> -#include <sys/kernel.h> -#include <sys/queue.h> - -#include <netiso/tp_ip.h> -#include <netiso/iso.h> -#include <netiso/argo_debug.h> -#include <netiso/tp_timer.h> -#include <netiso/tp_param.h> -#include <netiso/tp_stat.h> -#include <netiso/tp_pcb.h> -#include <netiso/tp_tpdu.h> -#include <netiso/tp_trace.h> -#include <netiso/tp_meas.h> -#include <netiso/tp_seq.h> - -int tp_emit(), tp_sbdrop(); -int tprexmtthresh = 3; -extern int ticks; -void tp_send(); - -/* - * CALLED FROM: - * tp.trans, when an XAK arrives - * FUNCTION and ARGUMENTS: - * Determines if the sequence number (seq) from the XAK - * acks anything new. If so, drop the appropriate tpdu - * from the XPD send queue. - * RETURN VALUE: - * Returns 1 if it did this, 0 if the ack caused no action. - */ -int -tp_goodXack(tpcb, seq) - struct tp_pcb *tpcb; - SeqNum seq; -{ - - IFTRACE(D_XPD) - tptraceTPCB(TPPTgotXack, - seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndnew, - tpcb->tp_snduna); - ENDTRACE - - if ( seq == tpcb->tp_Xuna ) { - tpcb->tp_Xuna = tpcb->tp_Xsndnxt; - - /* DROP 1 packet from the Xsnd socket buf - just so happens - * that only one packet can be there at any time - * so drop the whole thing. If you allow > 1 packet - * the socket buffer, then you'll have to keep - * track of how many characters went w/ each XPD tpdu, so this - * will get messier - */ - IFDEBUG(D_XPD) - dump_mbuf(tpcb->tp_Xsnd.sb_mb, - "tp_goodXack Xsnd before sbdrop"); - ENDDEBUG - - IFTRACE(D_XPD) - tptraceTPCB(TPPTmisc, - "goodXack: dropping cc ", - (int)(tpcb->tp_Xsnd.sb_cc), - 0,0,0); - ENDTRACE - sbdroprecord(&tpcb->tp_Xsnd); - return 1; - } - return 0; -} - -/* - * CALLED FROM: - * tp_good_ack() - * FUNCTION and ARGUMENTS: - * updates - * smoothed average round trip time (*rtt) - * roundtrip time variance (*rtv) - actually deviation, not variance - * given the new value (diff) - * RETURN VALUE: - * void - */ - -void -tp_rtt_rtv(tpcb) -register struct tp_pcb *tpcb; -{ - int old = tpcb->tp_rtt; - int delta, elapsed = ticks - tpcb->tp_rttemit; - - if (tpcb->tp_rtt != 0) { - /* - * rtt is the smoothed round trip time in machine clock ticks (hz). - * It is stored as a fixed point number, unscaled (unlike the tcp - * srtt). The rationale here is that it is only significant to the - * nearest unit of slowtimo, which is at least 8 machine clock ticks - * so there is no need to scale. The smoothing is done according - * to the same formula as TCP (rtt = rtt*7/8 + measured_rtt/8). - */ - delta = elapsed - tpcb->tp_rtt; - if ((tpcb->tp_rtt += (delta >> TP_RTT_ALPHA)) <= 0) - tpcb->tp_rtt = 1; - /* - * rtv is a smoothed accumulated mean difference, unscaled - * for reasons expressed above. - * It is smoothed with an alpha of .75, and the round trip timer - * will be set to rtt + 4*rtv, also as TCP does. - */ - if (delta < 0) - delta = -delta; - if ((tpcb->tp_rtv += ((delta - tpcb->tp_rtv) >> TP_RTV_ALPHA)) <= 0) - tpcb->tp_rtv = 1; - } else { - /* - * No rtt measurement yet - use the unsmoothed rtt. - * Set the variance to half the rtt (so our first - * retransmit happens at 3*rtt) - */ - tpcb->tp_rtt = elapsed; - tpcb->tp_rtv = elapsed >> 1; - } - tpcb->tp_rttemit = 0; - tpcb->tp_rxtshift = 0; - /* - * Quoting TCP: "the retransmit should happen at rtt + 4 * rttvar. - * Because of the way we do the smoothing, srtt and rttvar - * will each average +1/2 tick of bias. When we compute - * the retransmit timer, we want 1/2 tick of rounding and - * 1 extra tick because of +-1/2 tick uncertainty in the - * firing of the timer. The bias will give us exactly the - * 1.5 tick we need. But, because the bias is - * statistical, we have to test that we don't drop below - * the minimum feasible timer (which is 2 ticks)." - */ - TP_RANGESET(tpcb->tp_dt_ticks, TP_REXMTVAL(tpcb), - tpcb->tp_peer_acktime, 128 /* XXX */); - IFDEBUG(D_RTT) - printf("%s tpcb 0x%x, elapsed %d, delta %d, rtt %d, rtv %d, old %d\n", - "tp_rtt_rtv:",tpcb,elapsed,delta,tpcb->tp_rtt,tpcb->tp_rtv,old); - ENDDEBUG - tpcb->tp_rxtcur = tpcb->tp_dt_ticks; -} - -/* - * CALLED FROM: - * tp.trans when an AK arrives - * FUNCTION and ARGUMENTS: - * Given (cdt), the credit from the AK tpdu, and - * (seq), the sequence number from the AK tpdu, - * tp_goodack() determines if the AK acknowledges something in the send - * window, and if so, drops the appropriate packets from the retransmission - * list, computes the round trip time, and updates the retransmission timer - * based on the new smoothed round trip time. - * RETURN VALUE: - * Returns 1 if - * EITHER it actually acked something heretofore unacknowledged - * OR no news but the credit should be processed. - * If something heretofore unacked was acked with this sequence number, - * the appropriate tpdus are dropped from the retransmission control list, - * by calling tp_sbdrop(). - * No need to see the tpdu itself. - */ -int -tp_goodack(tpcb, cdt, seq, subseq) - register struct tp_pcb *tpcb; - u_int cdt; - register SeqNum seq; - u_int subseq; -{ - int old_fcredit; - int bang = 0; /* bang --> ack for something heretofore unacked */ - u_int bytes_acked; - - IFDEBUG(D_ACKRECV) - printf("goodack tpcb 0x%x seq 0x%x cdt %d una 0x%x new 0x%x nxt 0x%x\n", - tpcb, seq, cdt, tpcb->tp_snduna, tpcb->tp_sndnew, tpcb->tp_sndnxt); - ENDDEBUG - IFTRACE(D_ACKRECV) - tptraceTPCB(TPPTgotack, - seq,cdt, tpcb->tp_snduna,tpcb->tp_sndnew,subseq); - ENDTRACE - - IFPERF(tpcb) - tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0); - ENDPERF - - if (seq == tpcb->tp_snduna) { - if (subseq < tpcb->tp_r_subseq || - (subseq == tpcb->tp_r_subseq && cdt <= tpcb->tp_fcredit)) { - discard_the_ack: - IFDEBUG(D_ACKRECV) - printf("goodack discard : tpcb 0x%x subseq %d r_subseq %d\n", - tpcb, subseq, tpcb->tp_r_subseq); - ENDDEBUG - goto done; - } - if (cdt == tpcb->tp_fcredit /*&& thus subseq > tpcb->tp_r_subseq */) { - tpcb->tp_r_subseq = subseq; - if (tpcb->tp_timer[TM_data_retrans] == 0) - tpcb->tp_dupacks = 0; - else if (++tpcb->tp_dupacks == tprexmtthresh) { - /* partner went out of his way to signal with different - subsequences that he has the same lack of an expected - packet. This may be an early indiciation of a loss */ - - SeqNum onxt = tpcb->tp_sndnxt; - struct mbuf *onxt_m = tpcb->tp_sndnxt_m; - u_int win = min(tpcb->tp_fcredit, - tpcb->tp_cong_win / tpcb->tp_l_tpdusize) / 2; - IFDEBUG(D_ACKRECV) - printf("%s tpcb 0x%x seq 0x%x rttseq 0x%x onxt 0x%x\n", - "goodack dupacks:", tpcb, seq, tpcb->tp_rttseq, onxt); - ENDDEBUG - if (win < 2) - win = 2; - tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize; - tpcb->tp_timer[TM_data_retrans] = 0; - tpcb->tp_rttemit = 0; - tpcb->tp_sndnxt = tpcb->tp_snduna; - tpcb->tp_sndnxt_m = 0; - tpcb->tp_cong_win = tpcb->tp_l_tpdusize; - tp_send(tpcb); - tpcb->tp_cong_win = tpcb->tp_ssthresh + - tpcb->tp_dupacks * tpcb->tp_l_tpdusize; - if (SEQ_GT(tpcb, onxt, tpcb->tp_sndnxt)) { - tpcb->tp_sndnxt = onxt; - tpcb->tp_sndnxt_m = onxt_m; - } - - } else if (tpcb->tp_dupacks > tprexmtthresh) { - tpcb->tp_cong_win += tpcb->tp_l_tpdusize; - } - goto done; - } - } else if (SEQ_LT(tpcb, seq, tpcb->tp_snduna)) - goto discard_the_ack; - /* - * If the congestion window was inflated to account - * for the other side's cached packets, retract it. - */ - if (tpcb->tp_dupacks > tprexmtthresh && - tpcb->tp_cong_win > tpcb->tp_ssthresh) - tpcb->tp_cong_win = tpcb->tp_ssthresh; - tpcb->tp_r_subseq = subseq; - old_fcredit = tpcb->tp_fcredit; - tpcb->tp_fcredit = cdt; - if (cdt > tpcb->tp_maxfcredit) - tpcb->tp_maxfcredit = cdt; - tpcb->tp_dupacks = 0; - - if (IN_SWINDOW(tpcb, seq, tpcb->tp_snduna, tpcb->tp_sndnew)) { - - tpsbcheck(tpcb, 0); - bytes_acked = tp_sbdrop(tpcb, seq); - tpsbcheck(tpcb, 1); - /* - * If transmit timer is running and timed sequence - * number was acked, update smoothed round trip time. - * Since we now have an rtt measurement, cancel the - * timer backoff (cf., Phil Karn's retransmit alg.). - * Recompute the initial retransmit timer. - */ - if (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq)) - tp_rtt_rtv(tpcb); - /* - * If all outstanding data is acked, stop retransmit timer. - * If there is more data to be acked, restart retransmit - * timer, using current (possibly backed-off) value. - * OSI combines the keepalive and persistance functions. - * So, there is no persistance timer per se, to restart. - */ - if (tpcb->tp_class != TP_CLASS_0) - tpcb->tp_timer[TM_data_retrans] = - (seq == tpcb->tp_sndnew) ? 0 : tpcb->tp_rxtcur; - /* - * When new data is acked, open the congestion window. - * If the window gives us less than ssthresh packets - * in flight, open exponentially (maxseg per packet). - * Otherwise open linearly: maxseg per window - * (maxseg^2 / cwnd per packet), plus a constant - * fraction of a packet (maxseg/8) to help larger windows - * open quickly enough. - */ - { - u_int cw = tpcb->tp_cong_win, incr = tpcb->tp_l_tpdusize; - - incr = min(incr, bytes_acked); - if (cw > tpcb->tp_ssthresh) - incr = incr * incr / cw + incr / 8; - tpcb->tp_cong_win = - min(cw + incr, tpcb->tp_sock->so_snd.sb_hiwat); - } - tpcb->tp_snduna = seq; - if (SEQ_LT(tpcb, tpcb->tp_sndnxt, seq)) { - tpcb->tp_sndnxt = seq; - tpcb->tp_sndnxt_m = 0; - } - bang++; - } - - if( cdt != 0 && old_fcredit == 0 ) { - tpcb->tp_sendfcc = 1; - } - if (cdt == 0) { - if (old_fcredit != 0) - IncStat(ts_zfcdt); - /* The following might mean that the window shrunk */ - if (tpcb->tp_timer[TM_data_retrans]) { - tpcb->tp_timer[TM_data_retrans] = 0; - tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks; - if (tpcb->tp_sndnxt != tpcb->tp_snduna) { - tpcb->tp_sndnxt = tpcb->tp_snduna; - tpcb->tp_sndnxt_m = 0; - } - } - } - tpcb->tp_fcredit = cdt; - bang |= (old_fcredit < cdt); - -done: - IFDEBUG(D_ACKRECV) - printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n", - bang, cdt, old_fcredit, tpcb->tp_cong_win); - ENDDEBUG - /* if (bang) XXXXX Very bad to remove this test, but somethings broken */ - tp_send(tpcb); - return (bang); -} - -/* - * CALLED FROM: - * tp_goodack() - * FUNCTION and ARGUMENTS: - * drops everything up TO but not INCLUDING seq # (seq) - * from the retransmission queue. - */ -tp_sbdrop(tpcb, seq) - register struct tp_pcb *tpcb; - SeqNum seq; -{ - struct sockbuf *sb = &tpcb->tp_sock->so_snd; - register int i = SEQ_SUB(tpcb, seq, tpcb->tp_snduna); - int oldcc = sb->sb_cc, oldi = i; - - if (i >= tpcb->tp_seqhalf) - printf("tp_spdropping too much -- should panic"); - while (i-- > 0) - sbdroprecord(sb); - IFDEBUG(D_ACKRECV) - printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n", - oldi, oldcc - sb->sb_cc, tpcb, seq); - ENDDEBUG - if (sb->sb_flags & SB_NOTIFY) - sowwakeup(tpcb->tp_sock); - return (oldcc - sb->sb_cc); -} - -/* - * CALLED FROM: - * tp.trans on user send request, arrival of AK and arrival of XAK - * FUNCTION and ARGUMENTS: - * Emits tpdus starting at sequence number (tpcb->tp_sndnxt). - * Emits until a) runs out of data, or b) runs into an XPD mark, or - * c) it hits seq number (highseq) limited by cong or credit. - * - * If you want XPD to buffer > 1 du per socket buffer, you can - * modifiy this to issue XPD tpdus also, but then it'll have - * to take some argument(s) to distinguish between the type of DU to - * hand tp_emit. - * - * When something is sent for the first time, its time-of-send - * is stashed (in system clock ticks rather than pf_slowtimo ticks). - * When the ack arrives, the smoothed round-trip time is figured - * using this value. - */ -void -tp_send(tpcb) - register struct tp_pcb *tpcb; -{ - register int len; - register struct mbuf *m; - struct mbuf *mb = 0; - struct sockbuf *sb = &tpcb->tp_sock->so_snd; - unsigned int eotsdu = 0; - SeqNum highseq, checkseq; - int idle, idleticks, off, cong_win; -#ifdef TP_PERF_MEAS - int send_start_time = ticks; - SeqNum oldnxt = tpcb->tp_sndnxt; -#endif /* TP_PERF_MEAS */ - - idle = (tpcb->tp_snduna == tpcb->tp_sndnew); - if (idle) { - idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact]; - if (idleticks > tpcb->tp_dt_ticks) - /* - * We have been idle for "a while" and no acks are - * expected to clock out any data we send -- - * slow start to get ack "clock" running again. - */ - tpcb->tp_cong_win = tpcb->tp_l_tpdusize; - } - - cong_win = tpcb->tp_cong_win; - highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna); - if (tpcb->tp_Xsnd.sb_mb) - highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew); - - IFDEBUG(D_DATA) - printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n", - tpcb, tpcb->tp_sndnxt, cong_win, highseq); - ENDDEBUG - IFTRACE(D_DATA) - tptraceTPCB( TPPTmisc, "tp_send sndnew snduna", - tpcb->tp_sndnew, tpcb->tp_snduna, 0, 0); - tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin", - tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win); - ENDTRACE - IFTRACE(D_DATA) - tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin", - tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win); - ENDTRACE - - if (tpcb->tp_sndnxt_m) - m = tpcb->tp_sndnxt_m; - else { - off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna); - for (m = sb->sb_mb; m && off > 0; m = m->m_next) - off--; - } -send: - /* - * Avoid silly window syndrome here . . . figure out how! - */ - checkseq = tpcb->tp_sndnum; - if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq)) - checkseq = highseq; /* i.e. DON'T retain highest assigned packet */ - - while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) { - - eotsdu = (m->m_flags & M_EOR) != 0; - len = m->m_pkthdr.len; - if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 && - len < (tpcb->tp_l_tpdusize / 2)) - break; /* Nagle . . . . . */ - cong_win -= len; - /* make a copy - mb goes into the retransmission list - * while m gets emitted. m_copy won't copy a zero-length mbuf. - */ - mb = m; - m = m_copy(mb, 0, M_COPYALL); - if (m == MNULL) - break; - IFTRACE(D_STASH) - tptraceTPCB( TPPTmisc, - "tp_send mcopy nxt high eotsdu len", - tpcb->tp_sndnxt, highseq, eotsdu, len); - ENDTRACE - - IFDEBUG(D_DATA) - printf("tp_sending tpcb 0x%x nxt 0x%x\n", - tpcb, tpcb->tp_sndnxt); - ENDDEBUG - /* when headers are precomputed, may need to fill - in checksum here */ - if (tpcb->tp_sock->so_error = - tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) { - /* error */ - break; - } - m = mb->m_nextpkt; - tpcb->tp_sndnxt_m = m; - if (tpcb->tp_sndnxt == tpcb->tp_sndnew) { - SEQ_INC(tpcb, tpcb->tp_sndnew); - /* - * Time this transmission if not a retransmission and - * not currently timing anything. - */ - if (tpcb->tp_rttemit == 0) { - tpcb->tp_rttemit = ticks; - tpcb->tp_rttseq = tpcb->tp_sndnxt; - } - tpcb->tp_sndnxt = tpcb->tp_sndnew; - } else - SEQ_INC(tpcb, tpcb->tp_sndnxt); - /* - * Set retransmit timer if not currently set. - * Initial value for retransmit timer is smoothed - * round-trip time + 2 * round-trip time variance. - * Initialize shift counter which is used for backoff - * of retransmit time. - */ - if (tpcb->tp_timer[TM_data_retrans] == 0 && - tpcb->tp_class != TP_CLASS_0) { - tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks; - tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks; - tpcb->tp_rxtshift = 0; - } - } - if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum)) - tpcb->tp_oktonagle = 0; -#ifdef TP_PERF_MEAS - IFPERF(tpcb) - { - register int npkts; - int elapsed = ticks - send_start_time, *t; - struct timeval now; - - npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt); - - if (npkts > 0) - tpcb->tp_Nwindow++; - - if (npkts > TP_PM_MAX) - npkts = TP_PM_MAX; - - t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); - *t += (t - elapsed) >> TP_RTT_ALPHA; - - if (mb == 0) { - IncPStat(tpcb, tps_win_lim_by_data[npkts] ); - } else { - IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); - /* not true with congestion-window being used */ - } - now.tv_sec = elapsed / hz; - now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz; - tpmeas( tpcb->tp_lref, - TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts); - } - ENDPERF -#endif /* TP_PERF_MEAS */ - - - IFTRACE(D_DATA) - tptraceTPCB( TPPTmisc, - "tp_send at end: new nxt eotsdu error", - tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error); - - ENDTRACE -} - -int TPNagleok; -int TPNagled; - -tp_packetize(tpcb, m, eotsdu) -register struct tp_pcb *tpcb; -register struct mbuf *m; -int eotsdu; -{ - register struct mbuf *n; - register struct sockbuf *sb = &tpcb->tp_sock->so_snd; - int maxsize = tpcb->tp_l_tpdusize - - tp_headersize(DT_TPDU_type, tpcb) - - (tpcb->tp_use_checksum?4:0) ; - int totlen = m->m_pkthdr.len; - struct mbuf *m_split(); - /* - * Pre-packetize the data in the sockbuf - * according to negotiated mtu. Do it here - * where we can safely wait for mbufs. - * - * This presumes knowledge of sockbuf conventions. - * TODO: allocate space for header and fill it in (once!). - */ - IFDEBUG(D_DATA) - printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n", - maxsize, totlen, eotsdu, tpcb->tp_sndnum); - ENDTRACE - if (tpcb->tp_oktonagle) { - if ((n = sb->sb_mb) == 0) - panic("tp_packetize"); - while (n->m_act) - n = n->m_act; - if (n->m_flags & M_EOR) - panic("tp_packetize 2"); - SEQ_INC(tpcb, tpcb->tp_sndnum); - if (totlen + n->m_pkthdr.len < maxsize) { - /* There is an unsent packet with space, combine data */ - struct mbuf *old_n = n; - tpsbcheck(tpcb,3); - n->m_pkthdr.len += totlen; - while (n->m_next) - n = n->m_next; - sbcompress(sb, m, n); - tpsbcheck(tpcb,4); - n = old_n; - TPNagled++; - goto out; - } - } - while (m) { - n = m; - if (totlen > maxsize) { - if ((m = m_split(n, maxsize, M_WAIT)) == 0) - panic("tp_packetize"); - } else - m = 0; - totlen -= maxsize; - tpsbcheck(tpcb, 5); - sbappendrecord(sb, n); - tpsbcheck(tpcb, 6); - SEQ_INC(tpcb, tpcb->tp_sndnum); - } -out: - if (eotsdu) { - n->m_flags |= M_EOR; /* XXX belongs at end */ - tpcb->tp_oktonagle = 0; - } else { - SEQ_DEC(tpcb, tpcb->tp_sndnum); - tpcb->tp_oktonagle = 1; - TPNagleok++; - } - IFDEBUG(D_DATA) - printf("SEND out: oktonagle %d sndnum 0x%x\n", - tpcb->tp_oktonagle, tpcb->tp_sndnum); - ENDTRACE - return 0; -} - - -/* - * NAME: tp_stash() - * CALLED FROM: - * tp.trans on arrival of a DT tpdu - * FUNCTION, ARGUMENTS, and RETURN VALUE: - * Returns 1 if - * a) something new arrived and it's got eotsdu_reached bit on, - * b) this arrival was caused other out-of-sequence things to be - * accepted, or - * c) this arrival is the highest seq # for which we last gave credit - * (sender just sent a whole window) - * In other words, returns 1 if tp should send an ack immediately, 0 if - * the ack can wait a while. - * - * Note: this implementation no longer renegs on credit, (except - * when debugging option D_RENEG is on, for the purpose of testing - * ack subsequencing), so we don't need to check for incoming tpdus - * being in a reneged portion of the window. - */ - -tp_stash(tpcb, e) - register struct tp_pcb *tpcb; - register struct tp_event *e; -{ - register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; - /* 0--> delay acks until full window */ - /* 1--> ack each tpdu */ -#ifndef lint -#define E e->ATTR(DT_TPDU) -#else /* lint */ -#define E e->ev_union.EV_DT_TPDU -#endif /* lint */ - - if ( E.e_eot ) { - register struct mbuf *n = E.e_data; - n->m_flags |= M_EOR; - n->m_act = 0; - } - IFDEBUG(D_STASH) - dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, - "stash: so_rcv before appending"); - dump_mbuf(E.e_data, - "stash: e_data before appending"); - ENDDEBUG - - IFPERF(tpcb) - PStat(tpcb, Nb_from_ll) += E.e_datalen; - tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, - E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); - ENDPERF - - if (E.e_seq == tpcb->tp_rcvnxt) { - - IFDEBUG(D_STASH) - printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", - E.e_seq, E.e_datalen, E.e_eot); - ENDDEBUG - - IFTRACE(D_STASH) - tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", - E.e_seq, E.e_datalen, E.e_eot, 0); - ENDTRACE - - SET_DELACK(tpcb); - - sbappend(&tpcb->tp_sock->so_rcv, E.e_data); - - SEQ_INC( tpcb, tpcb->tp_rcvnxt ); - /* - * move chains from the reassembly queue to the socket buffer - */ - if (tpcb->tp_rsycnt) { - register struct mbuf **mp; - struct mbuf **mplim; - - mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit); - mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit; - - while (tpcb->tp_rsycnt && *mp) { - sbappend(&tpcb->tp_sock->so_rcv, *mp); - tpcb->tp_rsycnt--; - *mp = 0; - SEQ_INC(tpcb, tpcb->tp_rcvnxt); - ack_reason |= ACK_REORDER; - if (++mp == mplim) - mp = tpcb->tp_rsyq; - } - } - IFDEBUG(D_STASH) - dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, - "stash: so_rcv after appending"); - ENDDEBUG - - } else { - register struct mbuf **mp; - SeqNum uwe; - - IFTRACE(D_STASH) - tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", - E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); - ENDTRACE - - if (tpcb->tp_rsyq == 0) - tp_rsyset(tpcb); - uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit); - if (tpcb->tp_rsyq == 0 || - !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) { - ack_reason = ACK_DONT; - m_freem(E.e_data); - } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) { - IFDEBUG(D_STASH) - printf("tp_stash - drop & ack\n"); - ENDDEBUG - - /* retransmission - drop it and force an ack */ - IncStat(ts_dt_dup); - IFPERF(tpcb) - IncPStat(tpcb, tps_n_ack_cuz_dup); - ENDPERF - - m_freem(E.e_data); - ack_reason |= ACK_DUP; - } else { - *mp = E.e_data; - tpcb->tp_rsycnt++; - ack_reason = ACK_DONT; - } - } - /* there were some comments of historical interest here. */ - { - LOCAL_CREDIT(tpcb); - - if ( E.e_seq == tpcb->tp_sent_uwe ) - ack_reason |= ACK_STRAT_FULLWIN; - - IFTRACE(D_STASH) - tptraceTPCB(TPPTmisc, - "end of stash, eot, ack_reason, sent_uwe ", - E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); - ENDTRACE - - if ( ack_reason == ACK_DONT ) { - IncStat( ts_ackreason[ACK_DONT] ); - return 0; - } else { - IFPERF(tpcb) - if(ack_reason & ACK_STRAT_EACH) { - IncPStat(tpcb, tps_n_ack_cuz_strat); - } else if(ack_reason & ACK_STRAT_FULLWIN) { - IncPStat(tpcb, tps_n_ack_cuz_fullwin); - } else if(ack_reason & ACK_REORDER) { - IncPStat(tpcb, tps_n_ack_cuz_reorder); - } - tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, - SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); - ENDPERF - { - register int i; - - /* keep track of all reasons that apply */ - for( i=1; i<_ACK_NUM_REASONS_ ;i++) { - if( ack_reason & (1<<i) ) - IncStat( ts_ackreason[i] ); - } - } - return 1; - } - } -} - -/* - * tp_rsyflush - drop all the packets on the reassembly queue. - * Do this when closing the socket, or when somebody has changed - * the space avaible in the receive socket (XXX). - */ -tp_rsyflush(tpcb) -register struct tp_pcb *tpcb; -{ - register struct mbuf *m, **mp; - if (tpcb->tp_rsycnt) { - for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit; - --mp >= tpcb->tp_rsyq; ) - if (*mp) { - tpcb->tp_rsycnt--; - m_freem(*mp); - } - if (tpcb->tp_rsycnt) { - printf("tp_rsyflush %x\n", tpcb); - tpcb->tp_rsycnt = 0; - } - } - free((caddr_t)tpcb->tp_rsyq, M_PCB); - tpcb->tp_rsyq = 0; -} - -tp_rsyset(tpcb) -register struct tp_pcb *tpcb; -{ - register struct socket *so = tpcb->tp_sock; - int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf; - int old_credit = tpcb->tp_maxlcredit; - caddr_t rsyq; - - tpcb->tp_maxlcredit = maxcredit = min(maxcredit, - (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize); - - if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0) - return; - maxcredit *= sizeof(struct mbuf *); - if (tpcb->tp_rsyq) - tp_rsyflush(tpcb); - if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT)) - bzero(rsyq, maxcredit); - tpcb->tp_rsyq = (struct mbuf **)rsyq; -} - -tpsbcheck(tpcb, i) -struct tp_pcb *tpcb; -{ - register struct mbuf *n, *m; - register int len = 0, mbcnt = 0, pktlen; - struct sockbuf *sb = &tpcb->tp_sock->so_snd; - - for (n = sb->sb_mb; n; n = n->m_nextpkt) { - if ((n->m_flags & M_PKTHDR) == 0) - panic("tpsbcheck nohdr"); - pktlen = len + n->m_pkthdr.len; - for (m = n; m; m = m->m_next) { - len += m->m_len; - mbcnt += MSIZE; - if (m->m_flags & M_EXT) - mbcnt += m->m_ext.ext_size; - } - if (len != pktlen) { - printf("test %d; len %d != pktlen %d on mbuf 0x%x\n", - i, len, pktlen, n); - panic("tpsbcheck short"); - } - } - if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { - printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc, - mbcnt, sb->sb_mbcnt); - panic("tpsbcheck"); - } -} |
