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.14 (Berkeley) 09/17/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 #include "kernel.h" 60 61 #include "tp_ip.h" 62 #include "iso.h" 63 #include "argo_debug.h" 64 #include "tp_timer.h" 65 #include "tp_param.h" 66 #include "tp_stat.h" 67 #include "tp_pcb.h" 68 #include "tp_tpdu.h" 69 #include "tp_trace.h" 70 #include "tp_meas.h" 71 #include "tp_seq.h" 72 73 int tp_emit(), tp_sbdrop(); 74 75 /* 76 * CALLED FROM: 77 * tp.trans, when an XAK arrives 78 * FUNCTION and ARGUMENTS: 79 * Determines if the sequence number (seq) from the XAK 80 * acks anything new. If so, drop the appropriate tpdu 81 * from the XPD send queue. 82 * RETURN VALUE: 83 * Returns 1 if it did this, 0 if the ack caused no action. 84 */ 85 int 86 tp_goodXack(tpcb, seq) 87 struct tp_pcb *tpcb; 88 SeqNum seq; 89 { 90 91 IFTRACE(D_XPD) 92 tptraceTPCB(TPPTgotXack, 93 seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndhiwat, 94 tpcb->tp_snduna); 95 ENDTRACE 96 97 if ( seq == tpcb->tp_Xuna ) { 98 tpcb->tp_Xuna = tpcb->tp_Xsndnxt; 99 100 /* DROP 1 packet from the Xsnd socket buf - just so happens 101 * that only one packet can be there at any time 102 * so drop the whole thing. If you allow > 1 packet 103 * the socket buffer, then you'll have to keep 104 * track of how many characters went w/ each XPD tpdu, so this 105 * will get messier 106 */ 107 IFDEBUG(D_XPD) 108 dump_mbuf(tpcb->tp_Xsnd.sb_mb, 109 "tp_goodXack Xsnd before sbdrop"); 110 ENDDEBUG 111 112 IFTRACE(D_XPD) 113 tptraceTPCB(TPPTmisc, 114 "goodXack: dropping cc ", 115 (int)(tpcb->tp_Xsnd.sb_cc), 116 0,0,0); 117 ENDTRACE 118 sbdrop( &tpcb->tp_Xsnd, (int)(tpcb->tp_Xsnd.sb_cc)); 119 CONG_ACK(tpcb, seq); 120 return 1; 121 } 122 return 0; 123 } 124 125 /* 126 * CALLED FROM: 127 * tp_good_ack() 128 * FUNCTION and ARGUMENTS: 129 * updates 130 * smoothed average round trip time (*rtt) 131 * roundtrip time variance (*rtv) - actually deviation, not variance 132 * given the new value (diff) 133 * RETURN VALUE: 134 * void 135 */ 136 137 void 138 tp_rtt_rtv( rtt, rtv, newmeas ) 139 register int *rtt, *rtv; 140 int newmeas; 141 { 142 int delta = newmeas - *rtt; 143 144 if ((*rtt += (delta >> TP_RTT_ALPHA)) <= 0) 145 *rtt = 1; 146 if (delta < 0) 147 delta = -delta; 148 if (*rtv = ((delta - *rtv) >> TP_RTV_ALPHA) <= 0) 149 *rtv = 1; 150 } 151 152 /* 153 * CALLED FROM: 154 * tp.trans when an AK arrives 155 * FUNCTION and ARGUMENTS: 156 * Given (cdt), the credit from the AK tpdu, and 157 * (seq), the sequence number from the AK tpdu, 158 * tp_goodack() determines if the AK acknowledges something in the send 159 * window, and if so, drops the appropriate packets from the retransmission 160 * list, computes the round trip time, and updates the retransmission timer 161 * based on the new smoothed round trip time. 162 * RETURN VALUE: 163 * Returns 1 if 164 * EITHER it actually acked something heretofore unacknowledged 165 * OR no news but the credit should be processed. 166 * If something heretofore unacked was acked with this sequence number, 167 * the appropriate tpdus are dropped from the retransmission control list, 168 * by calling tp_sbdrop(). 169 * No need to see the tpdu itself. 170 */ 171 int 172 tp_goodack(tpcb, cdt, seq, subseq) 173 register struct tp_pcb *tpcb; 174 u_int cdt; 175 register SeqNum seq, subseq; 176 { 177 int old_fcredit = tpcb->tp_fcredit; 178 int bang = 0; /* bang --> ack for something heretofore unacked */ 179 180 IFDEBUG(D_ACKRECV) 181 printf("goodack seq 0x%x cdt 0x%x snduna 0x%x sndhiwat 0x%x\n", 182 seq, cdt, tpcb->tp_snduna, tpcb->tp_sndhiwat); 183 ENDDEBUG 184 IFTRACE(D_ACKRECV) 185 tptraceTPCB(TPPTgotack, 186 seq,cdt, tpcb->tp_snduna,tpcb->tp_sndhiwat,subseq); 187 ENDTRACE 188 189 IFPERF(tpcb) 190 tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0); 191 ENDPERF 192 193 if ( subseq != 0 && (subseq <= tpcb->tp_r_subseq) ) { 194 /* discard the ack */ 195 IFTRACE(D_ACKRECV) 196 tptraceTPCB(TPPTmisc, "goodack discard : subseq tp_r_subseq", 197 subseq, tpcb->tp_r_subseq, 0, 0); 198 ENDTRACE 199 return 0; 200 } else { 201 tpcb->tp_r_subseq = subseq; 202 } 203 204 if ( IN_SWINDOW(tpcb, seq, 205 tpcb->tp_snduna, SEQ(tpcb, tpcb->tp_sndhiwat+1)) ) { 206 207 IFDEBUG(D_XPD) 208 dump_mbuf(tpcb->tp_sock->so_snd.sb_mb, 209 "tp_goodack snd before sbdrop"); 210 ENDDEBUG 211 tpsbcheck(tpcb, 0); 212 (void)tp_sbdrop(tpcb, seq); 213 tpsbcheck(tpcb, 1); 214 215 /* increase congestion window but don't let it get too big */ 216 { 217 register int maxcdt = tpcb->tp_xtd_format?0xffff:0xf; 218 CONG_ACK(tpcb, seq); 219 } 220 221 /* Compute smoothed round trip time. 222 * Only measure rtt for tp_snduna if acked and the data 223 * were not retransmitted. 224 */ 225 if (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq)) { 226 int x = tick - tpcb->tp_rttemit; 227 228 if (tpcb->tp_rtt) 229 tp_rtt_rtv(&(tpcb->tp_rtt), &(tpcb->tp_rtv), x); 230 else { 231 tpcb->tp_rtt = x; 232 tpcb->tp_rtv = x >> 1; 233 } 234 235 { /* update the global rtt, rtv stats */ 236 int i = tpcb->tp_flags & (TPF_PEER_ON_SAMENET | TPF_NLQOS_PDN); 237 tp_rtt_rtv(tp_stat.ts_rtt + i, tp_stat.ts_rtv + i, x); 238 239 IFTRACE(D_RTT) 240 tptraceTPCB(TPPTmisc, "Global rtt, rtv: i", i, 0, 0, 0); 241 ENDTRACE 242 } 243 244 IFTRACE(D_RTT) 245 tptraceTPCB(TPPTmisc, 246 "Smoothed rtt: tp_snduna, (time.sec, time.usec), peer_acktime", 247 tpcb->tp_snduna, time.tv_sec, time.tv_usec, 248 tpcb->tp_peer_acktime); 249 250 tptraceTPCB(TPPTmisc, 251 "(secs): emittime diff(x) rtt, rtv", 252 tpcb->tp_rttemit, x, tpcb->tp_rtt, tpcb->tp_rtv); 253 ENDTRACE 254 255 { 256 /* Update data retransmission timer based on the smoothed 257 * round trip time, peer ack time, and the pseudo-arbitrary 258 * number 2. 259 * new ticks: (avg rtt + 4*dev) 260 * rtt, rtv are in hz-ticks, 261 * and slowtimo-ticks are hz / 2; 262 * We want no less than peer ack time and no less than 2 263 */ 264 265 266 int rtt = tpcb->tp_rtt, rtv = tpcb->tp_rtv, 267 old = tpcb->tp_dt_ticks, new; 268 269 new = (((rtt + (rtv << 2)) << 1) + hz) / hz; 270 new = MAX(new + 1, old); 271 new = MAX(new, tpcb->tp_peer_acktime); 272 new = MAX(new, 2); 273 IFTRACE(D_RTT) 274 tptraceTPCB(TPPTmisc, "oldticks ,rtv, rtt, newticks", 275 old, rtv, rtt, new); 276 ENDTRACE 277 tpcb->tp_dt_ticks = new; 278 } 279 tpcb->tp_rxtcur = tpcb->tp_dt_ticks; 280 tpcb->tp_rxtshift = 0; 281 282 } 283 tpcb->tp_snduna = seq; 284 tpcb->tp_retrans = tpcb->tp_Nretrans; /* CE_BIT */ 285 286 bang++; 287 } 288 289 if( cdt != 0 && old_fcredit == 0 ) { 290 tpcb->tp_sendfcc = 1; 291 } 292 if( cdt == 0 && old_fcredit != 0 ) { 293 IncStat(ts_zfcdt); 294 } 295 tpcb->tp_fcredit = cdt; 296 297 IFDEBUG(D_ACKRECV) 298 printf("goodack returning 0x%x, bang 0x%x cdt 0x%x old_fcredit 0x%x\n", 299 (bang || (old_fcredit < cdt) ), bang, cdt, old_fcredit ); 300 ENDDEBUG 301 302 return (bang || (old_fcredit < cdt)) ; 303 } 304 305 /* 306 * CALLED FROM: 307 * tp_goodack() 308 * FUNCTION and ARGUMENTS: 309 * drops everything up TO but not INCLUDING seq # (seq) 310 * from the retransmission queue. 311 */ 312 tp_sbdrop(tpcb, seq) 313 register struct tp_pcb *tpcb; 314 SeqNum seq; 315 { 316 struct sockbuf *sb = &tpcb->tp_sock->so_snd; 317 register int i = ((int)seq)-((int)tpcb->tp_snduna); 318 int oldcc = sb->sb_cc; 319 320 if (i < 0) i += tpcb->tp_seqhalf; 321 IFDEBUG(D_ACKRECV) 322 printf("tp_sbdroping %d up through seq 0x%x\n", i, seq); 323 ENDDEBUG 324 while (i-- > 0) 325 sbdroprecord(sb); 326 if (SEQ_LT(tpcb, tpcb->tp_sndhiwat, seq)) 327 tpcb->tp_sndhiwat_m = 0; 328 return (oldcc - sb->sb_cc); 329 } 330 331 /* 332 * CALLED FROM: 333 * tp.trans on user send request, arrival of AK and arrival of XAK 334 * FUNCTION and ARGUMENTS: 335 * Emits tpdus starting at sequence number (lowseq). 336 * Emits until a) runs out of data, or b) runs into an XPD mark, or 337 * c) it hits seq number (highseq) 338 * 339 * If you want XPD to buffer > 1 du per socket buffer, you can 340 * modifiy this to issue XPD tpdus also, but then it'll have 341 * to take some argument(s) to distinguish between the type of DU to 342 * hand tp_emit. 343 * 344 * When something is sent for the first time, its time-of-send 345 * is stashed (the last RTT_NUM of them are stashed). When the 346 * ack arrives, the smoothed round-trip time is figured using this value. 347 * RETURN VALUE: 348 * the highest seq # sent successfully. 349 */ 350 tp_send(tpcb) 351 register struct tp_pcb *tpcb; 352 { 353 register int len; 354 register struct mbuf *m; /* the one we're inspecting now */ 355 struct mbuf *mb;/* beginning of this tpdu */ 356 struct mbuf *nextrecord; /* NOT next tpdu but next sb record */ 357 struct sockbuf *sb = &tpcb->tp_sock->so_snd; 358 unsigned int eotsdu_reached=0; 359 SeqNum lowseq, highseq ; 360 SeqNum lowsave; 361 #ifdef TP_PERF_MEAS 362 363 int send_start_time = tick; 364 #endif TP_PERF_MEAS 365 366 lowsave = lowseq = SEQ(tpcb, tpcb->tp_sndhiwat + 1); 367 368 ASSERT( tpcb->tp_cong_win > 0 && tpcb->tp_cong_win < 0xffff); 369 370 if( tpcb->tp_rx_strat & TPRX_USE_CW ) { 371 /*first hiseq is temp vbl*/ 372 highseq = MIN(tpcb->tp_fcredit, tpcb->tp_cong_win); 373 } else { 374 highseq = tpcb->tp_fcredit; 375 } 376 highseq = SEQ(tpcb, tpcb->tp_snduna + highseq); 377 378 SEQ_DEC(tpcb, highseq); 379 380 IFDEBUG(D_DATA) 381 printf( 382 "tp_send enter tpcb 0x%x l %d -> h %d\ndump of sb_mb:\n", 383 tpcb, lowseq, highseq); 384 dump_mbuf(sb->sb_mb, "sb_mb:"); 385 ENDDEBUG 386 IFTRACE(D_DATA) 387 tptraceTPCB( TPPTmisc, "tp_send lowsave sndhiwat snduna", 388 lowsave, tpcb->tp_sndhiwat, tpcb->tp_snduna, 0); 389 tptraceTPCB( TPPTmisc, "tp_send low high fcredit congwin", 390 lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); 391 ENDTRACE 392 393 394 if ( SEQ_GT(tpcb, lowseq, highseq) ) 395 return ; /* don't send, don't change hiwat, don't set timers */ 396 397 ASSERT( SEQ_LEQ(tpcb, lowseq, highseq) ); 398 SEQ_DEC(tpcb, lowseq); 399 400 if (tpcb->tp_Xsnd.sb_mb) { 401 IFTRACE(D_XPD) 402 tptraceTPCB( TPPTmisc, 403 "tp_send XPD mark low high tpcb.Xuna", 404 lowseq, highseq, tpcb->tp_Xsnd.sb_mb, 0); 405 ENDTRACE 406 /* stop sending here because there are unacked XPD present 407 */ 408 IncStat(ts_xpd_intheway); 409 goto done; 410 } 411 IFTRACE(D_DATA) 412 tptraceTPCB( TPPTmisc, "tp_send 2 low high fcredit congwin", 413 lowseq, highseq, tpcb->tp_fcredit, tpcb->tp_cong_win); 414 ENDTRACE 415 416 if (m = tpcb->tp_sndhiwat_m) 417 mb = m->m_nextpkt; 418 else 419 mb = sb->sb_mb; 420 while ((SEQ_LT(tpcb, lowseq, highseq)) && mb ) { 421 422 /* 423 * In all cases, m points to mbuf containing first octet to be 424 * sent in the tpdu AFTER the one we're going to send now, 425 * or else m is null. 426 * 427 * The chain we're working on now begins at mb and has length <len>. 428 */ 429 430 eotsdu_reached = (mb->m_flags & M_EOR) != 0; 431 len = mb->m_pkthdr.len; 432 IFTRACE(D_STASH) 433 tptraceTPCB( TPPTmisc, 434 "tp_send mcopy low high eotsdu_reached len", 435 lowseq, highseq, eotsdu_reached, len); 436 ENDTRACE 437 438 /* make a copy - mb goes into the retransmission list 439 * while m gets emitted. m_copy won't copy a zero-length mbuf. 440 */ 441 m = m_copy(mb, 0, M_COPYALL); 442 if (m == MNULL) 443 goto done; 444 SEQ_INC(tpcb,lowseq); /* it was decremented at the beginning */ 445 IFTRACE(D_DATA) 446 tptraceTPCB( TPPTmisc, 447 "tp_send emitting DT lowseq eotsdu_reached len", 448 lowseq, eotsdu_reached, len, 0); 449 ENDTRACE 450 if (mb->m_nextpkt == 0 && tpcb->tp_oktonagle) { 451 SEQ_INC(tpcb, tpcb->tp_sndnum); 452 tpcb->tp_oktonagle = 0; 453 /* when headers are precomputed, may need to fill 454 in checksum here */ 455 } 456 if (tpcb->tp_sock->so_error = 457 tp_emit(DT_TPDU_type, tpcb, lowseq, eotsdu_reached, m)) { 458 /* error */ 459 SEQ_DEC(tpcb, lowseq); 460 goto done; 461 } 462 /* set the transmit-time for computation of round-trip times */ 463 if (tpcb->tp_rttemit == 0) { 464 tpcb->tp_rttemit = tick; 465 tpcb->tp_rttseq = lowseq; 466 } 467 tpcb->tp_sndhiwat_m = mb; 468 mb = mb->m_nextpkt; 469 } 470 471 done: 472 #ifdef TP_PERF_MEAS 473 IFPERF(tpcb) 474 { 475 register int npkts; 476 int elapsed = tick - send_start_time, *t; 477 struct timeval now; 478 479 npkts = lowseq; 480 SEQ_INC(tpcb, npkts); 481 npkts = SEQ_SUB(tpcb, npkts, lowsave); 482 483 if(npkts > 0) 484 tpcb->tp_Nwindow++; 485 486 if (npkts > TP_PM_MAX) 487 npkts = TP_PM_MAX; 488 489 t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); 490 *t += (t - elapsed) >> TP_RTT_ALPHA; 491 492 if ( SEQ_LT(tpcb, lowseq, highseq) ) { 493 IncPStat(tpcb, tps_win_lim_by_data[npkts] ); 494 } else { 495 IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); 496 /* not true with congestion-window being used */ 497 } 498 now.tv_sec = elapsed / hz; 499 now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz; 500 tpmeas( tpcb->tp_lref, 501 TPsbsend, &elapsed, lowsave, tpcb->tp_Nwindow, npkts); 502 } 503 ENDPERF 504 #endif TP_PERF_MEAS 505 506 tpcb->tp_sndhiwat = lowseq; 507 508 if ( SEQ_LEQ(tpcb, lowsave, tpcb->tp_sndhiwat) && 509 (tpcb->tp_class != TP_CLASS_0) ) 510 tp_etimeout(tpcb->tp_refp, TM_data_retrans, lowsave, 511 tpcb->tp_sndhiwat, 512 (u_int)tpcb->tp_Nretrans, (int)tpcb->tp_dt_ticks); 513 IFTRACE(D_DATA) 514 tptraceTPCB( TPPTmisc, 515 "tp_send at end: sndhiwat lowseq eotsdu_reached error", 516 tpcb->tp_sndhiwat, lowseq, eotsdu_reached, tpcb->tp_sock->so_error); 517 518 ENDTRACE 519 } 520 521 int TPNagleok; 522 int TPNagled; 523 524 tp_packetize(tpcb, m, eotsdu) 525 register struct tp_pcb *tpcb; 526 register struct mbuf *m; 527 int eotsdu; 528 { 529 register struct mbuf *n; 530 register struct sockbuf *sb = &tpcb->tp_sock->so_snd; 531 int maxsize = tpcb->tp_l_tpdusize 532 - tp_headersize(DT_TPDU_type, tpcb) 533 - (tpcb->tp_use_checksum?4:0) ; 534 int totlen = m->m_pkthdr.len; 535 struct mbuf *m_split(); 536 /* 537 * Pre-packetize the data in the sockbuf 538 * according to negotiated mtu. Do it here 539 * where we can safely wait for mbufs. 540 * 541 * This presumes knowledge of sockbuf conventions. 542 * TODO: allocate space for header and fill it in (once!). 543 */ 544 IFTRACE(D_DATA) 545 tptraceTPCB(TPPTmisc, 546 "SEND BF: maxsize totlen eotsdu", 547 maxsize, totlen, eotsdu, 0); 548 ENDTRACE 549 if (tpcb->tp_oktonagle) { 550 if ((n = sb->sb_mb) == 0) 551 panic("tp_packetize"); 552 while (n->m_act) 553 n = n->m_act; 554 if (n->m_flags & M_EOR) 555 panic("tp_packetize 2"); 556 SEQ_INC(tpcb, tpcb->tp_sndnum); 557 if (totlen + n->m_pkthdr.len < maxsize) { 558 /* There is an unsent packet with space, combine data */ 559 struct mbuf *old_n = n; 560 tpsbcheck(tpcb,3); 561 n->m_pkthdr.len += totlen; 562 while (n->m_next) 563 n = n->m_next; 564 sbcompress(sb, m, n); 565 tpsbcheck(tpcb,4); 566 n = old_n; 567 TPNagled++; 568 goto out; 569 } 570 } 571 while (m) { 572 n = m; 573 if (totlen > maxsize) { 574 if ((m = m_split(n, maxsize, M_WAIT)) == 0) 575 panic("tp_packetize"); 576 } else 577 m = 0; 578 totlen -= maxsize; 579 tpsbcheck(tpcb, 5); 580 sbappendrecord(sb, n); 581 tpsbcheck(tpcb, 6); 582 SEQ_INC(tpcb, tpcb->tp_sndnum); 583 } 584 out: 585 if (eotsdu) { 586 n->m_flags |= M_EOR; /* XXX belongs at end */ 587 tpcb->tp_oktonagle = 0; 588 } else { 589 SEQ_DEC(tpcb, tpcb->tp_sndnum); 590 tpcb->tp_oktonagle = 1; 591 TPNagleok++; 592 } 593 return 0; 594 } 595 596 597 /* 598 * NAME: tp_stash() 599 * CALLED FROM: 600 * tp.trans on arrival of a DT tpdu 601 * FUNCTION, ARGUMENTS, and RETURN VALUE: 602 * Returns 1 if 603 * a) something new arrived and it's got eotsdu_reached bit on, 604 * b) this arrival was caused other out-of-sequence things to be 605 * accepted, or 606 * c) this arrival is the highest seq # for which we last gave credit 607 * (sender just sent a whole window) 608 * In other words, returns 1 if tp should send an ack immediately, 0 if 609 * the ack can wait a while. 610 * 611 * Note: this implementation no longer renegs on credit, (except 612 * when debugging option D_RENEG is on, for the purpose of testing 613 * ack subsequencing), so we don't need to check for incoming tpdus 614 * being in a reneged portion of the window. 615 */ 616 617 tp_stash( tpcb, e ) 618 register struct tp_pcb *tpcb; 619 register struct tp_event *e; 620 { 621 register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; 622 /* 0--> delay acks until full window */ 623 /* 1--> ack each tpdu */ 624 #ifndef lint 625 #define E e->ATTR(DT_TPDU) 626 #else lint 627 #define E e->ev_union.EV_DT_TPDU 628 #endif lint 629 630 if ( E.e_eot ) { 631 register struct mbuf *n = E.e_data; 632 n->m_flags |= M_EOR; 633 n->m_act = 0; 634 } 635 IFDEBUG(D_STASH) 636 dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 637 "stash: so_rcv before appending"); 638 dump_mbuf(E.e_data, 639 "stash: e_data before appending"); 640 ENDDEBUG 641 642 IFPERF(tpcb) 643 PStat(tpcb, Nb_from_ll) += E.e_datalen; 644 tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, 645 E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); 646 ENDPERF 647 648 if (E.e_seq == tpcb->tp_rcvnxt) { 649 650 IFDEBUG(D_STASH) 651 printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", 652 E.e_seq, E.e_datalen, E.e_eot); 653 ENDDEBUG 654 655 IFTRACE(D_STASH) 656 tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", 657 E.e_seq, E.e_datalen, E.e_eot, 0); 658 ENDTRACE 659 660 SET_DELACK(tpcb); 661 662 sbappend(&tpcb->tp_sock->so_rcv, E.e_data); 663 664 SEQ_INC( tpcb, tpcb->tp_rcvnxt ); 665 /* 666 * move chains from the reassembly queue to the socket buffer 667 */ 668 if (tpcb->tp_rsycnt) { 669 register struct mbuf **mp; 670 struct mbuf **mplim; 671 672 mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit); 673 mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit; 674 675 while (tpcb->tp_rsycnt && *mp) { 676 sbappend(&tpcb->tp_sock->so_rcv, *mp); 677 tpcb->tp_rsycnt--; 678 *mp = 0; 679 SEQ_INC(tpcb, tpcb->tp_rcvnxt); 680 ack_reason |= ACK_REORDER; 681 if (++mp == mplim) 682 mp = tpcb->tp_rsyq; 683 } 684 } 685 IFDEBUG(D_STASH) 686 dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, 687 "stash: so_rcv after appending"); 688 ENDDEBUG 689 690 } else { 691 register struct mbuf **mp; 692 SeqNum uwe; 693 694 IFTRACE(D_STASH) 695 tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", 696 E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); 697 ENDTRACE 698 699 if (tpcb->tp_rsyq == 0) 700 tp_rsyset(tpcb); 701 uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit); 702 if (tpcb->tp_rsyq == 0 || 703 !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) { 704 ack_reason = ACK_DONT; 705 m_freem(E.e_data); 706 } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) { 707 IFDEBUG(D_STASH) 708 printf("tp_stash - drop & ack\n"); 709 ENDDEBUG 710 711 /* retransmission - drop it and force an ack */ 712 IncStat(ts_dt_dup); 713 IFPERF(tpcb) 714 IncPStat(tpcb, tps_n_ack_cuz_dup); 715 ENDPERF 716 717 m_freem(E.e_data); 718 ack_reason |= ACK_DUP; 719 } else { 720 *mp = E.e_data; 721 tpcb->tp_rsycnt++; 722 ack_reason = ACK_DONT; 723 } 724 } 725 /* there were some comments of historical interest here. */ 726 { 727 LOCAL_CREDIT(tpcb); 728 729 if ( E.e_seq == tpcb->tp_sent_uwe ) 730 ack_reason |= ACK_STRAT_FULLWIN; 731 732 IFTRACE(D_STASH) 733 tptraceTPCB(TPPTmisc, 734 "end of stash, eot, ack_reason, sent_uwe ", 735 E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); 736 ENDTRACE 737 738 if ( ack_reason == ACK_DONT ) { 739 IncStat( ts_ackreason[ACK_DONT] ); 740 return 0; 741 } else { 742 IFPERF(tpcb) 743 if(ack_reason & ACK_STRAT_EACH) { 744 IncPStat(tpcb, tps_n_ack_cuz_strat); 745 } else if(ack_reason & ACK_STRAT_FULLWIN) { 746 IncPStat(tpcb, tps_n_ack_cuz_fullwin); 747 } else if(ack_reason & ACK_REORDER) { 748 IncPStat(tpcb, tps_n_ack_cuz_reorder); 749 } 750 tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, 751 SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); 752 ENDPERF 753 { 754 register int i; 755 756 /* keep track of all reasons that apply */ 757 for( i=1; i<_ACK_NUM_REASONS_ ;i++) { 758 if( ack_reason & (1<<i) ) 759 IncStat( ts_ackreason[i] ); 760 } 761 } 762 return 1; 763 } 764 } 765 } 766 767 /* 768 * tp_rsyflush - drop all the packets on the reassembly queue. 769 * Do this when closing the socket, or when somebody has changed 770 * the space avaible in the receive socket (XXX). 771 */ 772 tp_rsyflush(tpcb) 773 register struct tp_pcb *tpcb; 774 { 775 register struct mbuf *m, **mp; 776 if (tpcb->tp_rsycnt) { 777 for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit; 778 --mp >= tpcb->tp_rsyq; ) 779 if (*mp) { 780 tpcb->tp_rsycnt--; 781 m_freem(*mp); 782 } 783 if (tpcb->tp_rsycnt) 784 panic("tp_rsyflush"); 785 } 786 free((caddr_t)tpcb->tp_rsyq, M_PCB); 787 tpcb->tp_rsyq = 0; 788 } 789 790 tp_rsyset(tpcb) 791 register struct tp_pcb *tpcb; 792 { 793 register struct socket *so = tpcb->tp_sock; 794 int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf; 795 int old_credit = tpcb->tp_maxlcredit; 796 caddr_t rsyq; 797 798 tpcb->tp_maxlcredit = maxcredit = min(maxcredit, 799 (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize); 800 801 if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0) 802 return; 803 maxcredit *= sizeof(struct mbuf *); 804 if (tpcb->tp_rsyq) 805 tp_rsyflush(tpcb); 806 if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT)) 807 bzero(rsyq, maxcredit); 808 tpcb->tp_rsyq = (struct mbuf **)rsyq; 809 } 810 811 tpsbcheck(tpcb, i) 812 struct tp_pcb *tpcb; 813 { 814 register struct mbuf *n, *m; 815 register int len = 0, mbcnt = 0, pktlen; 816 struct sockbuf *sb = &tpcb->tp_sock->so_snd; 817 818 for (n = sb->sb_mb; n; n = n->m_nextpkt) { 819 if ((n->m_flags & M_PKTHDR) == 0) 820 panic("tpsbcheck nohdr"); 821 pktlen = len + n->m_pkthdr.len; 822 for (m = n; m; m = m->m_next) { 823 len += m->m_len; 824 mbcnt += MSIZE; 825 if (m->m_flags & M_EXT) 826 mbcnt += m->m_ext.ext_size; 827 } 828 if (len != pktlen) { 829 printf("test %d; len %d != pktlen %d on mbuf 0x%x\n", 830 i, len, pktlen, n); 831 panic("tpsbcheck short"); 832 } 833 } 834 if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { 835 printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc, 836 mbcnt, sb->sb_mbcnt); 837 panic("tpsbcheck"); 838 } 839 } 840