1 /* tcp_usrreq.c 1.1 81/10/14 */ 2 #include "../h/param.h" 3 #include "../bbnnet/net.h" 4 #include "../bbnnet/tcp.h" 5 #include "../bbnnet/ip.h" 6 #include "../bbnnet/imp.h" 7 #include "../bbnnet/ucb.h" 8 #include "../bbnnet/fsm.h" 9 #include "../bbnnet/tcp_pred.h" 10 11 lis_cls(wp) /* passive open (1) */ 12 struct work *wp; 13 { 14 15 COUNT(LIS_CLS); 16 t_open(wp->w_tcb, PASSIVE); 17 18 return(LISTEN); 19 } 20 21 sys_cls(wp) /* active open (6) */ 22 register struct work *wp; 23 { 24 25 COUNT(SYS_CLS); 26 t_open(wp->w_tcb, ACTIVE); 27 send_ctl(wp->w_tcb); /* send SYN */ 28 29 return(SYN_SENT); 30 } 31 32 cls_opn(wp) /* close request before receiving foreign SYN (10) */ 33 struct work *wp; 34 { 35 36 COUNT(CLS_OPN); 37 t_close(wp->w_tcb, UCLOSED); 38 39 return(CLOSED); 40 } 41 42 cl2_clw(wp) /* close request after receiving foreign FIN (13) */ 43 struct work *wp; 44 { 45 register struct tcb *tp; 46 47 COUNT(CL2_CLW); 48 tp = wp->w_tcb; 49 50 tp->snd_fin = TRUE; /* send our own FIN */ 51 send_ctl(tp); 52 tp->usr_closed = TRUE; 53 54 return(CLOSING2); 55 } 56 57 cls_rwt(wp) /* rcv request after foreign close (20) */ 58 struct work *wp; 59 { 60 register struct tcb *tp; 61 62 COUNT(CLS_RWT); 63 tp = wp->w_tcb; 64 65 present_data(tp); /* present any remaining data */ 66 67 if (rcv_empty(tp)) { 68 t_close(tp, UCLOSED); 69 return(CLOSED); 70 } else 71 return(RCV_WAIT); 72 73 } 74 75 fw1_syr(wp) /* close request on synced connection (24,25) */ 76 struct work *wp; 77 { 78 register struct tcb *tp; 79 80 COUNT(FW1_SYR); 81 tp = wp->w_tcb; 82 83 tp->snd_fin = TRUE; /* send FIN */ 84 send_ctl(tp); 85 tp->usr_closed = TRUE; 86 87 return(FIN_W1); 88 } 89 90 sss_syn(wp) /* incoming seq on open connection (39) */ 91 struct work *wp; 92 { 93 register struct tcb *tp; 94 95 COUNT(SSS_SYN); 96 tp = wp->w_tcb; 97 98 rcv_data(tp, wp->w_dat); 99 present_data(tp); 100 101 return(SAME); 102 } 103 104 sss_snd(wp) /* send request on open connection (40,41) */ 105 struct work *wp; 106 { 107 register struct tcb *tp; 108 register struct mbuf *m, *n; 109 register struct ucb *up; 110 register off; 111 sequence last; 112 113 COUNT(SSS_SND); 114 tp = wp->w_tcb; 115 up = tp->t_ucb; 116 117 last = tp->snd_off; 118 119 /* count number of mbufs in send data */ 120 121 for (m = n = (struct mbuf *)wp->w_dat; m != NULL; m = m->m_next) { 122 up->uc_ssize++; 123 last += m->m_len; 124 } 125 126 /* find end of send buffer and append data */ 127 128 if ((m = up->uc_sbuf) != NULL) { /* something in send buffer */ 129 while (m->m_next != NULL) { /* find the end */ 130 m = m->m_next; 131 last += m->m_len; 132 } 133 last += m->m_len; 134 135 /* if there's room in old buffer for new data, consolidate */ 136 137 off = m->m_off + m->m_len; 138 while (n != NULL && (MSIZE - off) >= n->m_len) { 139 bcopy((caddr_t)((int)n + n->m_off), 140 (caddr_t)((int)m + off), n->m_len); 141 m->m_len += n->m_len; 142 off += n->m_len; 143 up->uc_ssize--; 144 n = m_free(n); 145 } 146 m->m_next = n; 147 148 } else /* nothing in send buffer */ 149 up->uc_sbuf = n; 150 151 if (up->uc_flags & UEOL) { /* set EOL */ 152 tp->snd_end = last; 153 } 154 155 if (up->uc_flags & UURG) { /* urgent data */ 156 tp->snd_urp = last+1; 157 tp->snd_urg = TRUE; 158 } 159 160 send(tp); 161 162 return(SAME); 163 } 164 165 sss_rcv(wp) /* rcv request on open connection (42) */ 166 struct work *wp; 167 { 168 register struct tcb *tp; 169 170 COUNT(SSS_RCV); 171 tp = wp->w_tcb; 172 173 send_ctl(tp); /* send new window */ 174 present_data(tp); 175 176 return(SAME); 177 } 178 179 cls_nsy(wp) /* abort request on unsynced connection (44) */ 180 struct work *wp; 181 { 182 183 COUNT(CLS_NSY); 184 t_close(wp->w_tcb, UABORT); 185 186 return(CLOSED); 187 } 188 189 cls_syn(wp) /* abort request on synced connection (45) */ 190 struct work *wp; 191 { 192 register struct tcb *tp; 193 194 COUNT(CLS_SYN); 195 tp = wp->w_tcb; 196 197 tp->snd_rst = TRUE; /* send reset */ 198 send_null(tp); 199 t_close(tp, UABORT); 200 201 return(CLOSED); 202 } 203 204 cls_act(wp) /* net closing open connection (47) */ 205 struct work *wp; 206 { 207 208 COUNT(CLS_ACT); 209 t_close(wp->w_tcb, UNETDWN); 210 211 return(CLOSED); 212 } 213 214 cls_err(wp) /* invalid user request in closing states */ 215 struct work *wp; 216 { 217 COUNT(CLS_ERR); 218 to_user(wp->w_tcb->t_ucb, UCLSERR); 219 220 return(SAME); 221 } 222 223 lis_netr(wp) /* incoming seg in LISTEN (3,4) */ 224 struct work *wp; 225 { 226 register struct tcb *tp; 227 register struct th *n; 228 229 COUNT(LIS_NETR); 230 tp = wp->w_tcb; 231 n = (struct th *)wp->w_dat; 232 233 if (!syn_ok(tp, n)) /* must have good SYN */ 234 return(EFAILEC); 235 236 /* fill in unspecified foreign host address. get/create entry 237 in foreign host table. if none available, ignore. probably 238 should send reset here. */ 239 240 if ((tp->t_ucb->uc_host = h_make(&n->t_s)) == NULL) 241 return(EFAILEC); 242 243 tp->t_fport = n->t_src; 244 245 rcv_data(tp, n); 246 247 if (!tp->fin_rcvd) { /* no FIN (4) */ 248 249 /* start init timer now that we have foreign host */ 250 251 tp->t_init = T_INIT/2; 252 return(L_SYN_RCVD); 253 254 } else { /* got a FIN, start timer (3) */ 255 tp->t_finack = T_2ML; 256 tp->waited_2_ml = FALSE; 257 return(CLOSE_WAIT); 258 } 259 } 260 261 sys_netr(wp) /* incoming segment after SYN sent (8,9,11,32) */ 262 struct work *wp; 263 { 264 register struct tcb *tp; 265 register struct th *n; 266 267 COUNT(SYS_NETR); 268 tp = wp->w_tcb; 269 n = (struct th *)wp->w_dat; 270 271 if (!syn_ok(tp, n)) /* must have good SYN */ 272 return(EFAILEC); 273 274 rcv_data(tp, n); 275 276 if (tp->fin_rcvd) { /* got a FIN */ 277 278 /* if good ACK, present any data */ 279 280 if (n->t_ack) { 281 282 if (n->t_ackno > tp->iss) /* 32 */ 283 present_data(tp); 284 285 } else { /* 9 */ 286 tp->t_finack = T_2ML; 287 tp->waited_2_ml = FALSE; 288 } 289 return (CLOSE_WAIT); 290 291 } else /* no FIN */ 292 293 /* if good ACK, open connection, otherwise wait for one */ 294 295 if (n->t_ack) { /* 11 */ 296 present_data(tp); 297 return(ESTAB); 298 } else 299 return(SYN_RCVD); /* 8 */ 300 } 301 302 cl1_netr(wp) /* incoming seg after we closed (15,18,22,23,30,39) */ 303 struct work *wp; 304 { 305 register struct tcb *tp; 306 register struct th *n; 307 308 COUNT(CL1_NETR); 309 tp = wp->w_tcb; 310 n = (struct th *)wp->w_dat; 311 312 if (ack_fin(tp, n)) /* got ACK of our FIN */ 313 314 if (n->t_fin) { /* got for FIN (23) */ 315 316 rcv_ctl(tp, n); 317 tp->t_finack = T_2ML; 318 tp->waited_2_ml = FALSE; 319 return(TIME_WAIT); 320 } else { 321 322 /* if wait done, see if any data left for user */ 323 324 if (tp->waited_2_ml) 325 326 if (rcv_empty(tp)) { /* 15 */ 327 328 t_close(tp, UCLOSED); 329 return(CLOSED); 330 } else 331 return(RCV_WAIT); /* 18 */ 332 333 else 334 return(TIME_WAIT); /* 22 */ 335 } 336 337 else /* our FIN not ACKed yet */ 338 339 if (n->t_fin) { /* rcvd for FIN (30) */ 340 341 rcv_ctl(tp, n); 342 tp->t_finack = T_2ML; 343 tp->waited_2_ml = FALSE; 344 345 } else { /* no FIN, just proc new data (39) */ 346 347 rcv_data(tp, n); 348 present_data(tp); 349 } 350 351 return(SAME); 352 } 353 354 cl2_netr(wp) /* incoming seg after foreign close (16,19,31,39) */ 355 struct work *wp; 356 { 357 register struct tcb *tp; 358 register struct th *n; 359 360 COUNT(CL2_NETR); 361 tp = wp->w_tcb; 362 n = (struct th *)wp->w_dat; 363 364 if (ack_fin(tp, n)) { /* this is ACK of our fin */ 365 366 /* if no data left for user, close; otherwise wait */ 367 368 if (rcv_empty(tp)) { /* 16 */ 369 370 t_close(tp, UCLOSED); 371 return(CLOSED); 372 } else /* 19 */ 373 return(RCV_WAIT); 374 375 } else /* no ACK of our FIN */ 376 377 /* duplicate FIN or data */ 378 379 if (n->t_fin) /* 31 */ 380 send_ctl(tp); /* ACK duplicate FIN */ 381 382 else { /* 39 */ 383 rcv_data(tp, n); 384 present_data(tp); 385 } 386 387 return(SAME); 388 } 389 390 fw1_netr(wp) /* incoming seg after user close (26,27,28,39) */ 391 struct work *wp; 392 { 393 register struct tcb *tp; 394 register struct th *n; 395 396 COUNT(FW1_NETR); 397 tp = wp->w_tcb; 398 n = (struct th *)wp->w_dat; 399 400 /* process any incoming data, since we closed but they didn't */ 401 402 rcv_data(tp, n); 403 present_data(tp); 404 405 if (ack_fin(tp, n)) /* our FIN got ACKed */ 406 407 if (tp->fin_rcvd) { /* got for FIN (28) */ 408 tp->t_finack = T_2ML; 409 tp->waited_2_ml = FALSE; 410 return(TIME_WAIT); 411 } else /* no FIN, wait (27) */ 412 return(FIN_W2); 413 414 else /* no ACK of FIN */ 415 416 if (tp->fin_rcvd) { /* got for FIN (26) */ 417 tp->t_finack = T_2ML; 418 tp->waited_2_ml = FALSE; 419 return(CLOSING1); 420 } 421 422 return(SAME); /* 39 */ 423 } 424 425 syr_netr(wp) /* incoming seg after SYN rcvd (5,33) */ 426 struct work *wp; 427 { 428 register struct tcb *tp; 429 register struct th *n; 430 431 COUNT(SYR_NETR); 432 tp = wp->w_tcb; 433 n = (struct th *)wp->w_dat; 434 435 if (!n->t_ack || (n->t_ack && n->t_ackno <= tp->iss)) /* must have ACK of our SYN */ 436 return(EFAILEC); 437 438 rcv_data(tp, n); 439 present_data(tp); 440 441 /* if no FIN, open connection, otherwise wait for user close */ 442 443 if (tp->fin_rcvd) /* 33 */ 444 return(CLOSE_WAIT); 445 else /* 5 */ 446 return(ESTAB); 447 448 } 449 450 est_netr(wp) /* incoming seg on open connection (12,39) */ 451 struct work *wp; 452 { 453 register struct tcb *tp; 454 register struct th *n; 455 456 COUNT(EST_NETR); 457 tp = wp->w_tcb; 458 n = (struct th *)wp->w_dat; 459 460 rcv_data(tp, n); 461 present_data(tp); 462 463 /* if no FIN, remain open, otherwise wait for user close */ 464 465 if (tp->fin_rcvd) /* 12 */ 466 return(CLOSE_WAIT); 467 else /* 39 */ 468 return(SAME); 469 } 470 471 fw2_netr(wp) /* incoming seg while waiting for for FIN (12,39) */ 472 struct work *wp; 473 { 474 register struct tcb *tp; 475 register struct th *n; 476 477 COUNT(FW2_NETR); 478 tp = wp->w_tcb; 479 n = (struct th *)wp->w_dat; 480 481 /* process data since we closed, but they may not have */ 482 483 rcv_data(tp, n); 484 present_data(tp); 485 486 /* if we get the FIN, start the finack timer, else keep waiting */ 487 488 if (tp->fin_rcvd) { /* got for FIN (29) */ 489 tp->t_finack = T_2ML; 490 tp->waited_2_ml = FALSE; 491 return(TIME_WAIT); 492 } else /* 39 */ 493 return(SAME); 494 } 495 496 cwt_netr(wp) /* incoming seg after exchange of FINs (30,31,39) */ 497 struct work *wp; 498 { 499 register struct tcb *tp; 500 register struct th *n; 501 502 COUNT(CWT_NETR); 503 tp = wp->w_tcb; 504 n = (struct th *)wp->w_dat; 505 506 /* either duplicate FIN or data */ 507 508 if (n->t_fin) { 509 510 if (n->t_ack && n->t_ackno <= tp->seq_fin) { /* dup ACK (30) */ 511 512 rcv_ctl(tp, n); 513 tp->t_finack = T_2ML; 514 tp->waited_2_ml = FALSE; 515 } else /* 31 */ 516 send_ctl(tp); 517 518 } else { /* duplicate data (39) */ 519 520 rcv_data(tp, n); 521 present_data(tp); 522 } 523 524 return(SAME); 525 } 526 527 rwt_netr(wp) /* incoming seg while waiting for user rcv (30,21) */ 528 struct work *wp; 529 { 530 register struct tcb *tp; 531 register struct th *n; 532 533 COUNT(RWT_NETR); 534 tp = wp->w_tcb; 535 n = (struct th *)wp->w_dat; 536 537 /* handle duplicate ACK of our FIN */ 538 539 if (n->t_fin && n->t_ack && n->t_ackno <= tp->seq_fin) { /* 30 */ 540 541 rcv_ctl(tp, n); 542 tp->t_finack = T_2ML; 543 tp->waited_2_ml = FALSE; 544 } 545 546 return(SAME); 547 } 548 549 timers(wp) /* timer processor (14,17,34,35,36,37,38) */ 550 struct work *wp; 551 { 552 register struct tcb *tp; 553 register type; 554 555 COUNT(TIMERS); 556 tp = wp->w_tcb; 557 type = wp->w_stype; 558 559 switch (type) { 560 561 case TINIT: /* initialization timer */ 562 563 if (!tp->syn_acked) { /* haven't got ACK of our SYN (35) */ 564 565 t_close(tp, UINTIMO); 566 return(CLOSED); 567 } 568 break; 569 570 case TFINACK: /* fin-ack timer */ 571 572 if (tp->t_state == TIME_WAIT) { 573 574 /* can be sure our ACK of for FIN was rcvd, 575 can close if no data left for user */ 576 577 if (rcv_empty(tp)) { /* 14 */ 578 t_close(tp, UCLOSED); 579 return(CLOSED); 580 } else /* 17 */ 581 return(RCV_WAIT); 582 583 } else if (tp->t_state == CLOSING1) /* 37 */ 584 585 /* safe to close */ 586 587 tp->waited_2_ml = TRUE; 588 589 break; 590 591 case TREXMT: /* retransmission timer */ 592 593 /* set up for a retransmission, increase rexmt time 594 in case of multiple retransmissions. */ 595 596 if (tp->t_rexmt_val > tp->snd_una) { /* 34 */ 597 tp->snd_nxt = tp->snd_una; 598 tp->rexmt = TRUE; 599 tp->t_xmtime = tp->t_xmtime << 1; 600 if (tp->t_xmtime > T_REMAX) 601 tp->t_xmtime = T_REMAX; 602 send(tp); 603 } 604 break; 605 606 case TREXMTTL: /* retransmit too long */ 607 608 /* tell user */ 609 610 if (tp->t_rtl_val > tp->snd_una) /* 36 */ 611 to_user(tp->t_ucb, URXTIMO); 612 613 /* if user has already closed, abort the connection */ 614 615 if (tp->usr_closed) { 616 t_close(tp, URXTIMO); 617 return(CLOSED); 618 } 619 break; 620 621 case TPERSIST: /* persist timer */ 622 623 /* force a byte send through closed window */ 624 625 tp->force_one = TRUE; /* 38 */ 626 send(tp); 627 break; 628 } 629 630 return(SAME); 631 } 632 633 netprepr(tp, n) /* network preproc (66,67,68,69,70,71,72,73,74,75,76) */ 634 register struct tcb *tp; 635 register struct th *n; 636 { 637 638 COUNT(NETPREPR); 639 switch (tp->t_state) { 640 641 case LISTEN: 642 643 if (n->t_ack || !syn_ok(tp, n)) 644 send_rst(tp, n); 645 else if (!n->t_rst) 646 return(0); 647 break; 648 649 case SYN_SENT: 650 651 if (!ack_ok(tp, n) || !syn_ok(tp, n)) 652 653 send_rst(tp, n); /* 71,72,75 */ 654 655 else if (n->t_rst) { 656 657 t_close(tp, URESET); /* 70 */ 658 return(CLOSED); 659 } else 660 return(0); 661 break; 662 663 default: 664 665 if (n->t_rst) { /* any resets? */ 666 667 if (n->t_seq >= tp->rcv_nxt) { /* good reset */ 668 669 if (tp->t_state == L_SYN_RCVD) { 670 671 if (ack_ok(tp, n)) { /* 67 */ 672 t_cancel(tp, TREXMT); 673 t_cancel(tp, TREXMTTL); 674 t_cancel(tp, TPERSIST); 675 h_free(tp->t_ucb->uc_host); 676 return(LISTEN); 677 } 678 } else { /* 66 */ 679 t_close(tp, URESET); 680 return(CLOSED); 681 } 682 } /* else 69 */ 683 break; 684 } 685 686 case SYN_RCVD: 687 688 if (ack_ok(tp, n)) /* acceptable ack */ 689 690 if (syn_ok(tp, n) && n->t_seq != tp->irs) 691 692 /* bad syn (73,75,76) */ 693 694 send_null(tp); 695 else 696 return(0); /* acceptable segment */ 697 else 698 send_rst(tp, n); /* bad ack (74) */ 699 700 } 701 702 return(-1); /* tell caller to eat segment (unacceptable) */ 703 } 704