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