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