1 /* tcp_input.c 1.4 81/10/28 */ 2 3 #include "../h/param.h" 4 #include "../h/systm.h" 5 #include "../bbnnet/net.h" 6 #include "../bbnnet/mbuf.h" 7 #include "../bbnnet/host.h" 8 #include "../bbnnet/imp.h" 9 #include "../bbnnet/ucb.h" 10 #include "../bbnnet/tcp.h" 11 #include "../bbnnet/ip.h" 12 #include "../h/dir.h" 13 #include "../h/user.h" 14 #include "../h/inode.h" 15 #include "../bbnnet/fsm.h" 16 17 extern int nosum; 18 19 tcp_input(mp) 20 register struct mbuf *mp; 21 { 22 register struct tcb *tp; 23 register struct th *n; 24 int nstate; 25 struct mbuf *m; 26 struct ucb *up; 27 int hlen, tlen, j; 28 u_short lport, fport; 29 #ifdef TCPDEBUG 30 struct tcp_debug tdb; 31 #endif 32 COUNT(TCP_INPUT); 33 34 /* 35 * Build extended tcp header 36 */ 37 n = (struct th *)((int)mp + mp->m_off); 38 tlen = ((struct ip *)n)->ip_len; 39 n->t_len = htons(tlen); 40 n->t_next = NULL; 41 n->t_prev = NULL; 42 n->t_x1 = 0; 43 lport = ntohs(n->t_dst); 44 fport = ntohs(n->t_src); 45 46 /* WONT BE POSSIBLE WHEN MBUFS ARE 256 BYTES */ 47 if ((hlen = n->t_off << 2) > mp->m_len) 48 { printf("tcp header overflow\n"); m_freem(mp); return; } 49 50 /* 51 * Checksum extended header and data 52 */ 53 j = n->t_sum; n->t_sum = 0; 54 if (j != cksum(mp, sizeof (struct ip) + tlen)) { 55 netstat.t_badsum++; 56 if (nosum == 0) { 57 m_freem(mp); 58 return; 59 } 60 } 61 62 /* 63 * Find tcb for message (SHOULDN'T USE LINEAR SEARCH!) 64 */ 65 for (tp = netcb.n_tcb_head; tp != 0; tp = tp->t_tcb_next) 66 if (tp->t_lport == lport && tp->t_fport == fport && 67 tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr) 68 goto found; 69 for (tp = netcb.n_tcb_head; tp != 0; tp = tp->t_tcb_next) 70 if (tp->t_lport == lport && 71 (tp->t_fport==fport || tp->t_fport==0) && 72 (tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr || 73 tp->t_ucb->uc_host->h_addr.s_addr == 0)) 74 goto found; 75 goto notwanted; 76 found: 77 78 /* 79 * Byte swap header 80 */ 81 n->t_len = tlen - hlen; 82 n->t_src = fport; 83 n->t_dst = lport; 84 n->t_seq = ntohl(n->t_seq); 85 n->t_ackno = ntohl(n->t_ackno); 86 n->t_win = ntohs(n->t_win); 87 n->t_urp = ntohs(n->t_urp); 88 89 /* 90 * Check segment seq # and do rst processing 91 */ 92 switch (tp->t_state) { 93 94 case LISTEN: 95 if ((n->th_flags&TH_ACK) || !syn_ok(tp, n)) { 96 send_rst(tp, n); 97 goto badseg; 98 } 99 if (n->th_flags&TH_RST) 100 goto badseg; 101 goto goodseg; 102 103 case SYN_SENT: 104 if (!ack_ok(tp, n) || !syn_ok(tp, n)) { 105 send_rst(tp, n); /* 71,72,75 */ 106 goto badseg; 107 } 108 if (n->th_flags&TH_RST) { 109 t_close(tp, URESET); /* 70 */ 110 tp->t_state = CLOSED; 111 goto badseg; 112 } 113 goto goodseg; 114 115 default: 116 if ((n->th_flags&TH_RST) == 0) 117 goto common; 118 if (n->t_seq < tp->rcv_nxt) /* bad rst */ 119 goto badseg; /* 69 */ 120 switch (tp->t_state) { 121 122 case L_SYN_RCVD: 123 if (ack_ok(tp, n) == 0) 124 goto badseg; /* 69 */ 125 tp->t_rexmt = 0; 126 tp->t_rexmttl = 0; 127 tp->t_persist = 0; 128 h_free(tp->t_ucb->uc_host); 129 tp->t_state = LISTEN; 130 goto badseg; 131 132 default: 133 t_close(tp, URESET); /* 66 */ 134 tp->t_state = CLOSED; 135 goto badseg; 136 } 137 /*NOTREACHED*/ 138 139 case SYN_RCVD: 140 common: 141 if (ack_ok(tp, n) == 0) { 142 send_rst(tp, n); /* 74 */ 143 goto badseg; 144 } 145 if (syn_ok(tp, n) && n->t_seq != tp->irs) { 146 send_null(tp); /* 74 */ 147 goto badseg; 148 } 149 goto goodseg; 150 } 151 badseg: 152 m_freem(mp); 153 return; 154 155 goodseg: 156 #ifdef notdef 157 /* 158 * Defer processing if no buffer space for this connection. 159 */ 160 up = tp->t_ucb; 161 if ((int)up->uc_rcv - (int)up->uc_rsize <= 0 162 && n->t_len != 0 && netcb.n_bufs < netcb.n_lowat) { 163 mp->m_act = (struct mbuf *)0; 164 if ((m = tp->t_rcv_unack) != NULL) { 165 while (m->m_act != NULL) 166 m = m->m_act; 167 m->m_act = mp; 168 } else 169 tp->t_rcv_unack = mp; 170 171 return; 172 } 173 #endif 174 175 /* 176 * Discard ip header, and do tcp input processing. 177 */ 178 hlen += sizeof(struct ip); 179 mp->m_off += hlen; 180 mp->m_len -= hlen; 181 nstate = tp->t_state; 182 tp->tc_flags &= ~TC_NET_KEEP; 183 acounts[tp->t_state][INRECV]++; 184 #ifdef TCPDEBUG 185 if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) { 186 tdb_setup(tp, n, INRECV, &tdb); 187 } else 188 tdb.td_tod = 0; 189 #endif 190 switch (tp->t_state) { 191 192 case LISTEN: 193 if (!syn_ok(tp, n) || 194 ((tp->t_ucb->uc_host = h_make(&n->t_s)) == 0)) { 195 nstate = EFAILEC; 196 goto done; 197 } 198 tp->t_fport = n->t_src; 199 tp->t_ucb->uc_template = tcp_template(tp); 200 rcv_ctldat(tp, n, 1); 201 if (tp->tc_flags&TC_FIN_RCVD) { 202 tp->t_finack = T_2ML; /* 3 */ 203 tp->tc_flags &= ~TC_WAITED_2_ML; 204 nstate = CLOSE_WAIT; 205 } else { 206 tp->t_init = T_INIT / 2; /* 4 */ 207 nstate = L_SYN_RCVD; 208 } 209 goto done; 210 211 case SYN_SENT: 212 if (!syn_ok(tp, n)) { 213 nstate = EFAILEC; 214 goto done; 215 } 216 rcv_ctldat(tp, n, 1); 217 if (tp->tc_flags&TC_FIN_RCVD) { 218 if (n->th_flags&TH_ACK) { 219 if (n->t_ackno > tp->iss) 220 present_data(tp); /* 32 */ 221 } else { 222 tp->t_finack = T_2ML; /* 9 */ 223 tp->tc_flags &= ~TC_WAITED_2_ML; 224 } 225 nstate = CLOSE_WAIT; 226 goto done; 227 } 228 if (n->th_flags&TH_ACK) { 229 present_data(tp); /* 11 */ 230 nstate = ESTAB; 231 } else 232 nstate = SYN_RCVD; /* 8 */ 233 goto done; 234 235 case SYN_RCVD: 236 case L_SYN_RCVD: 237 if ((n->th_flags&TH_ACK) == 0 || 238 (n->th_flags&TH_ACK) && n->t_ackno <= tp->iss) { 239 nstate = EFAILEC; 240 goto done; 241 } 242 goto input; 243 244 case ESTAB: 245 case FIN_W1: 246 case FIN_W2: 247 case TIME_WAIT: 248 input: 249 rcv_ctldat(tp, n, 1); /* 39 */ 250 present_data(tp); 251 switch (tp->t_state) { 252 253 case ESTAB: 254 if (tp->tc_flags&TC_FIN_RCVD) 255 nstate = CLOSE_WAIT; 256 break; 257 258 case SYN_RCVD: 259 case L_SYN_RCVD: 260 nstate = (tp->tc_flags&TC_FIN_RCVD) ? 261 CLOSE_WAIT : ESTAB; /* 33:5 */ 262 break; 263 264 case FIN_W1: 265 j = ack_fin(tp, n); 266 if ((tp->tc_flags & TC_FIN_RCVD) == 0) { 267 if (j) 268 nstate = FIN_W2; /* 27 */ 269 break; 270 } 271 tp->t_finack = T_2ML; 272 tp->tc_flags &= ~TC_WAITED_2_ML; 273 nstate = j ? TIME_WAIT : CLOSING1; /* 28:26 */ 274 break; 275 276 case FIN_W2: 277 if (tp->tc_flags&TC_FIN_RCVD) { 278 tp->t_finack = T_2ML; /* 29 */ 279 tp->tc_flags &= ~TC_WAITED_2_ML; 280 nstate = TIME_WAIT; 281 break; 282 } 283 break; 284 } 285 goto done; 286 287 case CLOSE_WAIT: 288 if (n->th_flags&TH_FIN) { 289 if ((n->th_flags&TH_ACK) && 290 n->t_ackno <= tp->seq_fin) { 291 rcv_ctldat(tp, n, 0); /* 30 */ 292 tp->t_finack = T_2ML; 293 tp->tc_flags &= ~TC_WAITED_2_ML; 294 } else 295 send_ctl(tp); /* 31 */ 296 goto done; 297 } 298 goto input; 299 300 case CLOSING1: 301 j = ack_fin(tp, n); 302 if (n->th_flags&TH_FIN) { 303 rcv_ctldat(tp, n, 0); 304 tp->t_finack = T_2ML; 305 tp->tc_flags &= ~TC_WAITED_2_ML; 306 if (j) 307 nstate = TIME_WAIT; /* 23 */ 308 goto done; 309 } 310 if (j) { 311 if (tp->tc_flags&TC_WAITED_2_ML) 312 if (rcv_empty(tp)) { 313 t_close(tp, UCLOSED); /* 15 */ 314 nstate = CLOSED; 315 } else 316 nstate = RCV_WAIT; /* 18 */ 317 else 318 nstate = TIME_WAIT; 319 goto done; 320 } 321 goto input; 322 323 case CLOSING2: 324 if (ack_fin(tp, n)) { 325 if (rcv_empty(tp)) { /* 16 */ 326 t_close(tp, UCLOSED); 327 nstate = CLOSED; 328 } else 329 nstate = RCV_WAIT; /* 19 */ 330 goto done; 331 } 332 if (n->th_flags&TH_FIN) { 333 send_ctl(tp); /* 31 */ 334 goto done; 335 } 336 goto input; 337 338 case RCV_WAIT: 339 if ((n->th_flags&TH_FIN) && (n->th_flags&TH_ACK) && 340 n->t_ackno <= tp->seq_fin) { 341 rcv_ctldat(tp, n, 0); 342 tp->t_finack = T_2ML; 343 tp->tc_flags &= ~TC_WAITED_2_ML; /* 30 */ 344 } 345 goto done; 346 } 347 panic("tcp_input"); 348 done: 349 350 /* 351 * Done with state*input specific processing. 352 * Form trace records, free input if not needed, 353 * and enter new state. 354 */ 355 #ifdef TCPDEBUG 356 if (tdb.td_tod) 357 tdb_stuff(&tdb, nstate); 358 #endif 359 switch (nstate) { 360 361 case EFAILEC: 362 m_freem(mp); 363 return; 364 365 default: 366 tp->t_state = nstate; 367 /* fall into ... */ 368 369 case CLOSED: 370 /* IF CLOSED CANT LOOK AT tc_flags */ 371 if ((tp->tc_flags&TC_NET_KEEP) == 0) 372 m_freem(mp); 373 return; 374 } 375 /* NOTREACHED */ 376 377 /* 378 * Unwanted packed; free everything 379 * but the header and return an rst. 380 */ 381 notwanted: 382 m_freem(mp->m_next); 383 mp->m_next = NULL; 384 mp->m_len = sizeof(struct th); 385 #define xchg(a,b) j=a; a=b; b=j 386 xchg(n->t_d.s_addr, n->t_s.s_addr); xchg(n->t_dst, n->t_src); 387 #undef xchg 388 if (n->th_flags&TH_ACK) 389 n->t_seq = n->t_ackno; 390 else { 391 n->t_ackno = htonl(ntohl(n->t_seq) + tlen - hlen); 392 n->t_seq = 0; 393 } 394 n->th_flags = TH_RST; /* not TH_FIN, TH_SYN */ 395 n->th_flags ^= TH_ACK; 396 n->t_len = htons(TCPSIZE); 397 n->t_off = 5; 398 n->t_sum = cksum(mp, sizeof(struct th)); 399 ((struct ip *)n)->ip_len = sizeof(struct th); 400 ip_output(mp); 401 netstat.t_badsegs++; 402 } 403 404 rcv_ctldat(tp, n, dataok) 405 register struct tcb *tp; 406 register struct th *n; 407 { 408 register sent; 409 register struct ucb *up; 410 register struct mbuf *m, *mn; 411 register len; 412 COUNT(RCV_CTLDAT); 413 414 tp->tc_flags &= ~(TC_DROPPED_TXT|TC_ACK_DUE|TC_NEW_WINDOW); 415 /* syn */ 416 if ((tp->tc_flags&TC_SYN_RCVD) == 0 && (n->th_flags&TH_SYN)) { 417 tp->irs = n->t_seq; 418 tp->rcv_nxt = n->t_seq + 1; 419 tp->snd_wl = tp->rcv_urp = tp->irs; 420 tp->tc_flags |= (TC_SYN_RCVD|TC_ACK_DUE); 421 } 422 /* ack */ 423 if ((n->th_flags&TH_ACK) && (tp->tc_flags&TC_SYN_RCVD) && 424 n->t_ackno > tp->snd_una) { 425 up = tp->t_ucb; 426 427 /* update snd_una and snd_nxt */ 428 tp->snd_una = n->t_ackno; 429 if (tp->snd_una > tp->snd_nxt) 430 tp->snd_nxt = tp->snd_una; 431 432 /* if timed msg acked, set retrans time value */ 433 if ((tp->tc_flags&TC_SYN_ACKED) && 434 tp->snd_una > tp->t_xmt_val) { 435 tp->t_xmtime = (tp->t_xmt != 0 ? tp->t_xmt : T_REXMT); 436 if (tp->t_xmtime > T_REMAX) 437 tp->t_xmtime = T_REMAX; 438 } 439 440 /* remove acked data from send buf */ 441 len = tp->snd_una - tp->snd_off; 442 m = up->uc_sbuf; 443 while (len > 0 && m != NULL) 444 if (m->m_len <= len) { 445 len -= m->m_len; 446 if (m->m_off > MMAXOFF) 447 up->uc_ssize -= NMBPG; 448 MFREE(m, mn); 449 m = mn; 450 up->uc_ssize--; 451 } else { 452 m->m_len -= len; 453 m->m_off += len; 454 break; 455 } 456 up->uc_sbuf = m; 457 tp->snd_off = tp->snd_una; 458 if ((tp->tc_flags&TC_SYN_ACKED) == 0 && 459 (tp->snd_una > tp->iss)) { 460 tp->tc_flags |= TC_SYN_ACKED; 461 tp->t_init = 0; 462 } 463 if (tp->seq_fin != tp->iss && tp->snd_una > tp->seq_fin) 464 tp->tc_flags &= ~TC_SND_FIN; 465 tp->t_rexmt = 0; 466 tp->t_rexmttl = 0; 467 tp->tc_flags |= TC_CANCELLED; 468 netwakeup(tp->t_ucb); /* wasteful */ 469 } 470 /* win */ 471 if ((tp->tc_flags & TC_SYN_RCVD) && n->t_seq >= tp->snd_wl) { 472 tp->snd_wl = n->t_seq; 473 tp->snd_wnd = n->t_win; 474 tp->tc_flags |= TC_NEW_WINDOW; 475 tp->t_persist = 0; 476 } 477 if (dataok) { 478 /* text */ 479 if (n->t_len != 0) 480 rcv_text(tp, n); 481 /* urg */ 482 if (n->th_flags&TH_URG) { 483 unsigned urgent; 484 485 urgent = n->t_urp + n->t_seq; 486 if (tp->rcv_nxt < urgent) { 487 if (tp->rcv_urp <= tp->rcv_nxt) 488 to_user(tp->t_ucb, UURGENT); 489 tp->rcv_urp = urgent; 490 } 491 } 492 /* eol */ 493 if ((n->th_flags&TH_EOL) && 494 (tp->tc_flags&TC_DROPPED_TXT) == 0 && 495 tp->t_rcv_prev != (struct th *)tp) { 496 /* mark last mbuf */ 497 m = dtom(tp->t_rcv_prev); 498 if (m != NULL) { 499 while (m->m_next != NULL) 500 m = m->m_next; 501 m->m_act = 502 (struct mbuf *)(m->m_off + m->m_len - 1); 503 } 504 } 505 } 506 /* fin */ 507 if ((n->th_flags&TH_FIN) && (tp->tc_flags&TC_DROPPED_TXT) == 0) { 508 int last; 509 510 if ((tp->tc_flags&TC_FIN_RCVD) == 0) { 511 /* do we really have fin ? */ 512 last = firstempty(tp); 513 if (tp->t_rcv_prev == (struct th *)tp || 514 last == t_end(tp->t_rcv_prev)) { 515 tp->tc_flags |= TC_FIN_RCVD; 516 netwakeup(tp->t_ucb); /* poke */ 517 } 518 if ((tp->tc_flags&TC_FIN_RCVD) && 519 tp->rcv_nxt >= last) { 520 tp->rcv_nxt = last + 1; /* fin seq */ 521 tp->tc_flags |= TC_ACK_DUE; 522 } 523 } else 524 tp->tc_flags |= TC_ACK_DUE; 525 } 526 527 /* respond */ 528 if (tp->tc_flags&TC_ACK_DUE) 529 sent = send_ctl(tp); 530 else if (tp->tc_flags&TC_NEW_WINDOW) 531 sent = send(tp); 532 else 533 sent = 0; 534 535 /* set for retrans */ 536 if (!sent && tp->snd_una < tp->snd_nxt && 537 (tp->tc_flags&TC_CANCELLED)) { 538 tp->t_rexmt = tp->t_xmtime; 539 tp->t_rexmttl = T_REXMTTL; 540 tp->t_rexmt_val = tp->t_rtl_val = tp->snd_lst; 541 tp->tc_flags &= ~TC_CANCELLED; 542 } 543 } 544 545 rcv_text(tp, n) 546 register struct tcb *tp; 547 register struct th *n; 548 { 549 register int i; 550 register struct th *p, *q; 551 register struct mbuf *m; 552 int overage; 553 COUNT(RCV_TEXT); 554 555 /* 556 * Discard duplicate data already passed to user. 557 */ 558 if (n->t_seq < tp->rcv_nxt){ 559 i = tp->rcv_nxt - n->t_seq; 560 if (i >= n->t_len) 561 goto dropseg; 562 n->t_seq += i; 563 n->t_len -= i; 564 m_adj(dtom(n), i); 565 } 566 567 /* 568 * Find a segment which begins after this one does. 569 */ 570 for (q = tp->t_rcv_next; q != (struct th *)tp; q = q->t_next) 571 if (q->t_seq > n->t_seq) 572 break; 573 574 /* 575 * If there is a preceding segment, it may provide some of 576 * our data already. If so, drop the data from the incoming 577 * segment. If it provides all of our data, drop us. 578 */ 579 if (q->t_prev != (struct th *)tp) { 580 i = q->t_prev->t_seq + q->t_prev->t_len - n->t_seq; 581 if (i > 0) { 582 if (i >= n->t_len) 583 goto dropseg; 584 m_adj(dtom(tp), i); 585 n->t_len -= i; 586 n->t_seq += i; 587 } 588 } 589 590 /* 591 * While we overlap succeeding segments trim them or, 592 * if they are completely covered, dequeue them. 593 */ 594 while (q != (struct th *)tp && n->t_seq + n->t_len > q->t_seq) { 595 i = (n->t_seq + n->t_len) - q->t_seq; 596 if (i < q->t_len) { 597 q->t_len -= i; 598 m_adj(dtom(q), i); 599 break; 600 } 601 q = q->t_next; 602 m_freem(dtom(q->t_prev)); 603 remque(q->t_prev); 604 } 605 606 /* 607 * Stick new segment in its place. 608 */ 609 insque(n, q->t_prev); 610 /* 611 tp->rcv_seqcnt += n->t_len; 612 */ 613 614 #ifdef notdef 615 /* 616 * Calculate available space and discard segments for 617 * which there is too much. 618 */ 619 q = tp->t_rcv_prev; 620 overage = (tp->t_socket->uc_rcc + tp->rcv_seqcnt) - tp->t_socket->uc_rhiwat; 621 if (overage > 0) 622 for (;;) { 623 i = MIN(q->t_len, overage); 624 overage -= i; 625 q->t_len -= i; 626 m_adj(q, -i); 627 if (q == n) 628 tp->tc_flags |= TC_DROPPED_TXT; 629 if (q->t_len) 630 break; 631 if (q == n) 632 printf("tcp_text dropall\n"); 633 q = q->t_prev; 634 remque(q->t_next); 635 } 636 #endif 637 638 /* 639 * Advance rcv_next through newly 640 * completed sequence space and force ACK. 641 */ 642 while (n->t_seq == tp->rcv_nxt) { 643 tp->rcv_nxt += n->t_len; 644 n = n->t_next; 645 if (n == (struct th *)tp) 646 break; 647 } 648 tp->tc_flags |= (TC_ACK_DUE|TC_NET_KEEP); 649 return; 650 651 dropseg: 652 /* don't set TC_NET_KEEP */ 653 return; 654 } 655 656 present_data(tp) 657 register struct tcb *tp; 658 { 659 register struct th *t; 660 register struct ucb *up; 661 register struct mbuf *m, **mp; 662 seq_t ready; 663 COUNT(PRESENT_DATA); 664 665 /* connection must be synced and data available for user */ 666 if (((tp->tc_flags&TC_SYN_ACKED) == 0) || 667 (t = tp->t_rcv_next) == (struct th *)tp) 668 return; 669 up = tp->t_ucb; 670 ready = firstempty(tp); /* seq # of last complete datum */ 671 mp = &up->uc_rbuf; 672 while (*mp) 673 mp = &(*mp)->m_next; 674 while (up->uc_rsize < up->uc_rcv && t != (struct th *) tp && 675 t_end(t) < ready) { 676 tcp_deq(t); 677 m = dtom(t); 678 t = t->t_next; 679 while (m) { 680 if (m->m_len == 0) { 681 m = m_free(m); 682 continue; 683 } 684 up->uc_rsize++; 685 if (m->m_off > MMAXOFF) 686 up->uc_rsize += NMBPG; 687 if (*mp == 0) 688 *mp = m; 689 mp = &m->m_next; 690 m = *mp; 691 } 692 } 693 if (up->uc_rsize != 0) 694 netwakeup(up); 695 /* 696 * Let user know about foreign tcp close if no more data. 697 */ 698 if ((tp->tc_flags&TC_FIN_RCVD) && (tp->tc_flags&TC_USR_CLOSED) == 0 && 699 rcv_empty(tp)) 700 to_user(up, UCLOSED); 701 } 702 703 #ifdef TCPDEBUG 704 tdb_setup(tp, n, input, tdp) 705 struct tcb *tp; 706 register struct th *n; 707 int input; 708 register struct tcp_debug *tdp; 709 { 710 711 tdp->td_tod = time; 712 tdp->td_tcb = tp; 713 tdp->td_old = tp->t_state; 714 tdp->td_inp = input; 715 tdp->td_tim = 0; 716 tdp->td_new = -1; 717 if (n) { 718 tdp->td_sno = n->t_seq; 719 tdp->td_ano = n->t_ackno; 720 tdp->td_wno = n->t_win; 721 tdp->td_lno = n->t_len; 722 tdp->td_flg = n->th_flags; 723 } else 724 tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno = 725 tdp->td_flg = 0; 726 } 727 728 tdb_stuff(tdp, nstate) 729 struct tcp_debug *tdp; 730 int nstate; 731 { 732 733 tdp->td_new = nstate; 734 tcp_debug[tdbx++ % TDBSIZE] = *tdp; 735 if (tcpconsdebug & 2) 736 tcp_prt(tdp); 737 } 738 #endif 739