149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*51204Ssklower * @(#)tp_subr.c 7.15 (Berkeley) 09/26/91 849268Sbostic */ 949268Sbostic 1036413Ssklower /*********************************************************** 1136413Ssklower Copyright IBM Corporation 1987 1236413Ssklower 1336413Ssklower All Rights Reserved 1436413Ssklower 1536413Ssklower Permission to use, copy, modify, and distribute this software and its 1636413Ssklower documentation for any purpose and without fee is hereby granted, 1736413Ssklower provided that the above copyright notice appear in all copies and that 1836413Ssklower both that copyright notice and this permission notice appear in 1936413Ssklower supporting documentation, and that the name of IBM not be 2036413Ssklower used in advertising or publicity pertaining to distribution of the 2136413Ssklower software without specific, written prior permission. 2236413Ssklower 2336413Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2436413Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2536413Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2636413Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2736413Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2836413Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2936413Ssklower SOFTWARE. 3036413Ssklower 3136413Ssklower ******************************************************************/ 3236413Ssklower 3336413Ssklower /* 3436413Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3536413Ssklower */ 3636413Ssklower /* 3736413Ssklower * ARGO TP 3836413Ssklower * 3936413Ssklower * $Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $ 4036413Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_subr.c,v $ 4136413Ssklower * 4236413Ssklower * The main work of data transfer is done here. 4336413Ssklower * These routines are called from tp.trans. 4436413Ssklower * They include the routines that check the validity of acks and Xacks, 4536413Ssklower * (tp_goodack() and tp_goodXack() ) 4636413Ssklower * take packets from socket buffers and send them (tp_send()), 4736413Ssklower * drop the data from the socket buffers (tp_sbdrop()), 4836413Ssklower * and put incoming packet data into socket buffers (tp_stash()). 4936413Ssklower */ 5036413Ssklower 5136413Ssklower #include "param.h" 5236413Ssklower #include "mbuf.h" 5336413Ssklower #include "socket.h" 5436413Ssklower #include "socketvar.h" 5536413Ssklower #include "protosw.h" 5636413Ssklower #include "errno.h" 5736413Ssklower #include "types.h" 5836413Ssklower #include "time.h" 5951138Ssklower #include "kernel.h" 6036413Ssklower 6137469Ssklower #include "tp_ip.h" 6237469Ssklower #include "iso.h" 6337469Ssklower #include "argo_debug.h" 6437469Ssklower #include "tp_timer.h" 6537469Ssklower #include "tp_param.h" 6637469Ssklower #include "tp_stat.h" 6737469Ssklower #include "tp_pcb.h" 6837469Ssklower #include "tp_tpdu.h" 6937469Ssklower #include "tp_trace.h" 7037469Ssklower #include "tp_meas.h" 7137469Ssklower #include "tp_seq.h" 7236413Ssklower 73*51204Ssklower int tp_emit(), tp_sbdrop(); 74*51204Ssklower int tprexmtthresh = 3; 75*51204Ssklower void tp_send(); 7636413Ssklower 7736413Ssklower /* 7836413Ssklower * CALLED FROM: 7936413Ssklower * tp.trans, when an XAK arrives 8036413Ssklower * FUNCTION and ARGUMENTS: 8136413Ssklower * Determines if the sequence number (seq) from the XAK 8236413Ssklower * acks anything new. If so, drop the appropriate tpdu 8336413Ssklower * from the XPD send queue. 8436413Ssklower * RETURN VALUE: 8536413Ssklower * Returns 1 if it did this, 0 if the ack caused no action. 8636413Ssklower */ 8736413Ssklower int 8836413Ssklower tp_goodXack(tpcb, seq) 8936413Ssklower struct tp_pcb *tpcb; 9036413Ssklower SeqNum seq; 9136413Ssklower { 9236413Ssklower 9336413Ssklower IFTRACE(D_XPD) 9436413Ssklower tptraceTPCB(TPPTgotXack, 95*51204Ssklower seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndnew, 9636413Ssklower tpcb->tp_snduna); 9736413Ssklower ENDTRACE 9836413Ssklower 9936413Ssklower if ( seq == tpcb->tp_Xuna ) { 10036413Ssklower tpcb->tp_Xuna = tpcb->tp_Xsndnxt; 10136413Ssklower 10236413Ssklower /* DROP 1 packet from the Xsnd socket buf - just so happens 10336413Ssklower * that only one packet can be there at any time 10436413Ssklower * so drop the whole thing. If you allow > 1 packet 10536413Ssklower * the socket buffer, then you'll have to keep 10636413Ssklower * track of how many characters went w/ each XPD tpdu, so this 10736413Ssklower * will get messier 10836413Ssklower */ 10936413Ssklower IFDEBUG(D_XPD) 11036413Ssklower dump_mbuf(tpcb->tp_Xsnd.sb_mb, 11136413Ssklower "tp_goodXack Xsnd before sbdrop"); 11236413Ssklower ENDDEBUG 11336413Ssklower 11436413Ssklower IFTRACE(D_XPD) 11536413Ssklower tptraceTPCB(TPPTmisc, 11636413Ssklower "goodXack: dropping cc ", 11736413Ssklower (int)(tpcb->tp_Xsnd.sb_cc), 11836413Ssklower 0,0,0); 11936413Ssklower ENDTRACE 120*51204Ssklower sbdroprecord(&tpcb->tp_Xsnd); 12136413Ssklower return 1; 12236413Ssklower } 12336413Ssklower return 0; 12436413Ssklower } 12536413Ssklower 12636413Ssklower /* 12736413Ssklower * CALLED FROM: 12836413Ssklower * tp_good_ack() 12936413Ssklower * FUNCTION and ARGUMENTS: 13036413Ssklower * updates 13151138Ssklower * smoothed average round trip time (*rtt) 13251138Ssklower * roundtrip time variance (*rtv) - actually deviation, not variance 13336413Ssklower * given the new value (diff) 13436413Ssklower * RETURN VALUE: 13536413Ssklower * void 13636413Ssklower */ 13736413Ssklower 13836413Ssklower void 139*51204Ssklower tp_rtt_rtv(tpcb) 140*51204Ssklower register struct tp_pcb *tpcb; 14136413Ssklower { 142*51204Ssklower int new, old = tpcb->tp_dt_ticks; 143*51204Ssklower int delta, elapsed = tick - tpcb->tp_rttemit; 14436413Ssklower 145*51204Ssklower if (tpcb->tp_rtt != 0) { 146*51204Ssklower /* 147*51204Ssklower * rtt is the smoothed round trip time in machine clock ticks (hz). 148*51204Ssklower * it is stored as a fixed point number, unscaled (unlike the tcp 149*51204Ssklower * srtt. The rationale here is that it is only significant to the 150*51204Ssklower * nearest unit of slowtimo, which is at least 8 machine clock ticks 151*51204Ssklower * so there is no need to scale. The smoothing is done according 152*51204Ssklower * to the same formula as TCP (rtt = rtt*7/8 + measured_rtt/8). 153*51204Ssklower */ 154*51204Ssklower delta = elapsed - tpcb->tp_rtt; 155*51204Ssklower if ((tpcb->tp_rtt += (delta >> TP_RTT_ALPHA)) <= 0) 156*51204Ssklower tpcb->tp_rtt = 1; 157*51204Ssklower /* 158*51204Ssklower * rtv is a smoothed accumulated mean difference, unscaled 159*51204Ssklower * for reasons expressed above. 160*51204Ssklower * It is smoothed with an alpha of .75, and the round trip timer 161*51204Ssklower * will be set to rtt + 4*rtv, also as TCP does. 162*51204Ssklower */ 163*51204Ssklower if (delta < 0) 164*51204Ssklower delta = -delta; 165*51204Ssklower if ((tpcb->tp_rtv += ((delta - tpcb->tp_rtv) >> TP_RTV_ALPHA)) <= 0) 166*51204Ssklower tpcb->tp_rtv = 1; 167*51204Ssklower } else { 168*51204Ssklower /* 169*51204Ssklower * No rtt measurement yet - use the unsmoothed rtt. 170*51204Ssklower * Set the variance to half the rtt (so our first 171*51204Ssklower * retransmit happens at 3*rtt) 172*51204Ssklower */ 173*51204Ssklower tpcb->tp_rtt = elapsed; 174*51204Ssklower tpcb->tp_rtv = elapsed >> 1; 175*51204Ssklower } 176*51204Ssklower tpcb->tp_rttemit = 0; 177*51204Ssklower tpcb->tp_rxtshift = 0; 178*51204Ssklower /* 179*51204Ssklower * Quoting TCP: "the retransmit should happen at rtt + 4 * rttvar. 180*51204Ssklower * Because of the way we do the smoothing, srtt and rttvar 181*51204Ssklower * will each average +1/2 tick of bias. When we compute 182*51204Ssklower * the retransmit timer, we want 1/2 tick of rounding and 183*51204Ssklower * 1 extra tick because of +-1/2 tick uncertainty in the 184*51204Ssklower * firing of the timer. The bias will give us exactly the 185*51204Ssklower * 1.5 tick we need. But, because the bias is 186*51204Ssklower * statistical, we have to test that we don't drop below 187*51204Ssklower * the minimum feasible timer (which is 2 ticks)." 188*51204Ssklower */ 189*51204Ssklower new = (((tpcb->tp_rtt + (tpcb->tp_rtv << 2)) * PR_SLOWHZ) + hz) / hz; 190*51204Ssklower new = MAX(new + 1, tpcb->tp_peer_acktime); 191*51204Ssklower new = MAX(new, 2); 192*51204Ssklower IFTRACE(D_RTT) 193*51204Ssklower tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks", 194*51204Ssklower old, rtv, rtt, new); 195*51204Ssklower ENDTRACE 196*51204Ssklower tpcb->tp_rxtcur = tpcb->tp_dt_ticks = new; 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; 222*51204Ssklower register SeqNum seq; 223*51204Ssklower u_int subseq; 22436413Ssklower { 225*51204Ssklower int old_fcredit; 22636413Ssklower int bang = 0; /* bang --> ack for something heretofore unacked */ 227*51204Ssklower u_int bytes_acked; 22836413Ssklower 22936413Ssklower IFDEBUG(D_ACKRECV) 230*51204Ssklower printf("goodack tpcb 0x%x seq 0x%x cdt %d una 0x%x new 0x%x nxt 0x%x\n", 231*51204Ssklower tpcb, seq, cdt, tpcb->tp_snduna, tpcb->tp_sndnew, tpcb->tp_sndnxt); 23236413Ssklower ENDDEBUG 23336413Ssklower IFTRACE(D_ACKRECV) 23436413Ssklower tptraceTPCB(TPPTgotack, 235*51204Ssklower 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 242*51204Ssklower if (seq == tpcb->tp_snduna) { 243*51204Ssklower if (subseq < tpcb->tp_r_subseq || 244*51204Ssklower (subseq == tpcb->tp_r_subseq && cdt <= tpcb->tp_fcredit)) { 245*51204Ssklower discard_the_ack: 246*51204Ssklower IFDEBUG(D_ACKRECV) 247*51204Ssklower printf("goodack discard : tpcb 0x%x subseq %d r_subseq %d\n", 248*51204Ssklower tpcb, subseq, tpcb->tp_r_subseq); 249*51204Ssklower ENDDEBUG 250*51204Ssklower goto done; 25136413Ssklower } 252*51204Ssklower if (cdt == tpcb->tp_fcredit /*&& thus subseq > tpcb->tp_r_subseq */) { 253*51204Ssklower tpcb->tp_r_subseq = subseq; 254*51204Ssklower if (tpcb->tp_timer[TM_data_retrans] == 0) 255*51204Ssklower tpcb->tp_dupacks = 0; 256*51204Ssklower else if (++tpcb->tp_dupacks == tprexmtthresh) { 257*51204Ssklower /* partner went out of his way to signal with different 258*51204Ssklower subsequences that he has the same lack of an expected 259*51204Ssklower packet. This may be an early indiciation of a loss */ 26036413Ssklower 261*51204Ssklower SeqNum onxt = tpcb->tp_sndnxt; 262*51204Ssklower struct mbuf *onxt_m = tpcb->tp_sndnxt_m; 263*51204Ssklower u_int win = min(tpcb->tp_fcredit, 264*51204Ssklower tpcb->tp_cong_win / tpcb->tp_l_tpdusize) / 2; 265*51204Ssklower if (win < 2) 266*51204Ssklower win = 2; 267*51204Ssklower tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize; 268*51204Ssklower tpcb->tp_timer[TM_data_retrans] = 0; 269*51204Ssklower tpcb->tp_rttemit = 0; 270*51204Ssklower tpcb->tp_sndnxt = tpcb->tp_snduna; 271*51204Ssklower tpcb->tp_sndnxt_m = 0; 272*51204Ssklower tpcb->tp_cong_win = tpcb->tp_l_tpdusize; 273*51204Ssklower tp_send(tpcb); 274*51204Ssklower tpcb->tp_cong_win = tpcb->tp_ssthresh + 275*51204Ssklower tpcb->tp_dupacks * tpcb->tp_l_tpdusize; 276*51204Ssklower if (SEQ_GT(tpcb, onxt, tpcb->tp_sndnxt)) { 277*51204Ssklower tpcb->tp_sndnxt = onxt; 278*51204Ssklower tpcb->tp_sndnxt_m = onxt_m; 279*51204Ssklower } 28036413Ssklower 281*51204Ssklower } else if (tpcb->tp_dupacks > tprexmtthresh) { 282*51204Ssklower tpcb->tp_cong_win += tpcb->tp_l_tpdusize; 28351138Ssklower } 284*51204Ssklower goto done; 285*51204Ssklower } 286*51204Ssklower } else if (SEQ_LT(tpcb, seq, tpcb->tp_snduna)) 287*51204Ssklower goto discard_the_ack; 288*51204Ssklower /* 289*51204Ssklower * If the congestion window was inflated to account 290*51204Ssklower * for the other side's cached packets, retract it. 291*51204Ssklower */ 292*51204Ssklower if (tpcb->tp_dupacks > tprexmtthresh && 293*51204Ssklower tpcb->tp_cong_win > tpcb->tp_ssthresh) 294*51204Ssklower tpcb->tp_cong_win = tpcb->tp_ssthresh; 295*51204Ssklower tpcb->tp_r_subseq = subseq; 296*51204Ssklower old_fcredit = tpcb->tp_fcredit; 297*51204Ssklower tpcb->tp_fcredit = cdt; 298*51204Ssklower if (cdt > tpcb->tp_maxfcredit) 299*51204Ssklower tpcb->tp_maxfcredit = cdt; 300*51204Ssklower tpcb->tp_dupacks = 0; 30136413Ssklower 302*51204Ssklower if (IN_SWINDOW(tpcb, seq, tpcb->tp_snduna, tpcb->tp_sndnew)) { 30336413Ssklower 304*51204Ssklower tpsbcheck(tpcb, 0); 305*51204Ssklower bytes_acked = tp_sbdrop(tpcb, seq); 306*51204Ssklower tpsbcheck(tpcb, 1); 307*51204Ssklower /* 308*51204Ssklower * If transmit timer is running and timed sequence 309*51204Ssklower * number was acked, update smoothed round trip time. 310*51204Ssklower * Since we now have an rtt measurement, cancel the 311*51204Ssklower * timer backoff (cf., Phil Karn's retransmit alg.). 312*51204Ssklower * Recompute the initial retransmit timer. 313*51204Ssklower */ 314*51204Ssklower if (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq)) 315*51204Ssklower tp_rtt_rtv(tpcb); 316*51204Ssklower /* 317*51204Ssklower * If all outstanding data is acked, stop retransmit timer. 318*51204Ssklower * If there is more data to be acked, restart retransmit 319*51204Ssklower * timer, using current (possibly backed-off) value. 320*51204Ssklower * OSI combines the keepalive and persistance functions. 321*51204Ssklower * So, there is no persistance timer per se, to restart. 322*51204Ssklower */ 323*51204Ssklower tpcb->tp_timer[TM_data_retrans] = 324*51204Ssklower (seq == tpcb->tp_sndnew) ? 0 : tpcb->tp_rxtcur; 325*51204Ssklower /* 326*51204Ssklower * When new data is acked, open the congestion window. 327*51204Ssklower * If the window gives us less than ssthresh packets 328*51204Ssklower * in flight, open exponentially (maxseg per packet). 329*51204Ssklower * Otherwise open linearly: maxseg per window 330*51204Ssklower * (maxseg^2 / cwnd per packet), plus a constant 331*51204Ssklower * fraction of a packet (maxseg/8) to help larger windows 332*51204Ssklower * open quickly enough. 333*51204Ssklower */ 334*51204Ssklower { 335*51204Ssklower u_int cw = tpcb->tp_cong_win, incr = tpcb->tp_l_tpdusize; 33636413Ssklower 337*51204Ssklower incr = min(incr, bytes_acked); 338*51204Ssklower if (cw > tpcb->tp_ssthresh) 339*51204Ssklower incr = incr * incr / cw + incr / 8; 340*51204Ssklower tpcb->tp_cong_win = 341*51204Ssklower min(cw + incr, tpcb->tp_sock->so_snd.sb_hiwat); 34236413Ssklower } 34336413Ssklower tpcb->tp_snduna = seq; 344*51204Ssklower if (SEQ_LT(tpcb, tpcb->tp_sndnxt, seq)) { 345*51204Ssklower tpcb->tp_sndnxt = seq; 346*51204Ssklower tpcb->tp_sndnxt_m = 0; 347*51204Ssklower } 34836413Ssklower bang++; 34936413Ssklower } 35036413Ssklower 35136413Ssklower if( cdt != 0 && old_fcredit == 0 ) { 35236413Ssklower tpcb->tp_sendfcc = 1; 35336413Ssklower } 35436413Ssklower if( cdt == 0 && old_fcredit != 0 ) { 35536413Ssklower IncStat(ts_zfcdt); 35636413Ssklower } 35736413Ssklower tpcb->tp_fcredit = cdt; 358*51204Ssklower bang |= (old_fcredit < cdt); 35936413Ssklower 360*51204Ssklower done: 36136413Ssklower IFDEBUG(D_ACKRECV) 362*51204Ssklower printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n", 363*51204Ssklower bang, cdt, old_fcredit, tpcb->tp_cong_win); 36436413Ssklower ENDDEBUG 365*51204Ssklower /* if (bang) XXXXX Very bad to remove this test, but somethings broken */ 366*51204Ssklower tp_send(tpcb); 367*51204Ssklower return (bang); 36836413Ssklower } 36936413Ssklower 37036413Ssklower /* 37136413Ssklower * CALLED FROM: 37236413Ssklower * tp_goodack() 37336413Ssklower * FUNCTION and ARGUMENTS: 37450901Ssklower * drops everything up TO but not INCLUDING seq # (seq) 37536413Ssklower * from the retransmission queue. 37636413Ssklower */ 37736413Ssklower tp_sbdrop(tpcb, seq) 37850901Ssklower register struct tp_pcb *tpcb; 37936413Ssklower SeqNum seq; 38036413Ssklower { 38150901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 382*51204Ssklower register int i = SEQ_SUB(tpcb, seq, tpcb->tp_snduna); 383*51204Ssklower int oldcc = sb->sb_cc, oldi = i; 38436413Ssklower 385*51204Ssklower if (i >= tpcb->tp_seqhalf) 386*51204Ssklower printf("tp_spdropping too much -- should panic"); 387*51204Ssklower while (i-- > 0) 388*51204Ssklower sbdroprecord(sb); 38936413Ssklower IFDEBUG(D_ACKRECV) 390*51204Ssklower printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n", 391*51204Ssklower oldi, oldcc - sb->sb_cc, tpcb, seq); 39236413Ssklower ENDDEBUG 393*51204Ssklower if (sb->sb_flags & SB_NOTIFY) 394*51204Ssklower sowwakeup(tpcb->tp_sock); 39551138Ssklower return (oldcc - sb->sb_cc); 39636413Ssklower } 39736413Ssklower 39836413Ssklower /* 39936413Ssklower * CALLED FROM: 40036413Ssklower * tp.trans on user send request, arrival of AK and arrival of XAK 40136413Ssklower * FUNCTION and ARGUMENTS: 402*51204Ssklower * Emits tpdus starting at sequence number (tpcb->tp_sndnxt). 40336413Ssklower * Emits until a) runs out of data, or b) runs into an XPD mark, or 404*51204Ssklower * c) it hits seq number (highseq) limited by cong or credit. 40536413Ssklower * 40636413Ssklower * If you want XPD to buffer > 1 du per socket buffer, you can 40736413Ssklower * modifiy this to issue XPD tpdus also, but then it'll have 40836413Ssklower * to take some argument(s) to distinguish between the type of DU to 40950901Ssklower * hand tp_emit. 41036413Ssklower * 41136413Ssklower * When something is sent for the first time, its time-of-send 412*51204Ssklower * is stashed (in system clock ticks rather than pf_slowtimo ticks). 413*51204Ssklower * When the ack arrives, the smoothed round-trip time is figured 414*51204Ssklower * using this value. 41536413Ssklower */ 416*51204Ssklower void 41736413Ssklower tp_send(tpcb) 41836413Ssklower register struct tp_pcb *tpcb; 41936413Ssklower { 42036413Ssklower register int len; 421*51204Ssklower register struct mbuf *m; 422*51204Ssklower struct mbuf *mb = 0; 42336413Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 424*51204Ssklower unsigned int eotsdu = 0; 425*51204Ssklower SeqNum highseq, checkseq; 426*51204Ssklower int idle, idleticks, off, cong_win; 42736413Ssklower #ifdef TP_PERF_MEAS 42851138Ssklower int send_start_time = tick; 429*51204Ssklower SeqNum oldnxt = tpcb->tp_sndnxt; 43036413Ssklower #endif TP_PERF_MEAS 43136413Ssklower 432*51204Ssklower idle = (tpcb->tp_snduna == tpcb->tp_sndnew); 433*51204Ssklower if (idle) { 434*51204Ssklower idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact]; 435*51204Ssklower if (idleticks > tpcb->tp_dt_ticks) 436*51204Ssklower /* 437*51204Ssklower * We have been idle for "a while" and no acks are 438*51204Ssklower * expected to clock out any data we send -- 439*51204Ssklower * slow start to get ack "clock" running again. 440*51204Ssklower */ 441*51204Ssklower tpcb->tp_cong_win = tpcb->tp_l_tpdusize; 442*51204Ssklower } 44336413Ssklower 444*51204Ssklower cong_win = tpcb->tp_cong_win; 445*51204Ssklower highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna); 446*51204Ssklower if (tpcb->tp_Xsnd.sb_mb) 447*51204Ssklower highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew); 44836413Ssklower 44936413Ssklower IFDEBUG(D_DATA) 450*51204Ssklower printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n", 451*51204Ssklower tpcb, tpcb->tp_sndnxt, cong_win, highseq); 45236413Ssklower ENDDEBUG 45336413Ssklower IFTRACE(D_DATA) 454*51204Ssklower tptraceTPCB( TPPTmisc, "tp_send sndnew snduna", 455*51204Ssklower tpcb->tp_sndnew, tpcb->tp_snduna, 0, 0); 456*51204Ssklower tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin", 457*51204Ssklower tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win); 45836413Ssklower ENDTRACE 45936413Ssklower IFTRACE(D_DATA) 460*51204Ssklower tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin", 461*51204Ssklower tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win); 46236413Ssklower ENDTRACE 46336413Ssklower 464*51204Ssklower if (tpcb->tp_sndnxt_m) 465*51204Ssklower m = tpcb->tp_sndnxt_m; 466*51204Ssklower else { 467*51204Ssklower off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna); 468*51204Ssklower for (m = sb->sb_mb; m && off > 0; m = m->m_next) 469*51204Ssklower off--; 470*51204Ssklower } 471*51204Ssklower send: 472*51204Ssklower /* 473*51204Ssklower * Avoid silly window syndrome here . . . figure out how! 474*51204Ssklower */ 475*51204Ssklower checkseq = tpcb->tp_sndnum; 476*51204Ssklower if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq)) 477*51204Ssklower checkseq = highseq; 47836413Ssklower 479*51204Ssklower while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) { 48036413Ssklower 481*51204Ssklower eotsdu = (m->m_flags & M_EOR) != 0; 482*51204Ssklower len = m->m_pkthdr.len; 483*51204Ssklower if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 && 484*51204Ssklower len < (tpcb->tp_l_tpdusize / 2)) 485*51204Ssklower break; /* Nagle . . . . . */ 486*51204Ssklower cong_win -= len; 48736413Ssklower /* make a copy - mb goes into the retransmission list 48836413Ssklower * while m gets emitted. m_copy won't copy a zero-length mbuf. 48936413Ssklower */ 490*51204Ssklower mb = m; 49150901Ssklower m = m_copy(mb, 0, M_COPYALL); 49250901Ssklower if (m == MNULL) 493*51204Ssklower break; 494*51204Ssklower IFTRACE(D_STASH) 49536413Ssklower tptraceTPCB( TPPTmisc, 496*51204Ssklower "tp_send mcopy nxt high eotsdu len", 497*51204Ssklower tpcb->tp_sndnxt, highseq, eotsdu, len); 49836413Ssklower ENDTRACE 499*51204Ssklower 500*51204Ssklower IFDEBUG(D_DATA) 501*51204Ssklower printf("tp_sending tpcb 0x%x nxt 0x%x\n", 502*51204Ssklower tpcb, tpcb->tp_sndnxt); 503*51204Ssklower ENDDEBUG 504*51204Ssklower /* when headers are precomputed, may need to fill 50550901Ssklower in checksum here */ 50650901Ssklower if (tpcb->tp_sock->so_error = 507*51204Ssklower tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) { 50836413Ssklower /* error */ 509*51204Ssklower break; 51036413Ssklower } 511*51204Ssklower m = mb->m_nextpkt; 512*51204Ssklower tpcb->tp_sndnxt_m = m; 513*51204Ssklower if (tpcb->tp_sndnxt == tpcb->tp_sndnew) { 514*51204Ssklower SEQ_INC(tpcb, tpcb->tp_sndnew); 515*51204Ssklower /* 516*51204Ssklower * Time this transmission if not a retransmission and 517*51204Ssklower * not currently timing anything. 518*51204Ssklower */ 519*51204Ssklower if (tpcb->tp_rttemit == 0) { 520*51204Ssklower tpcb->tp_rttemit = tick; 521*51204Ssklower tpcb->tp_rttseq = tpcb->tp_sndnxt; 522*51204Ssklower } 523*51204Ssklower tpcb->tp_sndnxt = tpcb->tp_sndnew; 524*51204Ssklower } else 525*51204Ssklower SEQ_INC(tpcb, tpcb->tp_sndnxt); 526*51204Ssklower /* 527*51204Ssklower * Set retransmit timer if not currently set. 528*51204Ssklower * Initial value for retransmit timer is smoothed 529*51204Ssklower * round-trip time + 2 * round-trip time variance. 530*51204Ssklower * Initialize shift counter which is used for backoff 531*51204Ssklower * of retransmit time. 532*51204Ssklower */ 533*51204Ssklower if (tpcb->tp_timer[TM_data_retrans] == 0) { 534*51204Ssklower tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks; 535*51204Ssklower tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks; 536*51204Ssklower tpcb->tp_rxtshift = 0; 53751138Ssklower } 53836413Ssklower } 539*51204Ssklower if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum)) 540*51204Ssklower tpcb->tp_oktonagle = 0; 54150236Ssklower #ifdef TP_PERF_MEAS 54236413Ssklower IFPERF(tpcb) 54336413Ssklower { 54436413Ssklower register int npkts; 54551138Ssklower int elapsed = tick - send_start_time, *t; 54651138Ssklower struct timeval now; 54736413Ssklower 548*51204Ssklower npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt); 54936413Ssklower 550*51204Ssklower if (npkts > 0) 55136413Ssklower tpcb->tp_Nwindow++; 55236413Ssklower 55336413Ssklower if (npkts > TP_PM_MAX) 55436413Ssklower npkts = TP_PM_MAX; 55536413Ssklower 55636413Ssklower t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); 55751138Ssklower *t += (t - elapsed) >> TP_RTT_ALPHA; 55836413Ssklower 559*51204Ssklower if (mb == 0) { 56036413Ssklower IncPStat(tpcb, tps_win_lim_by_data[npkts] ); 56136413Ssklower } else { 56236413Ssklower IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); 56336413Ssklower /* not true with congestion-window being used */ 56436413Ssklower } 56551138Ssklower now.tv_sec = elapsed / hz; 56651138Ssklower now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz; 56736413Ssklower tpmeas( tpcb->tp_lref, 568*51204Ssklower TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts); 56936413Ssklower } 57036413Ssklower ENDPERF 57150236Ssklower #endif TP_PERF_MEAS 57236413Ssklower 57336413Ssklower 57436413Ssklower IFTRACE(D_DATA) 57536413Ssklower tptraceTPCB( TPPTmisc, 576*51204Ssklower "tp_send at end: new nxt eotsdu error", 577*51204Ssklower tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error); 57836413Ssklower 57936413Ssklower ENDTRACE 58036413Ssklower } 58136413Ssklower 58250901Ssklower int TPNagleok; 58350901Ssklower int TPNagled; 58450901Ssklower 58550901Ssklower tp_packetize(tpcb, m, eotsdu) 58650901Ssklower register struct tp_pcb *tpcb; 58750901Ssklower register struct mbuf *m; 58850901Ssklower int eotsdu; 58950901Ssklower { 59050901Ssklower register struct mbuf *n; 59150901Ssklower register struct sockbuf *sb = &tpcb->tp_sock->so_snd; 59250901Ssklower int maxsize = tpcb->tp_l_tpdusize 59350901Ssklower - tp_headersize(DT_TPDU_type, tpcb) 59450901Ssklower - (tpcb->tp_use_checksum?4:0) ; 59550901Ssklower int totlen = m->m_pkthdr.len; 59650901Ssklower struct mbuf *m_split(); 59750901Ssklower /* 59850901Ssklower * Pre-packetize the data in the sockbuf 59950901Ssklower * according to negotiated mtu. Do it here 60050901Ssklower * where we can safely wait for mbufs. 60150901Ssklower * 60250901Ssklower * This presumes knowledge of sockbuf conventions. 60350901Ssklower * TODO: allocate space for header and fill it in (once!). 60450901Ssklower */ 605*51204Ssklower IFDEBUG(D_DATA) 606*51204Ssklower printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n", 607*51204Ssklower maxsize, totlen, eotsdu, tpcb->tp_sndnum); 60850901Ssklower ENDTRACE 60950901Ssklower if (tpcb->tp_oktonagle) { 61050901Ssklower if ((n = sb->sb_mb) == 0) 61150901Ssklower panic("tp_packetize"); 61250901Ssklower while (n->m_act) 61350901Ssklower n = n->m_act; 61450901Ssklower if (n->m_flags & M_EOR) 61550901Ssklower panic("tp_packetize 2"); 61650901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 61750901Ssklower if (totlen + n->m_pkthdr.len < maxsize) { 61850901Ssklower /* There is an unsent packet with space, combine data */ 61950901Ssklower struct mbuf *old_n = n; 62050901Ssklower tpsbcheck(tpcb,3); 62150901Ssklower n->m_pkthdr.len += totlen; 62250901Ssklower while (n->m_next) 62350901Ssklower n = n->m_next; 62450901Ssklower sbcompress(sb, m, n); 62550901Ssklower tpsbcheck(tpcb,4); 62650901Ssklower n = old_n; 62750901Ssklower TPNagled++; 62850901Ssklower goto out; 62950901Ssklower } 63050901Ssklower } 63150901Ssklower while (m) { 63250901Ssklower n = m; 63350901Ssklower if (totlen > maxsize) { 63450901Ssklower if ((m = m_split(n, maxsize, M_WAIT)) == 0) 63550901Ssklower panic("tp_packetize"); 63650901Ssklower } else 63750901Ssklower m = 0; 63850901Ssklower totlen -= maxsize; 63950901Ssklower tpsbcheck(tpcb, 5); 64050901Ssklower sbappendrecord(sb, n); 64150901Ssklower tpsbcheck(tpcb, 6); 64250901Ssklower SEQ_INC(tpcb, tpcb->tp_sndnum); 64350901Ssklower } 64450901Ssklower out: 64550901Ssklower if (eotsdu) { 64650901Ssklower n->m_flags |= M_EOR; /* XXX belongs at end */ 64750901Ssklower tpcb->tp_oktonagle = 0; 64850901Ssklower } else { 64950901Ssklower SEQ_DEC(tpcb, tpcb->tp_sndnum); 65050901Ssklower tpcb->tp_oktonagle = 1; 65150901Ssklower TPNagleok++; 65250901Ssklower } 653*51204Ssklower IFDEBUG(D_DATA) 654*51204Ssklower printf("SEND out: oktonagle %d sndnum 0x%x\n", 655*51204Ssklower tpcb->tp_oktonagle, tpcb->tp_sndnum); 656*51204Ssklower ENDTRACE 65750901Ssklower return 0; 65850901Ssklower } 65950901Ssklower 66050901Ssklower 66136413Ssklower /* 66236413Ssklower * NAME: tp_stash() 66336413Ssklower * CALLED FROM: 66436413Ssklower * tp.trans on arrival of a DT tpdu 66536413Ssklower * FUNCTION, ARGUMENTS, and RETURN VALUE: 66636413Ssklower * Returns 1 if 66736413Ssklower * a) something new arrived and it's got eotsdu_reached bit on, 66836413Ssklower * b) this arrival was caused other out-of-sequence things to be 66936413Ssklower * accepted, or 67036413Ssklower * c) this arrival is the highest seq # for which we last gave credit 67136413Ssklower * (sender just sent a whole window) 67236413Ssklower * In other words, returns 1 if tp should send an ack immediately, 0 if 67336413Ssklower * the ack can wait a while. 67436413Ssklower * 67536413Ssklower * Note: this implementation no longer renegs on credit, (except 67636413Ssklower * when debugging option D_RENEG is on, for the purpose of testing 67736413Ssklower * ack subsequencing), so we don't need to check for incoming tpdus 67836413Ssklower * being in a reneged portion of the window. 67936413Ssklower */ 68036413Ssklower 681*51204Ssklower tp_stash(tpcb, e) 68236413Ssklower register struct tp_pcb *tpcb; 68336413Ssklower register struct tp_event *e; 68436413Ssklower { 68536413Ssklower register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; 68636413Ssklower /* 0--> delay acks until full window */ 68736413Ssklower /* 1--> ack each tpdu */ 68836413Ssklower #ifndef lint 68936413Ssklower #define E e->ATTR(DT_TPDU) 69036413Ssklower #else lint 69136413Ssklower #define E e->ev_union.EV_DT_TPDU 69236413Ssklower #endif lint 69336413Ssklower 69436413Ssklower if ( E.e_eot ) { 69536413Ssklower register struct mbuf *n = E.e_data; 69637469Ssklower n->m_flags |= M_EOR; 69738841Ssklower n->m_act = 0; 69837469Ssklower } 69936413Ssklower IFDEBUG(D_STASH) 70036413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 70136413Ssklower "stash: so_rcv before appending"); 70236413Ssklower dump_mbuf(E.e_data, 70336413Ssklower "stash: e_data before appending"); 70436413Ssklower ENDDEBUG 70536413Ssklower 70636413Ssklower IFPERF(tpcb) 70736413Ssklower PStat(tpcb, Nb_from_ll) += E.e_datalen; 70836413Ssklower tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 70937469Ssklower E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); 71036413Ssklower ENDPERF 71136413Ssklower 71251024Ssklower if (E.e_seq == tpcb->tp_rcvnxt) { 71336413Ssklower 71436413Ssklower IFDEBUG(D_STASH) 71536413Ssklower printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", 71636413Ssklower E.e_seq, E.e_datalen, E.e_eot); 71736413Ssklower ENDDEBUG 71836413Ssklower 71936413Ssklower IFTRACE(D_STASH) 72036413Ssklower tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 72136413Ssklower E.e_seq, E.e_datalen, E.e_eot, 0); 72236413Ssklower ENDTRACE 72336413Ssklower 72451024Ssklower SET_DELACK(tpcb); 72551024Ssklower 72637469Ssklower sbappend(&tpcb->tp_sock->so_rcv, E.e_data); 72737469Ssklower 72836413Ssklower SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 72936413Ssklower /* 73050901Ssklower * move chains from the reassembly queue to the socket buffer 73136413Ssklower */ 73250901Ssklower if (tpcb->tp_rsycnt) { 73350901Ssklower register struct mbuf **mp; 73450901Ssklower struct mbuf **mplim; 73536413Ssklower 73650901Ssklower mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit); 73750901Ssklower mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit; 73836413Ssklower 73950901Ssklower while (tpcb->tp_rsycnt && *mp) { 74050901Ssklower sbappend(&tpcb->tp_sock->so_rcv, *mp); 74150901Ssklower tpcb->tp_rsycnt--; 74250901Ssklower *mp = 0; 74350901Ssklower SEQ_INC(tpcb, tpcb->tp_rcvnxt); 74436413Ssklower ack_reason |= ACK_REORDER; 74550901Ssklower if (++mp == mplim) 74650901Ssklower mp = tpcb->tp_rsyq; 74736413Ssklower } 74836413Ssklower } 74936413Ssklower IFDEBUG(D_STASH) 75036413Ssklower dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 75136413Ssklower "stash: so_rcv after appending"); 75236413Ssklower ENDDEBUG 75336413Ssklower 75436413Ssklower } else { 75550901Ssklower register struct mbuf **mp; 75650901Ssklower SeqNum uwe; 75736413Ssklower 75836413Ssklower IFTRACE(D_STASH) 75936413Ssklower tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", 76036413Ssklower E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); 76136413Ssklower ENDTRACE 76236413Ssklower 76350975Ssklower if (tpcb->tp_rsyq == 0) 76450975Ssklower tp_rsyset(tpcb); 76550901Ssklower uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit); 76650901Ssklower if (tpcb->tp_rsyq == 0 || 76750901Ssklower !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) { 76836413Ssklower ack_reason = ACK_DONT; 76950901Ssklower m_freem(E.e_data); 77050901Ssklower } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) { 77136413Ssklower IFDEBUG(D_STASH) 77236413Ssklower printf("tp_stash - drop & ack\n"); 77336413Ssklower ENDDEBUG 77436413Ssklower 77536413Ssklower /* retransmission - drop it and force an ack */ 77636413Ssklower IncStat(ts_dt_dup); 77736413Ssklower IFPERF(tpcb) 77836413Ssklower IncPStat(tpcb, tps_n_ack_cuz_dup); 77936413Ssklower ENDPERF 78036413Ssklower 78150901Ssklower m_freem(E.e_data); 78236413Ssklower ack_reason |= ACK_DUP; 78350901Ssklower } else { 78450901Ssklower *mp = E.e_data; 78550901Ssklower tpcb->tp_rsycnt++; 78650901Ssklower ack_reason = ACK_DONT; 78736413Ssklower } 78836413Ssklower } 78951024Ssklower /* there were some comments of historical interest here. */ 79036413Ssklower { 79136413Ssklower LOCAL_CREDIT(tpcb); 79236413Ssklower 79336413Ssklower if ( E.e_seq == tpcb->tp_sent_uwe ) 79436413Ssklower ack_reason |= ACK_STRAT_FULLWIN; 79536413Ssklower 79636413Ssklower IFTRACE(D_STASH) 79736413Ssklower tptraceTPCB(TPPTmisc, 79836413Ssklower "end of stash, eot, ack_reason, sent_uwe ", 79936413Ssklower E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); 80036413Ssklower ENDTRACE 80136413Ssklower 80236413Ssklower if ( ack_reason == ACK_DONT ) { 80336413Ssklower IncStat( ts_ackreason[ACK_DONT] ); 80436413Ssklower return 0; 80536413Ssklower } else { 80636413Ssklower IFPERF(tpcb) 80736413Ssklower if(ack_reason & ACK_STRAT_EACH) { 80836413Ssklower IncPStat(tpcb, tps_n_ack_cuz_strat); 80936413Ssklower } else if(ack_reason & ACK_STRAT_FULLWIN) { 81036413Ssklower IncPStat(tpcb, tps_n_ack_cuz_fullwin); 81136413Ssklower } else if(ack_reason & ACK_REORDER) { 81236413Ssklower IncPStat(tpcb, tps_n_ack_cuz_reorder); 81336413Ssklower } 81436413Ssklower tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, 81536413Ssklower SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); 81636413Ssklower ENDPERF 81736413Ssklower { 81836413Ssklower register int i; 81936413Ssklower 82036413Ssklower /* keep track of all reasons that apply */ 82136413Ssklower for( i=1; i<_ACK_NUM_REASONS_ ;i++) { 82236413Ssklower if( ack_reason & (1<<i) ) 82336413Ssklower IncStat( ts_ackreason[i] ); 82436413Ssklower } 82536413Ssklower } 82636413Ssklower return 1; 82736413Ssklower } 82836413Ssklower } 82936413Ssklower } 83050901Ssklower 83150901Ssklower /* 83250901Ssklower * tp_rsyflush - drop all the packets on the reassembly queue. 83350901Ssklower * Do this when closing the socket, or when somebody has changed 83450901Ssklower * the space avaible in the receive socket (XXX). 83550901Ssklower */ 83650901Ssklower tp_rsyflush(tpcb) 83750901Ssklower register struct tp_pcb *tpcb; 83850901Ssklower { 83950901Ssklower register struct mbuf *m, **mp; 84050901Ssklower if (tpcb->tp_rsycnt) { 84150901Ssklower for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit; 84250901Ssklower --mp >= tpcb->tp_rsyq; ) 84350901Ssklower if (*mp) { 84450901Ssklower tpcb->tp_rsycnt--; 84550901Ssklower m_freem(*mp); 84650901Ssklower } 84750901Ssklower if (tpcb->tp_rsycnt) 84850901Ssklower panic("tp_rsyflush"); 84950901Ssklower } 85050901Ssklower free((caddr_t)tpcb->tp_rsyq, M_PCB); 85150901Ssklower tpcb->tp_rsyq = 0; 85250901Ssklower } 85350901Ssklower 85450901Ssklower tp_rsyset(tpcb) 85550901Ssklower register struct tp_pcb *tpcb; 85650901Ssklower { 85750901Ssklower register struct socket *so = tpcb->tp_sock; 85850901Ssklower int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf; 85950975Ssklower int old_credit = tpcb->tp_maxlcredit; 86050975Ssklower caddr_t rsyq; 86150901Ssklower 86250901Ssklower tpcb->tp_maxlcredit = maxcredit = min(maxcredit, 86350901Ssklower (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize); 86450901Ssklower 86550975Ssklower if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0) 86650975Ssklower return; 86750901Ssklower maxcredit *= sizeof(struct mbuf *); 86850901Ssklower if (tpcb->tp_rsyq) 86950901Ssklower tp_rsyflush(tpcb); 87050901Ssklower if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT)) 87150901Ssklower bzero(rsyq, maxcredit); 87250901Ssklower tpcb->tp_rsyq = (struct mbuf **)rsyq; 87350901Ssklower } 87450901Ssklower 87550901Ssklower tpsbcheck(tpcb, i) 87650901Ssklower struct tp_pcb *tpcb; 87750901Ssklower { 87850901Ssklower register struct mbuf *n, *m; 87950901Ssklower register int len = 0, mbcnt = 0, pktlen; 88050901Ssklower struct sockbuf *sb = &tpcb->tp_sock->so_snd; 88150901Ssklower 88250901Ssklower for (n = sb->sb_mb; n; n = n->m_nextpkt) { 88350901Ssklower if ((n->m_flags & M_PKTHDR) == 0) 88450901Ssklower panic("tpsbcheck nohdr"); 88550901Ssklower pktlen = len + n->m_pkthdr.len; 88650901Ssklower for (m = n; m; m = m->m_next) { 88750901Ssklower len += m->m_len; 88850901Ssklower mbcnt += MSIZE; 88950901Ssklower if (m->m_flags & M_EXT) 89050901Ssklower mbcnt += m->m_ext.ext_size; 89150901Ssklower } 89250901Ssklower if (len != pktlen) { 89350901Ssklower printf("test %d; len %d != pktlen %d on mbuf 0x%x\n", 89450901Ssklower i, len, pktlen, n); 89550901Ssklower panic("tpsbcheck short"); 89650901Ssklower } 89750901Ssklower } 89850901Ssklower if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { 89950901Ssklower printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc, 90050901Ssklower mbcnt, sb->sb_mbcnt); 90150901Ssklower panic("tpsbcheck"); 90250901Ssklower } 90350901Ssklower } 904