|
|
1.1 ! root 1: /*- ! 2: * Copyright (c) 1991 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms, with or without ! 6: * modification, are permitted provided that the following conditions ! 7: * are met: ! 8: * 1. Redistributions of source code must retain the above copyright ! 9: * notice, this list of conditions and the following disclaimer. ! 10: * 2. Redistributions in binary form must reproduce the above copyright ! 11: * notice, this list of conditions and the following disclaimer in the ! 12: * documentation and/or other materials provided with the distribution. ! 13: * 3. All advertising materials mentioning features or use of this software ! 14: * must display the following acknowledgement: ! 15: * This product includes software developed by the University of ! 16: * California, Berkeley and its contributors. ! 17: * 4. Neither the name of the University nor the names of its contributors ! 18: * may be used to endorse or promote products derived from this software ! 19: * without specific prior written permission. ! 20: * ! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 31: * SUCH DAMAGE. ! 32: * ! 33: * @(#)tp_subr.c 7.9 (Berkeley) 6/27/91 ! 34: */ ! 35: ! 36: /*********************************************************** ! 37: Copyright IBM Corporation 1987 ! 38: ! 39: All Rights Reserved ! 40: ! 41: Permission to use, copy, modify, and distribute this software and its ! 42: documentation for any purpose and without fee is hereby granted, ! 43: provided that the above copyright notice appear in all copies and that ! 44: both that copyright notice and this permission notice appear in ! 45: supporting documentation, and that the name of IBM not be ! 46: used in advertising or publicity pertaining to distribution of the ! 47: software without specific, written prior permission. ! 48: ! 49: IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ! 50: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ! 51: IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ! 52: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ! 53: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ! 54: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ! 55: SOFTWARE. ! 56: ! 57: ******************************************************************/ ! 58: ! 59: /* ! 60: * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison ! 61: */ ! 62: /* ! 63: * ARGO TP ! 64: * ! 65: * $Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $ ! 66: * $Source: /usr/argo/sys/netiso/RCS/tp_subr.c,v $ ! 67: * ! 68: * The main work of data transfer is done here. ! 69: * These routines are called from tp.trans. ! 70: * They include the routines that check the validity of acks and Xacks, ! 71: * (tp_goodack() and tp_goodXack() ) ! 72: * take packets from socket buffers and send them (tp_send()), ! 73: * drop the data from the socket buffers (tp_sbdrop()), ! 74: * and put incoming packet data into socket buffers (tp_stash()). ! 75: */ ! 76: ! 77: #include "param.h" ! 78: #include "mbuf.h" ! 79: #include "socket.h" ! 80: #include "socketvar.h" ! 81: #include "protosw.h" ! 82: #include "errno.h" ! 83: #include "types.h" ! 84: #include "time.h" ! 85: ! 86: #include "tp_ip.h" ! 87: #include "iso.h" ! 88: #include "argo_debug.h" ! 89: #include "tp_timer.h" ! 90: #include "tp_param.h" ! 91: #include "tp_stat.h" ! 92: #include "tp_pcb.h" ! 93: #include "tp_tpdu.h" ! 94: #include "tp_trace.h" ! 95: #include "tp_meas.h" ! 96: #include "tp_seq.h" ! 97: ! 98: int tp_emit(); ! 99: static void tp_sbdrop(); ! 100: ! 101: #define SMOOTH(newtype, alpha, old, new) \ ! 102: (newtype) (((new - old)>>alpha) + (old)) ! 103: ! 104: #define ABS(type, val) \ ! 105: (type) (((int)(val)<0)?-(val):(val)) ! 106: ! 107: #define TP_MAKE_RTC( Xreg, Xseq, Xeot, Xdata, Xlen, Xretval, Xtype) \ ! 108: { struct mbuf *xxn;\ ! 109: MGET(xxn, M_DONTWAIT, Xtype);\ ! 110: if( xxn == (struct mbuf *)0 ) {\ ! 111: printf("MAKE RTC FAILED: ENOBUFS\n");\ ! 112: return (int)Xretval;\ ! 113: }\ ! 114: xxn->m_act=MNULL;\ ! 115: Xreg = mtod(xxn, struct tp_rtc *);\ ! 116: if( Xreg == (struct tp_rtc *)0 ) {\ ! 117: return (int)Xretval;\ ! 118: }\ ! 119: Xreg->tprt_eot = Xeot;\ ! 120: Xreg->tprt_seq = Xseq;\ ! 121: Xreg->tprt_data = Xdata;\ ! 122: Xreg->tprt_octets = Xlen;\ ! 123: } ! 124: ! 125: ! 126: /* ! 127: * CALLED FROM: ! 128: * tp.trans, when an XAK arrives ! 129: * FUNCTION and ARGUMENTS: ! 130: * Determines if the sequence number (seq) from the XAK ! 131: * acks anything new. If so, drop the appropriate tpdu ! 132: * from the XPD send queue. ! 133: * RETURN VALUE: ! 134: * Returns 1 if it did this, 0 if the ack caused no action. ! 135: */ ! 136: int ! 137: tp_goodXack(tpcb, seq) ! 138: struct tp_pcb *tpcb; ! 139: SeqNum seq; ! 140: { ! 141: ! 142: IFTRACE(D_XPD) ! 143: tptraceTPCB(TPPTgotXack, ! 144: seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndhiwat, ! 145: tpcb->tp_snduna); ! 146: ENDTRACE ! 147: ! 148: if ( seq == tpcb->tp_Xuna ) { ! 149: tpcb->tp_Xuna = tpcb->tp_Xsndnxt; ! 150: ! 151: /* DROP 1 packet from the Xsnd socket buf - just so happens ! 152: * that only one packet can be there at any time ! 153: * so drop the whole thing. If you allow > 1 packet ! 154: * the socket buffer, then you'll have to keep ! 155: * track of how many characters went w/ each XPD tpdu, so this ! 156: * will get messier ! 157: */ ! 158: IFDEBUG(D_XPD) ! 159: dump_mbuf(tpcb->tp_Xsnd.sb_mb, ! 160: "tp_goodXack Xsnd before sbdrop"); ! 161: ENDDEBUG ! 162: ! 163: IFTRACE(D_XPD) ! 164: tptraceTPCB(TPPTmisc, ! 165: "goodXack: dropping cc ", ! 166: (int)(tpcb->tp_Xsnd.sb_cc), ! 167: 0,0,0); ! 168: ENDTRACE ! 169: sbdrop( &tpcb->tp_Xsnd, (int)(tpcb->tp_Xsnd.sb_cc)); ! 170: CONG_ACK(tpcb, seq); ! 171: return 1; ! 172: } ! 173: return 0; ! 174: } ! 175: ! 176: /* ! 177: * CALLED FROM: ! 178: * tp_good_ack() ! 179: * FUNCTION and ARGUMENTS: ! 180: * updates ! 181: * smoothed average round trip time (base_rtt) ! 182: * roundtrip time variance (base_rtv) - actually deviation, not variance ! 183: * given the new value (diff) ! 184: * RETURN VALUE: ! 185: * void ! 186: */ ! 187: ! 188: void ! 189: tp_rtt_rtv( base_rtt, base_rtv, newmeas ) ! 190: struct timeval *base_rtt, *base_rtv, *newmeas; ! 191: { ! 192: /* update rt variance (really just the deviation): ! 193: * rtv.smooth_ave = SMOOTH( | oldrtt.smooth_avg - rtt.this_instance | ) ! 194: */ ! 195: base_rtv->tv_sec = ! 196: SMOOTH( long, TP_RTV_ALPHA, base_rtv->tv_sec, ! 197: ABS( long, base_rtt->tv_sec - newmeas->tv_sec )); ! 198: base_rtv->tv_usec = ! 199: SMOOTH( long, TP_RTV_ALPHA, base_rtv->tv_usec, ! 200: ABS(long, base_rtt->tv_usec - newmeas->tv_usec )); ! 201: ! 202: /* update smoothed average rtt */ ! 203: base_rtt->tv_sec = ! 204: SMOOTH( long, TP_RTT_ALPHA, base_rtt->tv_sec, newmeas->tv_sec); ! 205: base_rtt->tv_usec = ! 206: SMOOTH( long, TP_RTT_ALPHA, base_rtt->tv_usec, newmeas->tv_usec); ! 207: ! 208: } ! 209: ! 210: /* ! 211: * CALLED FROM: ! 212: * tp.trans when an AK arrives ! 213: * FUNCTION and ARGUMENTS: ! 214: * Given (cdt), the credit from the AK tpdu, and ! 215: * (seq), the sequence number from the AK tpdu, ! 216: * tp_goodack() determines if the AK acknowledges something in the send ! 217: * window, and if so, drops the appropriate packets from the retransmission ! 218: * list, computes the round trip time, and updates the retransmission timer ! 219: * based on the new smoothed round trip time. ! 220: * RETURN VALUE: ! 221: * Returns 1 if ! 222: * EITHER it actually acked something heretofore unacknowledged ! 223: * OR no news but the credit should be processed. ! 224: * If something heretofore unacked was acked with this sequence number, ! 225: * the appropriate tpdus are dropped from the retransmission control list, ! 226: * by calling tp_sbdrop(). ! 227: * No need to see the tpdu itself. ! 228: */ ! 229: int ! 230: tp_goodack(tpcb, cdt, seq, subseq) ! 231: register struct tp_pcb *tpcb; ! 232: u_int cdt; ! 233: register SeqNum seq, subseq; ! 234: { ! 235: int old_fcredit = tpcb->tp_fcredit; ! 236: int bang = 0; /* bang --> ack for something heretofore unacked */ ! 237: ! 238: IFDEBUG(D_ACKRECV) ! 239: printf("goodack seq 0x%x cdt 0x%x snduna 0x%x sndhiwat 0x%x\n", ! 240: seq, cdt, tpcb->tp_snduna, tpcb->tp_sndhiwat); ! 241: ENDDEBUG ! 242: IFTRACE(D_ACKRECV) ! 243: tptraceTPCB(TPPTgotack, ! 244: seq,cdt, tpcb->tp_snduna,tpcb->tp_sndhiwat,subseq); ! 245: ENDTRACE ! 246: ! 247: IFPERF(tpcb) ! 248: tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0); ! 249: ENDPERF ! 250: ! 251: if ( subseq != 0 && (subseq <= tpcb->tp_r_subseq) ) { ! 252: /* discard the ack */ ! 253: IFTRACE(D_ACKRECV) ! 254: tptraceTPCB(TPPTmisc, "goodack discard : subseq tp_r_subseq", ! 255: subseq, tpcb->tp_r_subseq, 0, 0); ! 256: ENDTRACE ! 257: return 0; ! 258: } else { ! 259: tpcb->tp_r_subseq = subseq; ! 260: } ! 261: ! 262: if ( IN_SWINDOW(tpcb, seq, ! 263: tpcb->tp_snduna, SEQ(tpcb, tpcb->tp_sndhiwat+1)) ) { ! 264: ! 265: IFDEBUG(D_XPD) ! 266: dump_mbuf(tpcb->tp_sock->so_snd.sb_mb, ! 267: "tp_goodack snd before sbdrop"); ! 268: ENDDEBUG ! 269: tp_sbdrop(tpcb, SEQ_SUB(tpcb, seq, 1) ); ! 270: ! 271: /* increase congestion window but don't let it get too big */ ! 272: { ! 273: register int maxcdt = tpcb->tp_xtd_format?0xffff:0xf; ! 274: CONG_ACK(tpcb, seq); ! 275: } ! 276: ! 277: /* Compute smoothed round trip time. ! 278: * Only measure rtt for tp_snduna if tp_snduna was among ! 279: * the last TP_RTT_NUM seq numbers sent, and if the data ! 280: * were not retransmitted. ! 281: */ ! 282: if (SEQ_GEQ(tpcb, tpcb->tp_snduna, ! 283: SEQ(tpcb, tpcb->tp_sndhiwat - TP_RTT_NUM)) ! 284: && SEQ_GT(tpcb, seq, SEQ_ADD(tpcb, tpcb->tp_retrans_hiwat, 1))) { ! 285: ! 286: struct timeval *t = &tpcb->tp_rttemit[tpcb->tp_snduna & TP_RTT_NUM]; ! 287: struct timeval x; ! 288: ! 289: GET_TIME_SINCE(t, &x); ! 290: ! 291: tp_rtt_rtv( &(tpcb->tp_rtt), &(tpcb->tp_rtv), &x ); ! 292: ! 293: { /* update the global rtt, rtv stats */ ! 294: register int i = ! 295: (int) tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN); ! 296: tp_rtt_rtv( &(tp_stat.ts_rtt[i]), &(tp_stat.ts_rtv[i]), &x ); ! 297: ! 298: IFTRACE(D_RTT) ! 299: tptraceTPCB(TPPTmisc, "Global rtt, rtv: i", i, 0, 0, 0); ! 300: ENDTRACE ! 301: } ! 302: ! 303: IFTRACE(D_RTT) ! 304: tptraceTPCB(TPPTmisc, ! 305: "Smoothed rtt: tp_snduna, (time.sec, time.usec), peer_acktime", ! 306: tpcb->tp_snduna, time.tv_sec, time.tv_usec, ! 307: tpcb->tp_peer_acktime); ! 308: ! 309: tptraceTPCB(TPPTmisc, ! 310: "(secs): emittime diff(x) rtt, rtv", ! 311: t->tv_sec, ! 312: x.tv_sec, ! 313: tpcb->tp_rtt.tv_sec, ! 314: tpcb->tp_rtv.tv_sec); ! 315: tptraceTPCB(TPPTmisc, ! 316: "(usecs): emittime diff(x) rtt rtv", ! 317: t->tv_usec, ! 318: x.tv_usec, ! 319: tpcb->tp_rtt.tv_usec, ! 320: tpcb->tp_rtv.tv_usec); ! 321: ENDTRACE ! 322: ! 323: { ! 324: /* Update data retransmission timer based on the smoothed ! 325: * round trip time, peer ack time, and the pseudo-arbitrary ! 326: * number 4. ! 327: * new ticks: avg rtt + 2*dev ! 328: * rtt, rtv are in microsecs, and ticks are 500 ms ! 329: * so 1 tick = 500*1000 us = 500000 us ! 330: * so ticks = (rtt + 2 rtv)/500000 ! 331: * with ticks no les than peer ack time and no less than 4 ! 332: */ ! 333: ! 334: int rtt = tpcb->tp_rtt.tv_usec + ! 335: tpcb->tp_rtt.tv_sec*1000000; ! 336: int rtv = tpcb->tp_rtv.tv_usec + ! 337: tpcb->tp_rtv.tv_sec*1000000; ! 338: ! 339: IFTRACE(D_RTT) ! 340: tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks", ! 341: tpcb->tp_dt_ticks, ! 342: rtv, rtt, ! 343: (rtt/500000 + (2 * rtv)/500000)); ! 344: ENDTRACE ! 345: tpcb->tp_dt_ticks = (rtt+ (2 * rtv))/500000; ! 346: tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks, ! 347: tpcb->tp_peer_acktime); ! 348: tpcb->tp_dt_ticks = MAX( tpcb->tp_dt_ticks, 4); ! 349: } ! 350: } ! 351: tpcb->tp_snduna = seq; ! 352: tpcb->tp_retrans = tpcb->tp_Nretrans; /* CE_BIT */ ! 353: ! 354: bang++; ! 355: } ! 356: ! 357: if( cdt != 0 && old_fcredit == 0 ) { ! 358: tpcb->tp_sendfcc = 1; ! 359: } ! 360: if( cdt == 0 && old_fcredit != 0 ) { ! 361: IncStat(ts_zfcdt); ! 362: } ! 363: tpcb->tp_fcredit = cdt; ! 364: ! 365: IFDEBUG(D_ACKRECV) ! 366: printf("goodack returning 0x%x, bang 0x%x cdt 0x%x old_fcredit 0x%x\n", ! 367: (bang || (old_fcredit < cdt) ), bang, cdt, old_fcredit ); ! 368: ENDDEBUG ! 369: ! 370: return (bang || (old_fcredit < cdt)) ; ! 371: } ! 372: ! 373: /* ! 374: * CALLED FROM: ! 375: * tp_goodack() ! 376: * FUNCTION and ARGUMENTS: ! 377: * drops everything up TO and INCLUDING seq # (seq) ! 378: * from the retransmission queue. ! 379: */ ! 380: static void ! 381: tp_sbdrop(tpcb, seq) ! 382: struct tp_pcb *tpcb; ! 383: SeqNum seq; ! 384: { ! 385: register struct tp_rtc *s = tpcb->tp_snduna_rtc; ! 386: ! 387: IFDEBUG(D_ACKRECV) ! 388: printf("tp_sbdrop up through seq 0x%x\n", seq); ! 389: ENDDEBUG ! 390: while (s != (struct tp_rtc *)0 && (SEQ_LEQ(tpcb, s->tprt_seq, seq))) { ! 391: m_freem( s->tprt_data ); ! 392: tpcb->tp_snduna_rtc = s->tprt_next; ! 393: (void) m_free( dtom( s ) ); ! 394: s = tpcb->tp_snduna_rtc; ! 395: } ! 396: if(tpcb->tp_snduna_rtc == (struct tp_rtc *)0) ! 397: tpcb->tp_sndhiwat_rtc = (struct tp_rtc *) 0; ! 398: ! 399: } ! 400: ! 401: /* ! 402: * CALLED FROM: ! 403: * tp.trans on user send request, arrival of AK and arrival of XAK ! 404: * FUNCTION and ARGUMENTS: ! 405: * Emits tpdus starting at sequence number (lowseq). ! 406: * Emits until a) runs out of data, or b) runs into an XPD mark, or ! 407: * c) it hits seq number (highseq) ! 408: * Removes the octets from the front of the socket buffer ! 409: * and repackages them in one mbuf chain per tpdu. ! 410: * Moves the mbuf chain to the doubly linked list that runs from ! 411: * tpcb->tp_sndhiwat_rtc to tpcb->tp_snduna_rtc. ! 412: * ! 413: * Creates tpdus that are no larger than <tpcb->tp_l_tpdusize - headersize>, ! 414: * ! 415: * If you want XPD to buffer > 1 du per socket buffer, you can ! 416: * modifiy this to issue XPD tpdus also, but then it'll have ! 417: * to take some argument(s) to distinguish between the type of DU to ! 418: * hand tp_emit, the socket buffer from which to get the data, and ! 419: * the chain of tp_rtc structures on which to put the data sent. ! 420: * ! 421: * When something is sent for the first time, its time-of-send ! 422: * is stashed (the last RTT_NUM of them are stashed). When the ! 423: * ack arrives, the smoothed round-trip time is figured using this value. ! 424: * RETURN VALUE: ! 425: * the highest seq # sent successfully. ! 426: */ ! 427: tp_send(tpcb) ! 428: register struct tp_pcb *tpcb; ! 429: { ! 430: register int len; ! 431: register struct mbuf *m; /* the one we're inspecting now */ ! 432: struct mbuf *mb;/* beginning of this tpdu */ ! 433: struct mbuf *nextrecord; /* NOT next tpdu but next sb record */ ! 434: struct sockbuf *sb = &tpcb->tp_sock->so_snd; ! 435: int maxsize = tpcb->tp_l_tpdusize ! 436: - tp_headersize(DT_TPDU_type, tpcb) ! 437: - (tpcb->tp_use_checksum?4:0) ; ! 438: unsigned int eotsdu_reached=0; ! 439: SeqNum lowseq, highseq ; ! 440: SeqNum lowsave; ! 441: #ifdef TP_PERF_MEAS ! 442: ! 443: struct timeval send_start_time; ! 444: IFPERF(tpcb) ! 445: GET_CUR_TIME(&send_start_time); ! 446: ENDPERF ! 447: #endif TP_PERF_MEAS ! 448: ! 449: lowsave = lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1); ! 450: ! 451: ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff); ! 452: ! 453: if( tpcb->tp_rx_strat & TPRX_USE_CW ) { ! 454: /*first hiseq is temp vbl*/ ! 455: highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win); ! 456: } else { ! 457: highseq = tpcb->tp_fcredit; ! 458: } ! 459: highseq = SEQ(tpcb, tpcb->tp_snduna + highseq); ! 460: ! 461: SEQ_DEC(tpcb, highseq); ! 462: ! 463: IFDEBUG(D_DATA) ! 464: printf( ! 465: "tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n", ! 466: tpcb, lowseq, highseq); ! 467: dump_mbuf(sb->sb_mb, "sb_mb:"); ! 468: ENDDEBUG ! 469: IFTRACE(D_DATA) ! 470: tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna", ! 471: lowsave, tpcb->tp_sndhiwat, tpcb->tp_snduna, 0); ! 472: tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin", ! 473: lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); ! 474: ENDTRACE ! 475: ! 476: ! 477: if ( SEQ_GT(tpcb, lowseq, highseq) ) ! 478: return ; /* don't send, don't change hiwat, don't set timers */ ! 479: ! 480: ASSERT( SEQ_LEQ(tpcb, lowseq, highseq) ); ! 481: SEQ_DEC(tpcb, lowseq); ! 482: ! 483: IFTRACE(D_DATA) ! 484: tptraceTPCB( TPPTmisc, "tp_send 2 low high fcredit congwin", ! 485: lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); ! 486: ENDTRACE ! 487: ! 488: while ((SEQ_LT(tpcb, lowseq, highseq)) && (mb = m = sb->sb_mb)) { ! 489: if (tpcb->tp_Xsnd.sb_mb) { ! 490: IFTRACE(D_XPD) ! 491: tptraceTPCB( TPPTmisc, ! 492: "tp_send XPD mark low high tpcb.Xuna", ! 493: lowseq, highseq, tpcb->tp_Xsnd.sb_mb, 0); ! 494: ENDTRACE ! 495: /* stop sending here because there are unacked XPD which were ! 496: * given to us before the next data were. ! 497: */ ! 498: IncStat(ts_xpd_intheway); ! 499: break; ! 500: } ! 501: eotsdu_reached = 0; ! 502: nextrecord = m->m_act; ! 503: for (len = 0; m; m = m->m_next) { ! 504: len += m->m_len; ! 505: if (m->m_flags & M_EOR) ! 506: eotsdu_reached = 1; ! 507: sbfree(sb, m); /* reduce counts in socket buffer */ ! 508: } ! 509: sb->sb_mb = nextrecord; ! 510: IFTRACE(D_STASH) ! 511: tptraceTPCB(TPPTmisc, "tp_send whole mbuf: m_len len maxsize", ! 512: 0, mb->m_len, len, maxsize); ! 513: ENDTRACE ! 514: ! 515: if ( len == 0 && !eotsdu_reached) { ! 516: /* THIS SHOULD NEVER HAPPEN! */ ! 517: ASSERT( 0 ); ! 518: goto done; ! 519: } ! 520: ! 521: /* If we arrive here one of the following holds: ! 522: * 1. We have exactly <maxsize> octets of whole mbufs, ! 523: * 2. We accumulated <maxsize> octets using partial mbufs, ! 524: * 3. We found an TPMT_EOT or an XPD mark ! 525: * 4. We hit the end of a chain through m_next. ! 526: * In this case, we'd LIKE to continue with the next record, ! 527: * but for the time being, for simplicity, we'll stop here. ! 528: * In all cases, m points to mbuf containing first octet to be ! 529: * sent in the tpdu AFTER the one we're going to send now, ! 530: * or else m is null. ! 531: * ! 532: * The chain we're working on now begins at mb and has length <len>. ! 533: */ ! 534: ! 535: IFTRACE(D_STASH) ! 536: tptraceTPCB( TPPTmisc, ! 537: "tp_send mcopy low high eotsdu_reached len", ! 538: lowseq, highseq, eotsdu_reached, len); ! 539: ENDTRACE ! 540: ! 541: /* make a copy - mb goes into the retransmission list ! 542: * while m gets emitted. m_copy won't copy a zero-length mbuf. ! 543: */ ! 544: if (len) { ! 545: if ((m = m_copy(mb, 0, len )) == MNULL) ! 546: goto done; ! 547: } else { ! 548: /* eotsdu reached */ ! 549: MGET(m, M_WAIT, TPMT_DATA); ! 550: if (m == MNULL) ! 551: goto done; ! 552: m->m_len = 0; ! 553: } ! 554: ! 555: SEQ_INC(tpcb,lowseq); /* it was decremented at the beginning */ ! 556: { ! 557: struct tp_rtc *t; ! 558: /* make an rtc and put it at the end of the chain */ ! 559: ! 560: TP_MAKE_RTC( t, lowseq, eotsdu_reached, mb, len, lowseq, ! 561: TPMT_SNDRTC); ! 562: t->tprt_next = (struct tp_rtc *)0; ! 563: ! 564: if ( tpcb->tp_sndhiwat_rtc != (struct tp_rtc *)0 ) ! 565: tpcb->tp_sndhiwat_rtc->tprt_next = t; ! 566: else { ! 567: ASSERT( tpcb->tp_snduna_rtc == (struct tp_rtc *)0 ); ! 568: tpcb->tp_snduna_rtc = t; ! 569: } ! 570: ! 571: tpcb->tp_sndhiwat_rtc = t; ! 572: } ! 573: ! 574: IFTRACE(D_DATA) ! 575: tptraceTPCB( TPPTmisc, ! 576: "tp_send emitting DT lowseq eotsdu_reached len", ! 577: lowseq, eotsdu_reached, len, 0); ! 578: ENDTRACE ! 579: if( tpcb->tp_sock->so_error = ! 580: tp_emit(DT_TPDU_type, tpcb, lowseq, eotsdu_reached, m) ) { ! 581: /* error */ ! 582: SEQ_DEC(tpcb, lowseq); ! 583: goto done; ! 584: } ! 585: /* set the transmit-time for computation of round-trip times */ ! 586: bcopy( (caddr_t)&time, ! 587: (caddr_t)&( tpcb->tp_rttemit[ lowseq & TP_RTT_NUM ] ), ! 588: sizeof(struct timeval)); ! 589: ! 590: } ! 591: ! 592: done: ! 593: #ifdef TP_PERF_MEAS ! 594: IFPERF(tpcb) ! 595: { ! 596: register int npkts; ! 597: struct timeval send_end_time; ! 598: register struct timeval *t; ! 599: ! 600: npkts = lowseq; ! 601: SEQ_INC(tpcb, npkts); ! 602: npkts = SEQ_SUB(tpcb, npkts, lowsave); ! 603: ! 604: if(npkts > 0) ! 605: tpcb->tp_Nwindow++; ! 606: ! 607: if (npkts > TP_PM_MAX) ! 608: npkts = TP_PM_MAX; ! 609: ! 610: GET_TIME_SINCE(&send_start_time, &send_end_time); ! 611: t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); ! 612: t->tv_sec = ! 613: SMOOTH( long, TP_RTT_ALPHA, t->tv_sec, send_end_time.tv_sec); ! 614: t->tv_usec = ! 615: SMOOTH( long, TP_RTT_ALPHA, t->tv_usec, send_end_time.tv_usec); ! 616: ! 617: if ( SEQ_LT(tpcb, lowseq, highseq) ) { ! 618: IncPStat(tpcb, tps_win_lim_by_data[npkts] ); ! 619: } else { ! 620: IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); ! 621: /* not true with congestion-window being used */ ! 622: } ! 623: tpmeas( tpcb->tp_lref, ! 624: TPsbsend, &send_end_time, lowsave, tpcb->tp_Nwindow, npkts); ! 625: } ! 626: ENDPERF ! 627: #endif TP_PERF_MEAS ! 628: ! 629: tpcb->tp_sndhiwat = lowseq; ! 630: ! 631: if ( SEQ_LEQ(tpcb, lowsave, tpcb->tp_sndhiwat) && ! 632: (tpcb->tp_class != TP_CLASS_0) ) ! 633: tp_etimeout(tpcb->tp_refp, TM_data_retrans, lowsave, ! 634: tpcb->tp_sndhiwat, ! 635: (u_int)tpcb->tp_Nretrans, (int)tpcb->tp_dt_ticks); ! 636: IFTRACE(D_DATA) ! 637: tptraceTPCB( TPPTmisc, ! 638: "tp_send at end: sndhiwat lowseq eotsdu_reached error", ! 639: tpcb->tp_sndhiwat, lowseq, eotsdu_reached, tpcb->tp_sock->so_error); ! 640: ! 641: ENDTRACE ! 642: } ! 643: ! 644: /* ! 645: * NAME: tp_stash() ! 646: * CALLED FROM: ! 647: * tp.trans on arrival of a DT tpdu ! 648: * FUNCTION, ARGUMENTS, and RETURN VALUE: ! 649: * Returns 1 if ! 650: * a) something new arrived and it's got eotsdu_reached bit on, ! 651: * b) this arrival was caused other out-of-sequence things to be ! 652: * accepted, or ! 653: * c) this arrival is the highest seq # for which we last gave credit ! 654: * (sender just sent a whole window) ! 655: * In other words, returns 1 if tp should send an ack immediately, 0 if ! 656: * the ack can wait a while. ! 657: * ! 658: * Note: this implementation no longer renegs on credit, (except ! 659: * when debugging option D_RENEG is on, for the purpose of testing ! 660: * ack subsequencing), so we don't need to check for incoming tpdus ! 661: * being in a reneged portion of the window. ! 662: */ ! 663: ! 664: int ! 665: tp_stash( tpcb, e ) ! 666: register struct tp_pcb *tpcb; ! 667: register struct tp_event *e; ! 668: { ! 669: register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; ! 670: /* 0--> delay acks until full window */ ! 671: /* 1--> ack each tpdu */ ! 672: int newrec = 0; ! 673: ! 674: #ifndef lint ! 675: #define E e->ATTR(DT_TPDU) ! 676: #else lint ! 677: #define E e->ev_union.EV_DT_TPDU ! 678: #endif lint ! 679: ! 680: if ( E.e_eot ) { ! 681: register struct mbuf *n = E.e_data; ! 682: n->m_flags |= M_EOR; ! 683: n->m_act = 0; ! 684: } ! 685: IFDEBUG(D_STASH) ! 686: dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, ! 687: "stash: so_rcv before appending"); ! 688: dump_mbuf(E.e_data, ! 689: "stash: e_data before appending"); ! 690: ENDDEBUG ! 691: ! 692: IFPERF(tpcb) ! 693: PStat(tpcb, Nb_from_ll) += E.e_datalen; ! 694: tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, ! 695: E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); ! 696: ENDPERF ! 697: ! 698: if( E.e_seq == tpcb->tp_rcvnxt ) { ! 699: ! 700: IFDEBUG(D_STASH) ! 701: printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", ! 702: E.e_seq, E.e_datalen, E.e_eot); ! 703: ENDDEBUG ! 704: ! 705: IFTRACE(D_STASH) ! 706: tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", ! 707: E.e_seq, E.e_datalen, E.e_eot, 0); ! 708: ENDTRACE ! 709: ! 710: sbappend(&tpcb->tp_sock->so_rcv, E.e_data); ! 711: ! 712: if (newrec = E.e_eot ) /* ASSIGNMENT */ ! 713: ack_reason |= ACK_EOT; ! 714: ! 715: SEQ_INC( tpcb, tpcb->tp_rcvnxt ); ! 716: /* ! 717: * move chains from the rtc list to the socket buffer ! 718: * and free the rtc header ! 719: */ ! 720: { ! 721: register struct tp_rtc **r = &tpcb->tp_rcvnxt_rtc; ! 722: register struct tp_rtc *s = tpcb->tp_rcvnxt_rtc; ! 723: ! 724: while (s != (struct tp_rtc *)0 && s->tprt_seq == tpcb->tp_rcvnxt) { ! 725: *r = s->tprt_next; ! 726: ! 727: sbappend(&tpcb->tp_sock->so_rcv, s->tprt_data); ! 728: ! 729: SEQ_INC( tpcb, tpcb->tp_rcvnxt ); ! 730: ! 731: (void) m_free( dtom( s ) ); ! 732: s = *r; ! 733: ack_reason |= ACK_REORDER; ! 734: } ! 735: } ! 736: IFDEBUG(D_STASH) ! 737: dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, ! 738: "stash: so_rcv after appending"); ! 739: ENDDEBUG ! 740: ! 741: } else { ! 742: register struct tp_rtc **s = &tpcb->tp_rcvnxt_rtc; ! 743: register struct tp_rtc *r = tpcb->tp_rcvnxt_rtc; ! 744: register struct tp_rtc *t; ! 745: ! 746: IFTRACE(D_STASH) ! 747: tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", ! 748: E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); ! 749: ENDTRACE ! 750: ! 751: r = tpcb->tp_rcvnxt_rtc; ! 752: while (r != (struct tp_rtc *)0 && SEQ_LT(tpcb, r->tprt_seq, E.e_seq)) { ! 753: s = &r->tprt_next; ! 754: r = r->tprt_next; ! 755: } ! 756: ! 757: if (r == (struct tp_rtc *)0 || SEQ_GT(tpcb, r->tprt_seq, E.e_seq) ) { ! 758: IncStat(ts_dt_ooo); ! 759: ! 760: IFTRACE(D_STASH) ! 761: tptrace(TPPTmisc, ! 762: "tp_stash OUT OF ORDER- MAKE RTC: seq, 1st seq in list\n", ! 763: E.e_seq, r->tprt_seq,0,0); ! 764: ENDTRACE ! 765: IFDEBUG(D_STASH) ! 766: printf("tp_stash OUT OF ORDER- MAKE RTC\n"); ! 767: ENDDEBUG ! 768: TP_MAKE_RTC(t, E.e_seq, E.e_eot, E.e_data, E.e_datalen, 0, ! 769: TPMT_RCVRTC); ! 770: ! 771: *s = t; ! 772: t->tprt_next = (struct tp_rtc *)r; ! 773: ack_reason = ACK_DONT; ! 774: goto done; ! 775: } else { ! 776: IFDEBUG(D_STASH) ! 777: printf("tp_stash - drop & ack\n"); ! 778: ENDDEBUG ! 779: ! 780: /* retransmission - drop it and force an ack */ ! 781: IncStat(ts_dt_dup); ! 782: IFPERF(tpcb) ! 783: IncPStat(tpcb, tps_n_ack_cuz_dup); ! 784: ENDPERF ! 785: ! 786: m_freem( E.e_data ); ! 787: ack_reason |= ACK_DUP; ! 788: goto done; ! 789: } ! 790: } ! 791: ! 792: ! 793: /* ! 794: * an ack should be sent when at least one of the ! 795: * following holds: ! 796: * a) we've received a TPDU with EOTSDU set ! 797: * b) the TPDU that just arrived represents the ! 798: * full window last advertised, or ! 799: * c) when seq X arrives [ where ! 800: * X = last_sent_uwe - 1/2 last_lcredit_sent ! 801: * (the packet representing 1/2 the last advertised window) ] ! 802: * and lcredit at the time of X arrival > last_lcredit_sent/2 ! 803: * In other words, if the last ack sent advertised cdt=8 and uwe = 8 ! 804: * then when seq 4 arrives I'd like to send a new ack ! 805: * iff the credit at the time of 4's arrival is > 4. ! 806: * The other end thinks it has cdt of 4 so if local cdt ! 807: * is still 4 there's no point in sending an ack, but if ! 808: * my credit has increased because the receiver has taken ! 809: * some data out of the buffer (soreceive doesn't notify ! 810: * me until the SYSTEM CALL finishes), I'd like to tell ! 811: * the other end. ! 812: */ ! 813: ! 814: done: ! 815: { ! 816: LOCAL_CREDIT(tpcb); ! 817: ! 818: if ( E.e_seq == tpcb->tp_sent_uwe ) ! 819: ack_reason |= ACK_STRAT_FULLWIN; ! 820: ! 821: IFTRACE(D_STASH) ! 822: tptraceTPCB(TPPTmisc, ! 823: "end of stash, eot, ack_reason, sent_uwe ", ! 824: E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); ! 825: ENDTRACE ! 826: ! 827: if ( ack_reason == ACK_DONT ) { ! 828: IncStat( ts_ackreason[ACK_DONT] ); ! 829: return 0; ! 830: } else { ! 831: IFPERF(tpcb) ! 832: if(ack_reason & ACK_EOT) { ! 833: IncPStat(tpcb, tps_n_ack_cuz_eot); ! 834: } ! 835: if(ack_reason & ACK_STRAT_EACH) { ! 836: IncPStat(tpcb, tps_n_ack_cuz_strat); ! 837: } else if(ack_reason & ACK_STRAT_FULLWIN) { ! 838: IncPStat(tpcb, tps_n_ack_cuz_fullwin); ! 839: } else if(ack_reason & ACK_REORDER) { ! 840: IncPStat(tpcb, tps_n_ack_cuz_reorder); ! 841: } ! 842: tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, ! 843: SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); ! 844: ENDPERF ! 845: { ! 846: register int i; ! 847: ! 848: /* keep track of all reasons that apply */ ! 849: for( i=1; i<_ACK_NUM_REASONS_ ;i++) { ! 850: if( ack_reason & (1<<i) ) ! 851: IncStat( ts_ackreason[i] ); ! 852: } ! 853: } ! 854: return 1; ! 855: } ! 856: } ! 857: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.