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