|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /*- ! 23: * Copyright (c) 1991, 1993 ! 24: * The Regents of the University of California. All rights reserved. ! 25: * ! 26: * Redistribution and use in source and binary forms, with or without ! 27: * modification, are permitted provided that the following conditions ! 28: * are met: ! 29: * 1. Redistributions of source code must retain the above copyright ! 30: * notice, this list of conditions and the following disclaimer. ! 31: * 2. Redistributions in binary form must reproduce the above copyright ! 32: * notice, this list of conditions and the following disclaimer in the ! 33: * documentation and/or other materials provided with the distribution. ! 34: * 3. All advertising materials mentioning features or use of this software ! 35: * must display the following acknowledgement: ! 36: * This product includes software developed by the University of ! 37: * California, Berkeley and its contributors. ! 38: * 4. Neither the name of the University nor the names of its contributors ! 39: * may be used to endorse or promote products derived from this software ! 40: * without specific prior written permission. ! 41: * ! 42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 52: * SUCH DAMAGE. ! 53: * ! 54: * @(#)tp_subr.c 8.1 (Berkeley) 6/10/93 ! 55: */ ! 56: ! 57: /*********************************************************** ! 58: Copyright IBM Corporation 1987 ! 59: ! 60: All Rights Reserved ! 61: ! 62: Permission to use, copy, modify, and distribute this software and its ! 63: documentation for any purpose and without fee is hereby granted, ! 64: provided that the above copyright notice appear in all copies and that ! 65: both that copyright notice and this permission notice appear in ! 66: supporting documentation, and that the name of IBM not be ! 67: used in advertising or publicity pertaining to distribution of the ! 68: software without specific, written prior permission. ! 69: ! 70: IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ! 71: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ! 72: IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ! 73: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ! 74: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ! 75: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ! 76: SOFTWARE. ! 77: ! 78: ******************************************************************/ ! 79: ! 80: /* ! 81: * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison ! 82: */ ! 83: /* ! 84: * ARGO TP ! 85: * ! 86: * The main work of data transfer is done here. ! 87: * These routines are called from tp.trans. ! 88: * They include the routines that check the validity of acks and Xacks, ! 89: * (tp_goodack() and tp_goodXack() ) ! 90: * take packets from socket buffers and send them (tp_send()), ! 91: * drop the data from the socket buffers (tp_sbdrop()), ! 92: * and put incoming packet data into socket buffers (tp_stash()). ! 93: */ ! 94: ! 95: #include <sys/param.h> ! 96: #include <sys/systm.h> ! 97: #include <sys/mbuf.h> ! 98: #include <sys/socket.h> ! 99: #include <sys/socketvar.h> ! 100: #include <sys/protosw.h> ! 101: #include <sys/errno.h> ! 102: #include <sys/time.h> ! 103: #include <sys/kernel.h> ! 104: ! 105: #include <netiso/tp_ip.h> ! 106: #include <netiso/iso.h> ! 107: #include <netiso/argo_debug.h> ! 108: #include <netiso/tp_timer.h> ! 109: #include <netiso/tp_param.h> ! 110: #include <netiso/tp_stat.h> ! 111: #include <netiso/tp_pcb.h> ! 112: #include <netiso/tp_tpdu.h> ! 113: #include <netiso/tp_trace.h> ! 114: #include <netiso/tp_meas.h> ! 115: #include <netiso/tp_seq.h> ! 116: ! 117: int tp_emit(), tp_sbdrop(); ! 118: int tprexmtthresh = 3; ! 119: extern int ticks; ! 120: void tp_send(); ! 121: ! 122: /* ! 123: * CALLED FROM: ! 124: * tp.trans, when an XAK arrives ! 125: * FUNCTION and ARGUMENTS: ! 126: * Determines if the sequence number (seq) from the XAK ! 127: * acks anything new. If so, drop the appropriate tpdu ! 128: * from the XPD send queue. ! 129: * RETURN VALUE: ! 130: * Returns 1 if it did this, 0 if the ack caused no action. ! 131: */ ! 132: int ! 133: tp_goodXack(tpcb, seq) ! 134: struct tp_pcb *tpcb; ! 135: SeqNum seq; ! 136: { ! 137: ! 138: IFTRACE(D_XPD) ! 139: tptraceTPCB(TPPTgotXack, ! 140: seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndnew, ! 141: tpcb->tp_snduna); ! 142: ENDTRACE ! 143: ! 144: if ( seq == tpcb->tp_Xuna ) { ! 145: tpcb->tp_Xuna = tpcb->tp_Xsndnxt; ! 146: ! 147: /* DROP 1 packet from the Xsnd socket buf - just so happens ! 148: * that only one packet can be there at any time ! 149: * so drop the whole thing. If you allow > 1 packet ! 150: * the socket buffer, then you'll have to keep ! 151: * track of how many characters went w/ each XPD tpdu, so this ! 152: * will get messier ! 153: */ ! 154: IFDEBUG(D_XPD) ! 155: dump_mbuf(tpcb->tp_Xsnd.sb_mb, ! 156: "tp_goodXack Xsnd before sbdrop"); ! 157: ENDDEBUG ! 158: ! 159: IFTRACE(D_XPD) ! 160: tptraceTPCB(TPPTmisc, ! 161: "goodXack: dropping cc ", ! 162: (int)(tpcb->tp_Xsnd.sb_cc), ! 163: 0,0,0); ! 164: ENDTRACE ! 165: sbdroprecord(&tpcb->tp_Xsnd); ! 166: return 1; ! 167: } ! 168: return 0; ! 169: } ! 170: ! 171: /* ! 172: * CALLED FROM: ! 173: * tp_good_ack() ! 174: * FUNCTION and ARGUMENTS: ! 175: * updates ! 176: * smoothed average round trip time (*rtt) ! 177: * roundtrip time variance (*rtv) - actually deviation, not variance ! 178: * given the new value (diff) ! 179: * RETURN VALUE: ! 180: * void ! 181: */ ! 182: ! 183: void ! 184: tp_rtt_rtv(tpcb) ! 185: register struct tp_pcb *tpcb; ! 186: { ! 187: int old = tpcb->tp_rtt; ! 188: int delta, elapsed = ticks - tpcb->tp_rttemit; ! 189: ! 190: if (tpcb->tp_rtt != 0) { ! 191: /* ! 192: * rtt is the smoothed round trip time in machine clock ticks (hz). ! 193: * It is stored as a fixed point number, unscaled (unlike the tcp ! 194: * srtt). The rationale here is that it is only significant to the ! 195: * nearest unit of slowtimo, which is at least 8 machine clock ticks ! 196: * so there is no need to scale. The smoothing is done according ! 197: * to the same formula as TCP (rtt = rtt*7/8 + measured_rtt/8). ! 198: */ ! 199: delta = elapsed - tpcb->tp_rtt; ! 200: if ((tpcb->tp_rtt += (delta >> TP_RTT_ALPHA)) <= 0) ! 201: tpcb->tp_rtt = 1; ! 202: /* ! 203: * rtv is a smoothed accumulated mean difference, unscaled ! 204: * for reasons expressed above. ! 205: * It is smoothed with an alpha of .75, and the round trip timer ! 206: * will be set to rtt + 4*rtv, also as TCP does. ! 207: */ ! 208: if (delta < 0) ! 209: delta = -delta; ! 210: if ((tpcb->tp_rtv += ((delta - tpcb->tp_rtv) >> TP_RTV_ALPHA)) <= 0) ! 211: tpcb->tp_rtv = 1; ! 212: } else { ! 213: /* ! 214: * No rtt measurement yet - use the unsmoothed rtt. ! 215: * Set the variance to half the rtt (so our first ! 216: * retransmit happens at 3*rtt) ! 217: */ ! 218: tpcb->tp_rtt = elapsed; ! 219: tpcb->tp_rtv = elapsed >> 1; ! 220: } ! 221: tpcb->tp_rttemit = 0; ! 222: tpcb->tp_rxtshift = 0; ! 223: /* ! 224: * Quoting TCP: "the retransmit should happen at rtt + 4 * rttvar. ! 225: * Because of the way we do the smoothing, srtt and rttvar ! 226: * will each average +1/2 tick of bias. When we compute ! 227: * the retransmit timer, we want 1/2 tick of rounding and ! 228: * 1 extra tick because of +-1/2 tick uncertainty in the ! 229: * firing of the timer. The bias will give us exactly the ! 230: * 1.5 tick we need. But, because the bias is ! 231: * statistical, we have to test that we don't drop below ! 232: * the minimum feasible timer (which is 2 ticks)." ! 233: */ ! 234: TP_RANGESET(tpcb->tp_dt_ticks, TP_REXMTVAL(tpcb), ! 235: tpcb->tp_peer_acktime, 128 /* XXX */); ! 236: IFDEBUG(D_RTT) ! 237: printf("%s tpcb 0x%x, elapsed %d, delta %d, rtt %d, rtv %d, old %d\n", ! 238: "tp_rtt_rtv:",tpcb,elapsed,delta,tpcb->tp_rtt,tpcb->tp_rtv,old); ! 239: ENDDEBUG ! 240: tpcb->tp_rxtcur = tpcb->tp_dt_ticks; ! 241: } ! 242: ! 243: /* ! 244: * CALLED FROM: ! 245: * tp.trans when an AK arrives ! 246: * FUNCTION and ARGUMENTS: ! 247: * Given (cdt), the credit from the AK tpdu, and ! 248: * (seq), the sequence number from the AK tpdu, ! 249: * tp_goodack() determines if the AK acknowledges something in the send ! 250: * window, and if so, drops the appropriate packets from the retransmission ! 251: * list, computes the round trip time, and updates the retransmission timer ! 252: * based on the new smoothed round trip time. ! 253: * RETURN VALUE: ! 254: * Returns 1 if ! 255: * EITHER it actually acked something heretofore unacknowledged ! 256: * OR no news but the credit should be processed. ! 257: * If something heretofore unacked was acked with this sequence number, ! 258: * the appropriate tpdus are dropped from the retransmission control list, ! 259: * by calling tp_sbdrop(). ! 260: * No need to see the tpdu itself. ! 261: */ ! 262: int ! 263: tp_goodack(tpcb, cdt, seq, subseq) ! 264: register struct tp_pcb *tpcb; ! 265: u_int cdt; ! 266: register SeqNum seq; ! 267: u_int subseq; ! 268: { ! 269: int old_fcredit; ! 270: int bang = 0; /* bang --> ack for something heretofore unacked */ ! 271: u_int bytes_acked; ! 272: ! 273: IFDEBUG(D_ACKRECV) ! 274: printf("goodack tpcb 0x%x seq 0x%x cdt %d una 0x%x new 0x%x nxt 0x%x\n", ! 275: tpcb, seq, cdt, tpcb->tp_snduna, tpcb->tp_sndnew, tpcb->tp_sndnxt); ! 276: ENDDEBUG ! 277: IFTRACE(D_ACKRECV) ! 278: tptraceTPCB(TPPTgotack, ! 279: seq,cdt, tpcb->tp_snduna,tpcb->tp_sndnew,subseq); ! 280: ENDTRACE ! 281: ! 282: IFPERF(tpcb) ! 283: tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0); ! 284: ENDPERF ! 285: ! 286: if (seq == tpcb->tp_snduna) { ! 287: if (subseq < tpcb->tp_r_subseq || ! 288: (subseq == tpcb->tp_r_subseq && cdt <= tpcb->tp_fcredit)) { ! 289: discard_the_ack: ! 290: IFDEBUG(D_ACKRECV) ! 291: printf("goodack discard : tpcb 0x%x subseq %d r_subseq %d\n", ! 292: tpcb, subseq, tpcb->tp_r_subseq); ! 293: ENDDEBUG ! 294: goto done; ! 295: } ! 296: if (cdt == tpcb->tp_fcredit /*&& thus subseq > tpcb->tp_r_subseq */) { ! 297: tpcb->tp_r_subseq = subseq; ! 298: if (tpcb->tp_timer[TM_data_retrans] == 0) ! 299: tpcb->tp_dupacks = 0; ! 300: else if (++tpcb->tp_dupacks == tprexmtthresh) { ! 301: /* partner went out of his way to signal with different ! 302: subsequences that he has the same lack of an expected ! 303: packet. This may be an early indiciation of a loss */ ! 304: ! 305: SeqNum onxt = tpcb->tp_sndnxt; ! 306: struct mbuf *onxt_m = tpcb->tp_sndnxt_m; ! 307: u_int win = min(tpcb->tp_fcredit, ! 308: tpcb->tp_cong_win / tpcb->tp_l_tpdusize) / 2; ! 309: IFDEBUG(D_ACKRECV) ! 310: printf("%s tpcb 0x%x seq 0x%x rttseq 0x%x onxt 0x%x\n", ! 311: "goodack dupacks:", tpcb, seq, tpcb->tp_rttseq, onxt); ! 312: ENDDEBUG ! 313: if (win < 2) ! 314: win = 2; ! 315: tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize; ! 316: tpcb->tp_timer[TM_data_retrans] = 0; ! 317: tpcb->tp_rttemit = 0; ! 318: tpcb->tp_sndnxt = tpcb->tp_snduna; ! 319: tpcb->tp_sndnxt_m = 0; ! 320: tpcb->tp_cong_win = tpcb->tp_l_tpdusize; ! 321: tp_send(tpcb); ! 322: tpcb->tp_cong_win = tpcb->tp_ssthresh + ! 323: tpcb->tp_dupacks * tpcb->tp_l_tpdusize; ! 324: if (SEQ_GT(tpcb, onxt, tpcb->tp_sndnxt)) { ! 325: tpcb->tp_sndnxt = onxt; ! 326: tpcb->tp_sndnxt_m = onxt_m; ! 327: } ! 328: ! 329: } else if (tpcb->tp_dupacks > tprexmtthresh) { ! 330: tpcb->tp_cong_win += tpcb->tp_l_tpdusize; ! 331: } ! 332: goto done; ! 333: } ! 334: } else if (SEQ_LT(tpcb, seq, tpcb->tp_snduna)) ! 335: goto discard_the_ack; ! 336: /* ! 337: * If the congestion window was inflated to account ! 338: * for the other side's cached packets, retract it. ! 339: */ ! 340: if (tpcb->tp_dupacks > tprexmtthresh && ! 341: tpcb->tp_cong_win > tpcb->tp_ssthresh) ! 342: tpcb->tp_cong_win = tpcb->tp_ssthresh; ! 343: tpcb->tp_r_subseq = subseq; ! 344: old_fcredit = tpcb->tp_fcredit; ! 345: tpcb->tp_fcredit = cdt; ! 346: if (cdt > tpcb->tp_maxfcredit) ! 347: tpcb->tp_maxfcredit = cdt; ! 348: tpcb->tp_dupacks = 0; ! 349: ! 350: if (IN_SWINDOW(tpcb, seq, tpcb->tp_snduna, tpcb->tp_sndnew)) { ! 351: ! 352: tpsbcheck(tpcb, 0); ! 353: bytes_acked = tp_sbdrop(tpcb, seq); ! 354: tpsbcheck(tpcb, 1); ! 355: /* ! 356: * If transmit timer is running and timed sequence ! 357: * number was acked, update smoothed round trip time. ! 358: * Since we now have an rtt measurement, cancel the ! 359: * timer backoff (cf., Phil Karn's retransmit alg.). ! 360: * Recompute the initial retransmit timer. ! 361: */ ! 362: if (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq)) ! 363: tp_rtt_rtv(tpcb); ! 364: /* ! 365: * If all outstanding data is acked, stop retransmit timer. ! 366: * If there is more data to be acked, restart retransmit ! 367: * timer, using current (possibly backed-off) value. ! 368: * OSI combines the keepalive and persistance functions. ! 369: * So, there is no persistance timer per se, to restart. ! 370: */ ! 371: if (tpcb->tp_class != TP_CLASS_0) ! 372: tpcb->tp_timer[TM_data_retrans] = ! 373: (seq == tpcb->tp_sndnew) ? 0 : tpcb->tp_rxtcur; ! 374: /* ! 375: * When new data is acked, open the congestion window. ! 376: * If the window gives us less than ssthresh packets ! 377: * in flight, open exponentially (maxseg per packet). ! 378: * Otherwise open linearly: maxseg per window ! 379: * (maxseg^2 / cwnd per packet), plus a constant ! 380: * fraction of a packet (maxseg/8) to help larger windows ! 381: * open quickly enough. ! 382: */ ! 383: { ! 384: u_int cw = tpcb->tp_cong_win, incr = tpcb->tp_l_tpdusize; ! 385: ! 386: incr = min(incr, bytes_acked); ! 387: if (cw > tpcb->tp_ssthresh) ! 388: incr = incr * incr / cw + incr / 8; ! 389: tpcb->tp_cong_win = ! 390: min(cw + incr, tpcb->tp_sock->so_snd.sb_hiwat); ! 391: } ! 392: tpcb->tp_snduna = seq; ! 393: if (SEQ_LT(tpcb, tpcb->tp_sndnxt, seq)) { ! 394: tpcb->tp_sndnxt = seq; ! 395: tpcb->tp_sndnxt_m = 0; ! 396: } ! 397: bang++; ! 398: } ! 399: ! 400: if( cdt != 0 && old_fcredit == 0 ) { ! 401: tpcb->tp_sendfcc = 1; ! 402: } ! 403: if (cdt == 0) { ! 404: if (old_fcredit != 0) ! 405: IncStat(ts_zfcdt); ! 406: /* The following might mean that the window shrunk */ ! 407: if (tpcb->tp_timer[TM_data_retrans]) { ! 408: tpcb->tp_timer[TM_data_retrans] = 0; ! 409: tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks; ! 410: if (tpcb->tp_sndnxt != tpcb->tp_snduna) { ! 411: tpcb->tp_sndnxt = tpcb->tp_snduna; ! 412: tpcb->tp_sndnxt_m = 0; ! 413: } ! 414: } ! 415: } ! 416: tpcb->tp_fcredit = cdt; ! 417: bang |= (old_fcredit < cdt); ! 418: ! 419: done: ! 420: IFDEBUG(D_ACKRECV) ! 421: printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n", ! 422: bang, cdt, old_fcredit, tpcb->tp_cong_win); ! 423: ENDDEBUG ! 424: /* if (bang) XXXXX Very bad to remove this test, but somethings broken */ ! 425: tp_send(tpcb); ! 426: return (bang); ! 427: } ! 428: ! 429: /* ! 430: * CALLED FROM: ! 431: * tp_goodack() ! 432: * FUNCTION and ARGUMENTS: ! 433: * drops everything up TO but not INCLUDING seq # (seq) ! 434: * from the retransmission queue. ! 435: */ ! 436: tp_sbdrop(tpcb, seq) ! 437: register struct tp_pcb *tpcb; ! 438: SeqNum seq; ! 439: { ! 440: struct sockbuf *sb = &tpcb->tp_sock->so_snd; ! 441: register int i = SEQ_SUB(tpcb, seq, tpcb->tp_snduna); ! 442: int oldcc = sb->sb_cc, oldi = i; ! 443: ! 444: if (i >= tpcb->tp_seqhalf) ! 445: printf("tp_spdropping too much -- should panic"); ! 446: while (i-- > 0) ! 447: sbdroprecord(sb); ! 448: IFDEBUG(D_ACKRECV) ! 449: printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n", ! 450: oldi, oldcc - sb->sb_cc, tpcb, seq); ! 451: ENDDEBUG ! 452: if (sb->sb_flags & SB_NOTIFY) ! 453: sowwakeup(tpcb->tp_sock); ! 454: return (oldcc - sb->sb_cc); ! 455: } ! 456: ! 457: /* ! 458: * CALLED FROM: ! 459: * tp.trans on user send request, arrival of AK and arrival of XAK ! 460: * FUNCTION and ARGUMENTS: ! 461: * Emits tpdus starting at sequence number (tpcb->tp_sndnxt). ! 462: * Emits until a) runs out of data, or b) runs into an XPD mark, or ! 463: * c) it hits seq number (highseq) limited by cong or credit. ! 464: * ! 465: * If you want XPD to buffer > 1 du per socket buffer, you can ! 466: * modifiy this to issue XPD tpdus also, but then it'll have ! 467: * to take some argument(s) to distinguish between the type of DU to ! 468: * hand tp_emit. ! 469: * ! 470: * When something is sent for the first time, its time-of-send ! 471: * is stashed (in system clock ticks rather than pf_slowtimo ticks). ! 472: * When the ack arrives, the smoothed round-trip time is figured ! 473: * using this value. ! 474: */ ! 475: void ! 476: tp_send(tpcb) ! 477: register struct tp_pcb *tpcb; ! 478: { ! 479: register int len; ! 480: register struct mbuf *m; ! 481: struct mbuf *mb = 0; ! 482: struct sockbuf *sb = &tpcb->tp_sock->so_snd; ! 483: unsigned int eotsdu = 0; ! 484: SeqNum highseq, checkseq; ! 485: int idle, idleticks, off, cong_win; ! 486: #ifdef TP_PERF_MEAS ! 487: int send_start_time = ticks; ! 488: SeqNum oldnxt = tpcb->tp_sndnxt; ! 489: #endif /* TP_PERF_MEAS */ ! 490: ! 491: idle = (tpcb->tp_snduna == tpcb->tp_sndnew); ! 492: if (idle) { ! 493: idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact]; ! 494: if (idleticks > tpcb->tp_dt_ticks) ! 495: /* ! 496: * We have been idle for "a while" and no acks are ! 497: * expected to clock out any data we send -- ! 498: * slow start to get ack "clock" running again. ! 499: */ ! 500: tpcb->tp_cong_win = tpcb->tp_l_tpdusize; ! 501: } ! 502: ! 503: cong_win = tpcb->tp_cong_win; ! 504: highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna); ! 505: if (tpcb->tp_Xsnd.sb_mb) ! 506: highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew); ! 507: ! 508: IFDEBUG(D_DATA) ! 509: printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n", ! 510: tpcb, tpcb->tp_sndnxt, cong_win, highseq); ! 511: ENDDEBUG ! 512: IFTRACE(D_DATA) ! 513: tptraceTPCB( TPPTmisc, "tp_send sndnew snduna", ! 514: tpcb->tp_sndnew, tpcb->tp_snduna, 0, 0); ! 515: tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin", ! 516: tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win); ! 517: ENDTRACE ! 518: IFTRACE(D_DATA) ! 519: tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin", ! 520: tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win); ! 521: ENDTRACE ! 522: ! 523: if (tpcb->tp_sndnxt_m) ! 524: m = tpcb->tp_sndnxt_m; ! 525: else { ! 526: off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna); ! 527: for (m = sb->sb_mb; m && off > 0; m = m->m_next) ! 528: off--; ! 529: } ! 530: send: ! 531: /* ! 532: * Avoid silly window syndrome here . . . figure out how! ! 533: */ ! 534: checkseq = tpcb->tp_sndnum; ! 535: if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq)) ! 536: checkseq = highseq; /* i.e. DON'T retain highest assigned packet */ ! 537: ! 538: while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) { ! 539: ! 540: eotsdu = (m->m_flags & M_EOR) != 0; ! 541: len = m->m_pkthdr.len; ! 542: if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 && ! 543: len < (tpcb->tp_l_tpdusize / 2)) ! 544: break; /* Nagle . . . . . */ ! 545: cong_win -= len; ! 546: /* make a copy - mb goes into the retransmission list ! 547: * while m gets emitted. m_copy won't copy a zero-length mbuf. ! 548: */ ! 549: mb = m; ! 550: m = m_copy(mb, 0, M_COPYALL); ! 551: if (m == MNULL) ! 552: break; ! 553: IFTRACE(D_STASH) ! 554: tptraceTPCB( TPPTmisc, ! 555: "tp_send mcopy nxt high eotsdu len", ! 556: tpcb->tp_sndnxt, highseq, eotsdu, len); ! 557: ENDTRACE ! 558: ! 559: IFDEBUG(D_DATA) ! 560: printf("tp_sending tpcb 0x%x nxt 0x%x\n", ! 561: tpcb, tpcb->tp_sndnxt); ! 562: ENDDEBUG ! 563: /* when headers are precomputed, may need to fill ! 564: in checksum here */ ! 565: if (tpcb->tp_sock->so_error = ! 566: tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) { ! 567: /* error */ ! 568: break; ! 569: } ! 570: m = mb->m_nextpkt; ! 571: tpcb->tp_sndnxt_m = m; ! 572: if (tpcb->tp_sndnxt == tpcb->tp_sndnew) { ! 573: SEQ_INC(tpcb, tpcb->tp_sndnew); ! 574: /* ! 575: * Time this transmission if not a retransmission and ! 576: * not currently timing anything. ! 577: */ ! 578: if (tpcb->tp_rttemit == 0) { ! 579: tpcb->tp_rttemit = ticks; ! 580: tpcb->tp_rttseq = tpcb->tp_sndnxt; ! 581: } ! 582: tpcb->tp_sndnxt = tpcb->tp_sndnew; ! 583: } else ! 584: SEQ_INC(tpcb, tpcb->tp_sndnxt); ! 585: /* ! 586: * Set retransmit timer if not currently set. ! 587: * Initial value for retransmit timer is smoothed ! 588: * round-trip time + 2 * round-trip time variance. ! 589: * Initialize shift counter which is used for backoff ! 590: * of retransmit time. ! 591: */ ! 592: if (tpcb->tp_timer[TM_data_retrans] == 0 && ! 593: tpcb->tp_class != TP_CLASS_0) { ! 594: tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks; ! 595: tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks; ! 596: tpcb->tp_rxtshift = 0; ! 597: } ! 598: } ! 599: if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum)) ! 600: tpcb->tp_oktonagle = 0; ! 601: #ifdef TP_PERF_MEAS ! 602: IFPERF(tpcb) ! 603: { ! 604: register int npkts; ! 605: int elapsed = ticks - send_start_time, *t; ! 606: struct timeval now; ! 607: ! 608: npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt); ! 609: ! 610: if (npkts > 0) ! 611: tpcb->tp_Nwindow++; ! 612: ! 613: if (npkts > TP_PM_MAX) ! 614: npkts = TP_PM_MAX; ! 615: ! 616: t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); ! 617: *t += (t - elapsed) >> TP_RTT_ALPHA; ! 618: ! 619: if (mb == 0) { ! 620: IncPStat(tpcb, tps_win_lim_by_data[npkts] ); ! 621: } else { ! 622: IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); ! 623: /* not true with congestion-window being used */ ! 624: } ! 625: now.tv_sec = elapsed / hz; ! 626: now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz; ! 627: tpmeas( tpcb->tp_lref, ! 628: TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts); ! 629: } ! 630: ENDPERF ! 631: #endif /* TP_PERF_MEAS */ ! 632: ! 633: ! 634: IFTRACE(D_DATA) ! 635: tptraceTPCB( TPPTmisc, ! 636: "tp_send at end: new nxt eotsdu error", ! 637: tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error); ! 638: ! 639: ENDTRACE ! 640: } ! 641: ! 642: int TPNagleok; ! 643: int TPNagled; ! 644: ! 645: tp_packetize(tpcb, m, eotsdu) ! 646: register struct tp_pcb *tpcb; ! 647: register struct mbuf *m; ! 648: int eotsdu; ! 649: { ! 650: register struct mbuf *n; ! 651: register struct sockbuf *sb = &tpcb->tp_sock->so_snd; ! 652: int maxsize = tpcb->tp_l_tpdusize ! 653: - tp_headersize(DT_TPDU_type, tpcb) ! 654: - (tpcb->tp_use_checksum?4:0) ; ! 655: int totlen = m->m_pkthdr.len; ! 656: struct mbuf *m_split(); ! 657: /* ! 658: * Pre-packetize the data in the sockbuf ! 659: * according to negotiated mtu. Do it here ! 660: * where we can safely wait for mbufs. ! 661: * ! 662: * This presumes knowledge of sockbuf conventions. ! 663: * TODO: allocate space for header and fill it in (once!). ! 664: */ ! 665: IFDEBUG(D_DATA) ! 666: printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n", ! 667: maxsize, totlen, eotsdu, tpcb->tp_sndnum); ! 668: ENDTRACE ! 669: if (tpcb->tp_oktonagle) { ! 670: if ((n = sb->sb_mb) == 0) ! 671: panic("tp_packetize"); ! 672: while (n->m_act) ! 673: n = n->m_act; ! 674: if (n->m_flags & M_EOR) ! 675: panic("tp_packetize 2"); ! 676: SEQ_INC(tpcb, tpcb->tp_sndnum); ! 677: if (totlen + n->m_pkthdr.len < maxsize) { ! 678: /* There is an unsent packet with space, combine data */ ! 679: struct mbuf *old_n = n; ! 680: tpsbcheck(tpcb,3); ! 681: n->m_pkthdr.len += totlen; ! 682: while (n->m_next) ! 683: n = n->m_next; ! 684: sbcompress(sb, m, n); ! 685: tpsbcheck(tpcb,4); ! 686: n = old_n; ! 687: TPNagled++; ! 688: goto out; ! 689: } ! 690: } ! 691: while (m) { ! 692: n = m; ! 693: if (totlen > maxsize) { ! 694: if ((m = m_split(n, maxsize, M_WAIT)) == 0) ! 695: panic("tp_packetize"); ! 696: } else ! 697: m = 0; ! 698: totlen -= maxsize; ! 699: tpsbcheck(tpcb, 5); ! 700: sbappendrecord(sb, n); ! 701: tpsbcheck(tpcb, 6); ! 702: SEQ_INC(tpcb, tpcb->tp_sndnum); ! 703: } ! 704: out: ! 705: if (eotsdu) { ! 706: n->m_flags |= M_EOR; /* XXX belongs at end */ ! 707: tpcb->tp_oktonagle = 0; ! 708: } else { ! 709: SEQ_DEC(tpcb, tpcb->tp_sndnum); ! 710: tpcb->tp_oktonagle = 1; ! 711: TPNagleok++; ! 712: } ! 713: IFDEBUG(D_DATA) ! 714: printf("SEND out: oktonagle %d sndnum 0x%x\n", ! 715: tpcb->tp_oktonagle, tpcb->tp_sndnum); ! 716: ENDTRACE ! 717: return 0; ! 718: } ! 719: ! 720: ! 721: /* ! 722: * NAME: tp_stash() ! 723: * CALLED FROM: ! 724: * tp.trans on arrival of a DT tpdu ! 725: * FUNCTION, ARGUMENTS, and RETURN VALUE: ! 726: * Returns 1 if ! 727: * a) something new arrived and it's got eotsdu_reached bit on, ! 728: * b) this arrival was caused other out-of-sequence things to be ! 729: * accepted, or ! 730: * c) this arrival is the highest seq # for which we last gave credit ! 731: * (sender just sent a whole window) ! 732: * In other words, returns 1 if tp should send an ack immediately, 0 if ! 733: * the ack can wait a while. ! 734: * ! 735: * Note: this implementation no longer renegs on credit, (except ! 736: * when debugging option D_RENEG is on, for the purpose of testing ! 737: * ack subsequencing), so we don't need to check for incoming tpdus ! 738: * being in a reneged portion of the window. ! 739: */ ! 740: ! 741: tp_stash(tpcb, e) ! 742: register struct tp_pcb *tpcb; ! 743: register struct tp_event *e; ! 744: { ! 745: register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; ! 746: /* 0--> delay acks until full window */ ! 747: /* 1--> ack each tpdu */ ! 748: #ifndef lint ! 749: #define E e->ATTR(DT_TPDU) ! 750: #else /* lint */ ! 751: #define E e->ev_union.EV_DT_TPDU ! 752: #endif /* lint */ ! 753: ! 754: if ( E.e_eot ) { ! 755: register struct mbuf *n = E.e_data; ! 756: n->m_flags |= M_EOR; ! 757: n->m_act = 0; ! 758: } ! 759: IFDEBUG(D_STASH) ! 760: dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, ! 761: "stash: so_rcv before appending"); ! 762: dump_mbuf(E.e_data, ! 763: "stash: e_data before appending"); ! 764: ENDDEBUG ! 765: ! 766: IFPERF(tpcb) ! 767: PStat(tpcb, Nb_from_ll) += E.e_datalen; ! 768: tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, ! 769: E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); ! 770: ENDPERF ! 771: ! 772: if (E.e_seq == tpcb->tp_rcvnxt) { ! 773: ! 774: IFDEBUG(D_STASH) ! 775: printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", ! 776: E.e_seq, E.e_datalen, E.e_eot); ! 777: ENDDEBUG ! 778: ! 779: IFTRACE(D_STASH) ! 780: tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", ! 781: E.e_seq, E.e_datalen, E.e_eot, 0); ! 782: ENDTRACE ! 783: ! 784: SET_DELACK(tpcb); ! 785: ! 786: sbappend(&tpcb->tp_sock->so_rcv, E.e_data); ! 787: ! 788: SEQ_INC( tpcb, tpcb->tp_rcvnxt ); ! 789: /* ! 790: * move chains from the reassembly queue to the socket buffer ! 791: */ ! 792: if (tpcb->tp_rsycnt) { ! 793: register struct mbuf **mp; ! 794: struct mbuf **mplim; ! 795: ! 796: mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit); ! 797: mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit; ! 798: ! 799: while (tpcb->tp_rsycnt && *mp) { ! 800: sbappend(&tpcb->tp_sock->so_rcv, *mp); ! 801: tpcb->tp_rsycnt--; ! 802: *mp = 0; ! 803: SEQ_INC(tpcb, tpcb->tp_rcvnxt); ! 804: ack_reason |= ACK_REORDER; ! 805: if (++mp == mplim) ! 806: mp = tpcb->tp_rsyq; ! 807: } ! 808: } ! 809: IFDEBUG(D_STASH) ! 810: dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, ! 811: "stash: so_rcv after appending"); ! 812: ENDDEBUG ! 813: ! 814: } else { ! 815: register struct mbuf **mp; ! 816: SeqNum uwe; ! 817: ! 818: IFTRACE(D_STASH) ! 819: tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", ! 820: E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); ! 821: ENDTRACE ! 822: ! 823: if (tpcb->tp_rsyq == 0) ! 824: tp_rsyset(tpcb); ! 825: uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit); ! 826: if (tpcb->tp_rsyq == 0 || ! 827: !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) { ! 828: ack_reason = ACK_DONT; ! 829: m_freem(E.e_data); ! 830: } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) { ! 831: IFDEBUG(D_STASH) ! 832: printf("tp_stash - drop & ack\n"); ! 833: ENDDEBUG ! 834: ! 835: /* retransmission - drop it and force an ack */ ! 836: IncStat(ts_dt_dup); ! 837: IFPERF(tpcb) ! 838: IncPStat(tpcb, tps_n_ack_cuz_dup); ! 839: ENDPERF ! 840: ! 841: m_freem(E.e_data); ! 842: ack_reason |= ACK_DUP; ! 843: } else { ! 844: *mp = E.e_data; ! 845: tpcb->tp_rsycnt++; ! 846: ack_reason = ACK_DONT; ! 847: } ! 848: } ! 849: /* there were some comments of historical interest here. */ ! 850: { ! 851: LOCAL_CREDIT(tpcb); ! 852: ! 853: if ( E.e_seq == tpcb->tp_sent_uwe ) ! 854: ack_reason |= ACK_STRAT_FULLWIN; ! 855: ! 856: IFTRACE(D_STASH) ! 857: tptraceTPCB(TPPTmisc, ! 858: "end of stash, eot, ack_reason, sent_uwe ", ! 859: E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); ! 860: ENDTRACE ! 861: ! 862: if ( ack_reason == ACK_DONT ) { ! 863: IncStat( ts_ackreason[ACK_DONT] ); ! 864: return 0; ! 865: } else { ! 866: IFPERF(tpcb) ! 867: if(ack_reason & ACK_STRAT_EACH) { ! 868: IncPStat(tpcb, tps_n_ack_cuz_strat); ! 869: } else if(ack_reason & ACK_STRAT_FULLWIN) { ! 870: IncPStat(tpcb, tps_n_ack_cuz_fullwin); ! 871: } else if(ack_reason & ACK_REORDER) { ! 872: IncPStat(tpcb, tps_n_ack_cuz_reorder); ! 873: } ! 874: tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, ! 875: SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); ! 876: ENDPERF ! 877: { ! 878: register int i; ! 879: ! 880: /* keep track of all reasons that apply */ ! 881: for( i=1; i<_ACK_NUM_REASONS_ ;i++) { ! 882: if( ack_reason & (1<<i) ) ! 883: IncStat( ts_ackreason[i] ); ! 884: } ! 885: } ! 886: return 1; ! 887: } ! 888: } ! 889: } ! 890: ! 891: /* ! 892: * tp_rsyflush - drop all the packets on the reassembly queue. ! 893: * Do this when closing the socket, or when somebody has changed ! 894: * the space avaible in the receive socket (XXX). ! 895: */ ! 896: tp_rsyflush(tpcb) ! 897: register struct tp_pcb *tpcb; ! 898: { ! 899: register struct mbuf *m, **mp; ! 900: if (tpcb->tp_rsycnt) { ! 901: for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit; ! 902: --mp >= tpcb->tp_rsyq; ) ! 903: if (*mp) { ! 904: tpcb->tp_rsycnt--; ! 905: m_freem(*mp); ! 906: } ! 907: if (tpcb->tp_rsycnt) { ! 908: printf("tp_rsyflush %x\n", tpcb); ! 909: tpcb->tp_rsycnt = 0; ! 910: } ! 911: } ! 912: FREE((caddr_t)tpcb->tp_rsyq, M_PCB); ! 913: tpcb->tp_rsyq = 0; ! 914: } ! 915: ! 916: tp_rsyset(tpcb) ! 917: register struct tp_pcb *tpcb; ! 918: { ! 919: register struct socket *so = tpcb->tp_sock; ! 920: int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf; ! 921: int old_credit = tpcb->tp_maxlcredit; ! 922: caddr_t rsyq; ! 923: ! 924: tpcb->tp_maxlcredit = maxcredit = min(maxcredit, ! 925: (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize); ! 926: ! 927: if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0) ! 928: return; ! 929: maxcredit *= sizeof(struct mbuf *); ! 930: if (tpcb->tp_rsyq) ! 931: tp_rsyflush(tpcb); ! 932: // if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT)) ! 933: MALLOC(rsyq, caddr_t, maxcredit, M_PCB, M_NOWAIT); ! 934: if (rsyq) ! 935: bzero(rsyq, maxcredit); ! 936: tpcb->tp_rsyq = (struct mbuf **)rsyq; ! 937: } ! 938: ! 939: tpsbcheck(tpcb, i) ! 940: struct tp_pcb *tpcb; ! 941: { ! 942: register struct mbuf *n, *m; ! 943: register int len = 0, mbcnt = 0, pktlen; ! 944: struct sockbuf *sb = &tpcb->tp_sock->so_snd; ! 945: ! 946: for (n = sb->sb_mb; n; n = n->m_nextpkt) { ! 947: if ((n->m_flags & M_PKTHDR) == 0) ! 948: panic("tpsbcheck nohdr"); ! 949: pktlen = len + n->m_pkthdr.len; ! 950: for (m = n; m; m = m->m_next) { ! 951: len += m->m_len; ! 952: mbcnt += MSIZE; ! 953: if (m->m_flags & M_EXT) ! 954: mbcnt += m->m_ext.ext_size; ! 955: } ! 956: if (len != pktlen) { ! 957: printf("test %d; len %d != pktlen %d on mbuf 0x%x\n", ! 958: i, len, pktlen, n); ! 959: panic("tpsbcheck short"); ! 960: } ! 961: } ! 962: if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { ! 963: printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc, ! 964: mbcnt, sb->sb_mbcnt); ! 965: panic("tpsbcheck"); ! 966: } ! 967: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.