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