1 /** @file 2 TCP input process routines. 3 4 Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php<BR> 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 16 #include "Tcp4Main.h" 17 18 19 /** 20 Check whether the sequence number of the incoming segment is acceptable. 21 22 @param Tcb Pointer to the TCP_CB of this TCP instance. 23 @param Seg Pointer to the incoming segment. 24 25 @retval 1 The sequence number is acceptable. 26 @retval 0 The sequence number is not acceptable. 27 28 **/ 29 INTN 30 TcpSeqAcceptable ( 31 IN TCP_CB *Tcb, 32 IN TCP_SEG *Seg 33 ) 34 { 35 return (TCP_SEQ_LEQ (Tcb->RcvWl2, Seg->End) && 36 TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2 + Tcb->RcvWnd)); 37 } 38 39 40 /** 41 NewReno fast recovery, RFC3782. 42 43 @param Tcb Pointer to the TCP_CB of this TCP instance. 44 @param Seg Segment that triggers the fast recovery. 45 46 **/ 47 VOID 48 TcpFastRecover ( 49 IN OUT TCP_CB *Tcb, 50 IN TCP_SEG *Seg 51 ) 52 { 53 UINT32 FlightSize; 54 UINT32 Acked; 55 56 // 57 // Step 1: Three duplicate ACKs and not in fast recovery 58 // 59 if (Tcb->CongestState != TCP_CONGEST_RECOVER) { 60 61 // 62 // Step 1A: Invoking fast retransmission. 63 // 64 FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna); 65 66 Tcb->Ssthresh = MAX (FlightSize >> 1, (UINT32) (2 * Tcb->SndMss)); 67 Tcb->Recover = Tcb->SndNxt; 68 69 Tcb->CongestState = TCP_CONGEST_RECOVER; 70 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON); 71 72 // 73 // Step 2: Entering fast retransmission 74 // 75 TcpRetransmit (Tcb, Tcb->SndUna); 76 Tcb->CWnd = Tcb->Ssthresh + 3 * Tcb->SndMss; 77 78 DEBUG ((EFI_D_INFO, "TcpFastRecover: enter fast retransmission" 79 " for TCB %p, recover point is %d\n", Tcb, Tcb->Recover)); 80 return; 81 } 82 83 // 84 // During fast recovery, execute Step 3, 4, 5 of RFC3782 85 // 86 if (Seg->Ack == Tcb->SndUna) { 87 88 // 89 // Step 3: Fast Recovery, 90 // If this is a duplicated ACK, increse Cwnd by SMSS. 91 // 92 93 // Step 4 is skipped here only to be executed later 94 // by TcpToSendData 95 // 96 Tcb->CWnd += Tcb->SndMss; 97 DEBUG ((EFI_D_INFO, "TcpFastRecover: received another" 98 " duplicated ACK (%d) for TCB %p\n", Seg->Ack, Tcb)); 99 100 } else { 101 102 // 103 // New data is ACKed, check whether it is a 104 // full ACK or partial ACK 105 // 106 if (TCP_SEQ_GEQ (Seg->Ack, Tcb->Recover)) { 107 108 // 109 // Step 5 - Full ACK: 110 // deflate the congestion window, and exit fast recovery 111 // 112 FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna); 113 114 Tcb->CWnd = MIN (Tcb->Ssthresh, FlightSize + Tcb->SndMss); 115 116 Tcb->CongestState = TCP_CONGEST_OPEN; 117 DEBUG ((EFI_D_INFO, "TcpFastRecover: received a full ACK(%d)" 118 " for TCB %p, exit fast recovery\n", Seg->Ack, Tcb)); 119 120 } else { 121 122 // 123 // Step 5 - Partial ACK: 124 // fast retransmit the first unacknowledge field 125 // , then deflate the CWnd 126 // 127 TcpRetransmit (Tcb, Seg->Ack); 128 Acked = TCP_SUB_SEQ (Seg->Ack, Tcb->SndUna); 129 130 // 131 // Deflate the CWnd by the amount of new data 132 // ACKed by SEG.ACK. If more than one SMSS data 133 // is ACKed, add back SMSS byte to CWnd after 134 // 135 if (Acked >= Tcb->SndMss) { 136 Acked -= Tcb->SndMss; 137 138 } 139 140 Tcb->CWnd -= Acked; 141 142 DEBUG ((EFI_D_INFO, "TcpFastRecover: received a partial" 143 " ACK(%d) for TCB %p\n", Seg->Ack, Tcb)); 144 145 } 146 } 147 } 148 149 150 /** 151 NewReno fast loss recovery, RFC3792. 152 153 @param Tcb Pointer to the TCP_CB of this TCP instance. 154 @param Seg Segment that triggers the fast loss recovery. 155 156 **/ 157 VOID 158 TcpFastLossRecover ( 159 IN OUT TCP_CB *Tcb, 160 IN TCP_SEG *Seg 161 ) 162 { 163 if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) { 164 165 // 166 // New data is ACKed, check whether it is a 167 // full ACK or partial ACK 168 // 169 if (TCP_SEQ_GEQ (Seg->Ack, Tcb->LossRecover)) { 170 171 // 172 // Full ACK: exit the loss recovery. 173 // 174 Tcb->LossTimes = 0; 175 Tcb->CongestState = TCP_CONGEST_OPEN; 176 177 DEBUG ((EFI_D_INFO, "TcpFastLossRecover: received a " 178 "full ACK(%d) for TCB %p\n", Seg->Ack, Tcb)); 179 180 } else { 181 182 // 183 // Partial ACK: 184 // fast retransmit the first unacknowledge field. 185 // 186 TcpRetransmit (Tcb, Seg->Ack); 187 DEBUG ((EFI_D_INFO, "TcpFastLossRecover: received a " 188 "partial ACK(%d) for TCB %p\n", Seg->Ack, Tcb)); 189 } 190 } 191 } 192 193 194 /** 195 Compute the RTT as specified in RFC2988. 196 197 @param Tcb Pointer to the TCP_CB of this TCP instance. 198 @param Measure Currently measured RTT in heart beats. 199 200 **/ 201 VOID 202 TcpComputeRtt ( 203 IN OUT TCP_CB *Tcb, 204 IN UINT32 Measure 205 ) 206 { 207 INT32 Var; 208 209 // 210 // Step 2.3: Compute the RTO for subsequent RTT measurement. 211 // 212 if (Tcb->SRtt != 0) { 213 214 Var = Tcb->SRtt - (Measure << TCP_RTT_SHIFT); 215 216 if (Var < 0) { 217 Var = -Var; 218 } 219 220 Tcb->RttVar = (3 * Tcb->RttVar + Var) >> 2; 221 Tcb->SRtt = 7 * (Tcb->SRtt >> 3) + Measure; 222 223 } else { 224 // 225 // Step 2.2: compute the first RTT measure 226 // 227 Tcb->SRtt = Measure << TCP_RTT_SHIFT; 228 Tcb->RttVar = Measure << (TCP_RTT_SHIFT - 1); 229 } 230 231 Tcb->Rto = (Tcb->SRtt + MAX (8, 4 * Tcb->RttVar)) >> TCP_RTT_SHIFT; 232 233 // 234 // Step 2.4: Limit the RTO to at least 1 second 235 // Step 2.5: Limit the RTO to a maxium value that 236 // is at least 60 second 237 // 238 if (Tcb->Rto < TCP_RTO_MIN) { 239 Tcb->Rto = TCP_RTO_MIN; 240 241 } else if (Tcb->Rto > TCP_RTO_MAX) { 242 Tcb->Rto = TCP_RTO_MAX; 243 244 } 245 246 DEBUG ((EFI_D_INFO, "TcpComputeRtt: new RTT for TCB %p" 247 " computed SRTT: %d RTTVAR: %d RTO: %d\n", 248 Tcb, Tcb->SRtt, Tcb->RttVar, Tcb->Rto)); 249 250 } 251 252 253 /** 254 Trim the data, SYN and FIN to fit into the window defined by Left and Right. 255 256 @param Nbuf Buffer that contains received TCP segment without IP header. 257 @param Left The sequence number of the window's left edge. 258 @param Right The sequence number of the window's right edge. 259 260 **/ 261 VOID 262 TcpTrimSegment ( 263 IN NET_BUF *Nbuf, 264 IN TCP_SEQNO Left, 265 IN TCP_SEQNO Right 266 ) 267 { 268 TCP_SEG *Seg; 269 TCP_SEQNO Urg; 270 UINT32 Drop; 271 272 Seg = TCPSEG_NETBUF (Nbuf); 273 274 // 275 // If the segment is completely out of window, 276 // truncate every thing, include SYN and FIN. 277 // 278 if (TCP_SEQ_LEQ (Seg->End, Left) || TCP_SEQ_LEQ (Right, Seg->Seq)) { 279 280 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN); 281 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN); 282 283 Seg->Seq = Seg->End; 284 NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_HEAD); 285 return; 286 } 287 288 // 289 // Adjust the buffer header 290 // 291 if (TCP_SEQ_LT (Seg->Seq, Left)) { 292 293 Drop = TCP_SUB_SEQ (Left, Seg->Seq); 294 Urg = Seg->Seq + Seg->Urg; 295 Seg->Seq = Left; 296 297 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) { 298 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN); 299 Drop--; 300 } 301 302 // 303 // Adjust the urgent point 304 // 305 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG)) { 306 307 if (TCP_SEQ_LT (Urg, Seg->Seq)) { 308 309 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG); 310 } else { 311 Seg->Urg = (UINT16) TCP_SUB_SEQ (Urg, Seg->Seq); 312 } 313 } 314 315 if (Drop != 0) { 316 NetbufTrim (Nbuf, Drop, NET_BUF_HEAD); 317 } 318 } 319 320 // 321 // Adjust the buffer tail 322 // 323 if (TCP_SEQ_GT (Seg->End, Right)) { 324 325 Drop = TCP_SUB_SEQ (Seg->End, Right); 326 Seg->End = Right; 327 328 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) { 329 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN); 330 Drop--; 331 } 332 333 if (Drop != 0) { 334 NetbufTrim (Nbuf, Drop, NET_BUF_TAIL); 335 } 336 } 337 338 ASSERT (TcpVerifySegment (Nbuf) != 0); 339 } 340 341 342 /** 343 Trim off the data outside the tcb's receive window. 344 345 @param Tcb Pointer to the TCP_CB of this TCP instance. 346 @param Nbuf Pointer to the NET_BUF containing the received tcp segment. 347 348 **/ 349 VOID 350 TcpTrimInWnd ( 351 IN TCP_CB *Tcb, 352 IN NET_BUF *Nbuf 353 ) 354 { 355 TcpTrimSegment (Nbuf, Tcb->RcvNxt, Tcb->RcvWl2 + Tcb->RcvWnd); 356 } 357 358 359 /** 360 Process the data and FIN flag, check whether to deliver 361 data to the socket layer. 362 363 @param Tcb Pointer to the TCP_CB of this TCP instance. 364 365 @retval 0 No error occurred to deliver data. 366 @retval -1 Error condition occurred. Proper response is to reset the 367 connection. 368 369 **/ 370 INTN 371 TcpDeliverData ( 372 IN OUT TCP_CB *Tcb 373 ) 374 { 375 LIST_ENTRY *Entry; 376 NET_BUF *Nbuf; 377 TCP_SEQNO Seq; 378 TCP_SEG *Seg; 379 UINT32 Urgent; 380 381 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL)); 382 383 // 384 // make sure there is some data queued, 385 // and TCP is in a proper state 386 // 387 if (IsListEmpty (&Tcb->RcvQue) || !TCP_CONNECTED (Tcb->State)) { 388 389 return 0; 390 } 391 392 // 393 // Deliver data to the socket layer 394 // 395 Entry = Tcb->RcvQue.ForwardLink; 396 Seq = Tcb->RcvNxt; 397 398 while (Entry != &Tcb->RcvQue) { 399 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List); 400 Seg = TCPSEG_NETBUF (Nbuf); 401 402 ASSERT (TcpVerifySegment (Nbuf) != 0); 403 ASSERT (Nbuf->Tcp == NULL); 404 405 if (TCP_SEQ_GT (Seg->Seq, Seq)) { 406 break; 407 } 408 409 Entry = Entry->ForwardLink; 410 Seq = Seg->End; 411 Tcb->RcvNxt = Seq; 412 413 RemoveEntryList (&Nbuf->List); 414 415 // 416 // RFC793 Eighth step: process FIN in sequence 417 // 418 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) { 419 420 // 421 // The peer sends to us junky data after FIN, 422 // reset the connection. 423 // 424 if (!IsListEmpty (&Tcb->RcvQue)) { 425 DEBUG ((EFI_D_ERROR, "TcpDeliverData: data received after" 426 " FIN from peer of TCB %p, reset connection\n", Tcb)); 427 428 NetbufFree (Nbuf); 429 return -1; 430 } 431 432 DEBUG ((EFI_D_INFO, "TcpDeliverData: processing FIN " 433 "from peer of TCB %p\n", Tcb)); 434 435 switch (Tcb->State) { 436 case TCP_SYN_RCVD: 437 case TCP_ESTABLISHED: 438 439 TcpSetState (Tcb, TCP_CLOSE_WAIT); 440 break; 441 442 case TCP_FIN_WAIT_1: 443 444 if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) { 445 446 TcpSetState (Tcb, TCP_CLOSING); 447 break; 448 } 449 450 // 451 // fall through 452 // 453 case TCP_FIN_WAIT_2: 454 455 TcpSetState (Tcb, TCP_TIME_WAIT); 456 TcpClearAllTimer (Tcb); 457 458 if (Tcb->TimeWaitTimeout != 0) { 459 460 TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout); 461 } else { 462 463 DEBUG ((EFI_D_WARN, "Connection closed immediately " 464 "because app disables TIME_WAIT timer for %p\n", Tcb)); 465 466 TcpSendAck (Tcb); 467 TcpClose (Tcb); 468 } 469 break; 470 471 case TCP_CLOSE_WAIT: 472 case TCP_CLOSING: 473 case TCP_LAST_ACK: 474 case TCP_TIME_WAIT: 475 // 476 // The peer sends to us junk FIN byte. Discard 477 // the buffer then reset the connection 478 // 479 NetbufFree (Nbuf); 480 return -1; 481 default: 482 break; 483 } 484 485 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW); 486 487 Seg->End--; 488 } 489 490 // 491 // Don't delay the ack if PUSH flag is on. 492 // 493 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_PSH)) { 494 495 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW); 496 } 497 498 if (Nbuf->TotalSize != 0) { 499 Urgent = 0; 500 501 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) && 502 TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvUp)) { 503 504 if (TCP_SEQ_LEQ (Seg->End, Tcb->RcvUp)) { 505 Urgent = Nbuf->TotalSize; 506 } else { 507 Urgent = TCP_SUB_SEQ (Tcb->RcvUp, Seg->Seq) + 1; 508 } 509 } 510 511 SockDataRcvd (Tcb->Sk, Nbuf, Urgent); 512 } 513 514 if (TCP_FIN_RCVD (Tcb->State)) { 515 516 SockNoMoreData (Tcb->Sk); 517 } 518 519 NetbufFree (Nbuf); 520 } 521 522 return 0; 523 } 524 525 526 /** 527 Store the data into the reassemble queue. 528 529 @param Tcb Pointer to the TCP_CB of this TCP instance. 530 @param Nbuf Pointer to the buffer containing the data to be queued. 531 532 **/ 533 VOID 534 TcpQueueData ( 535 IN OUT TCP_CB *Tcb, 536 IN NET_BUF *Nbuf 537 ) 538 { 539 TCP_SEG *Seg; 540 LIST_ENTRY *Head; 541 LIST_ENTRY *Prev; 542 LIST_ENTRY *Cur; 543 NET_BUF *Node; 544 545 ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL)); 546 547 NET_GET_REF (Nbuf); 548 549 Seg = TCPSEG_NETBUF (Nbuf); 550 Head = &Tcb->RcvQue; 551 552 // 553 // Fast path to process normal case. That is, 554 // no out-of-order segments are received. 555 // 556 if (IsListEmpty (Head)) { 557 558 InsertTailList (Head, &Nbuf->List); 559 return; 560 } 561 562 // 563 // Find the point to insert the buffer 564 // 565 for (Prev = Head, Cur = Head->ForwardLink; 566 Cur != Head; 567 Prev = Cur, Cur = Cur->ForwardLink) { 568 569 Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List); 570 571 if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->Seq)) { 572 break; 573 } 574 } 575 576 // 577 // Check whether the current segment overlaps with the 578 // previous segment. 579 // 580 if (Prev != Head) { 581 Node = NET_LIST_USER_STRUCT (Prev, NET_BUF, List); 582 583 if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->End)) { 584 585 if (TCP_SEQ_LEQ (Seg->End, TCPSEG_NETBUF (Node)->End)) { 586 587 NetbufFree (Nbuf); 588 return; 589 } 590 591 TcpTrimSegment (Nbuf, TCPSEG_NETBUF (Node)->End, Seg->End); 592 } 593 } 594 595 InsertHeadList (Prev, &Nbuf->List); 596 597 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW); 598 599 // 600 // Check the segments after the insert point. 601 // 602 while (Cur != Head) { 603 Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List); 604 605 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->End, Seg->End)) { 606 607 Cur = Cur->ForwardLink; 608 609 RemoveEntryList (&Node->List); 610 NetbufFree (Node); 611 continue; 612 } 613 614 if (TCP_SEQ_LT (TCPSEG_NETBUF (Node)->Seq, Seg->End)) { 615 616 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->Seq, Seg->Seq)) { 617 618 RemoveEntryList (&Nbuf->List); 619 NetbufFree (Nbuf); 620 return ; 621 } 622 623 TcpTrimSegment (Nbuf, Seg->Seq, TCPSEG_NETBUF (Node)->Seq); 624 break; 625 } 626 627 Cur = Cur->ForwardLink; 628 } 629 } 630 631 632 /** 633 Ajust the send queue or the retransmit queue. 634 635 @param Tcb Pointer to the TCP_CB of this TCP instance. 636 @param Ack The acknowledge seuqence number of the received segment. 637 638 **/ 639 VOID 640 TcpAdjustSndQue ( 641 IN TCP_CB *Tcb, 642 IN TCP_SEQNO Ack 643 ) 644 { 645 LIST_ENTRY *Head; 646 LIST_ENTRY *Cur; 647 NET_BUF *Node; 648 TCP_SEG *Seg; 649 650 Head = &Tcb->SndQue; 651 Cur = Head->ForwardLink; 652 653 while (Cur != Head) { 654 Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List); 655 Seg = TCPSEG_NETBUF (Node); 656 657 if (TCP_SEQ_GEQ (Seg->Seq, Ack)) { 658 break; 659 } 660 661 // 662 // Remove completely ACKed segments 663 // 664 if (TCP_SEQ_LEQ (Seg->End, Ack)) { 665 Cur = Cur->ForwardLink; 666 667 RemoveEntryList (&Node->List); 668 NetbufFree (Node); 669 continue; 670 } 671 672 TcpTrimSegment (Node, Ack, Seg->End); 673 break; 674 } 675 } 676 677 678 /** 679 Process the received TCP segments. 680 681 @param Nbuf Buffer that contains received TCP segment without IP header. 682 @param Src Source address of the segment, or the peer's IP address. 683 @param Dst Destination address of the segment, or the local end's IP 684 address. 685 686 @retval 0 Segment is processed successfully. It is either accepted or 687 discarded. But no connection is reset by the segment. 688 @retval -1 A connection is reset by the segment. 689 690 **/ 691 INTN 692 TcpInput ( 693 IN NET_BUF *Nbuf, 694 IN UINT32 Src, 695 IN UINT32 Dst 696 ) 697 { 698 TCP_CB *Tcb; 699 TCP_CB *Parent; 700 TCP_OPTION Option; 701 TCP_HEAD *Head; 702 INT32 Len; 703 TCP_SEG *Seg; 704 TCP_SEQNO Right; 705 TCP_SEQNO Urg; 706 707 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE); 708 709 Parent = NULL; 710 Tcb = NULL; 711 712 Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL); 713 ASSERT (Head != NULL); 714 Len = Nbuf->TotalSize - (Head->HeadLen << 2); 715 716 if ((Head->HeadLen < 5) || (Len < 0) || 717 (TcpChecksum (Nbuf, NetPseudoHeadChecksum (Src, Dst, 6, 0)) != 0)) { 718 719 DEBUG ((EFI_D_INFO, "TcpInput: received an mal-formated packet\n")); 720 goto DISCARD; 721 } 722 723 if (TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)) { 724 Len++; 725 } 726 727 if (TCP_FLG_ON (Head->Flag, TCP_FLG_FIN)) { 728 Len++; 729 } 730 731 Tcb = TcpLocateTcb ( 732 Head->DstPort, 733 Dst, 734 Head->SrcPort, 735 Src, 736 (BOOLEAN) TCP_FLG_ON (Head->Flag, TCP_FLG_SYN) 737 ); 738 739 if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) { 740 DEBUG ((EFI_D_INFO, "TcpInput: send reset because no TCB found\n")); 741 742 Tcb = NULL; 743 goto SEND_RESET; 744 } 745 746 Seg = TcpFormatNetbuf (Tcb, Nbuf); 747 748 // 749 // RFC1122 recommended reaction to illegal option 750 // (in fact, an illegal option length) is reset. 751 // 752 if (TcpParseOption (Nbuf->Tcp, &Option) == -1) { 753 DEBUG ((EFI_D_ERROR, "TcpInput: reset the peer because" 754 " of malformed option for TCB %p\n", Tcb)); 755 756 goto SEND_RESET; 757 } 758 759 // 760 // From now on, the segment is headless 761 // 762 NetbufTrim (Nbuf, (Head->HeadLen << 2), NET_BUF_HEAD); 763 Nbuf->Tcp = NULL; 764 765 // 766 // Process the segment in LISTEN state. 767 // 768 if (Tcb->State == TCP_LISTEN) { 769 // 770 // First step: Check RST 771 // 772 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) { 773 DEBUG ((EFI_D_WARN, "TcpInput: discard a reset segment " 774 "for TCB %p in listening\n", Tcb)); 775 776 goto DISCARD; 777 } 778 779 // 780 // Second step: Check ACK. 781 // Any ACK sent to TCP in LISTEN is reseted. 782 // 783 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) { 784 DEBUG ((EFI_D_WARN, "TcpInput: send reset because of" 785 " segment with ACK for TCB %p in listening\n", Tcb)); 786 787 goto SEND_RESET; 788 } 789 790 // 791 // Third step: Check SYN 792 // 793 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) { 794 // 795 // create a child TCB to handle the data 796 // 797 Parent = Tcb; 798 799 Tcb = TcpCloneTcb (Parent); 800 if (Tcb == NULL) { 801 DEBUG ((EFI_D_ERROR, "TcpInput: discard a segment because" 802 " failed to clone a child for TCB %p\n", Tcb)); 803 804 goto DISCARD; 805 } 806 807 DEBUG ((EFI_D_INFO, "TcpInput: create a child for TCB %p" 808 " in listening\n", Tcb)); 809 810 // 811 // init the TCB structure 812 // 813 Tcb->LocalEnd.Ip = Dst; 814 Tcb->LocalEnd.Port = Head->DstPort; 815 Tcb->RemoteEnd.Ip = Src; 816 Tcb->RemoteEnd.Port = Head->SrcPort; 817 818 TcpInitTcbLocal (Tcb); 819 TcpInitTcbPeer (Tcb, Seg, &Option); 820 821 TcpSetState (Tcb, TCP_SYN_RCVD); 822 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout); 823 TcpTrimInWnd (Tcb, Nbuf); 824 825 goto StepSix; 826 } 827 828 goto DISCARD; 829 830 } else if (Tcb->State == TCP_SYN_SENT) { 831 // 832 // First step: Check ACK bit 833 // 834 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK) && (Seg->Ack != Tcb->Iss + 1)) { 835 836 DEBUG ((EFI_D_WARN, "TcpInput: send reset because of " 837 "wrong ACK received for TCB %p in SYN_SENT\n", Tcb)); 838 839 goto SEND_RESET; 840 } 841 842 // 843 // Second step: Check RST bit 844 // 845 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) { 846 847 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) { 848 849 DEBUG ((EFI_D_WARN, "TcpInput: connection reset by" 850 " peer for TCB %p in SYN_SENT\n", Tcb)); 851 852 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET); 853 goto DROP_CONNECTION; 854 } else { 855 856 DEBUG ((EFI_D_WARN, "TcpInput: discard a reset segment " 857 "because of no ACK for TCB %p in SYN_SENT\n", Tcb)); 858 859 goto DISCARD; 860 } 861 } 862 863 // 864 // Third step: Check security and precedence. Skipped 865 // 866 867 // 868 // Fourth step: Check SYN. Pay attention to simultaneous open 869 // 870 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) { 871 872 TcpInitTcbPeer (Tcb, Seg, &Option); 873 874 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) { 875 876 Tcb->SndUna = Seg->Ack; 877 } 878 879 TcpClearTimer (Tcb, TCP_TIMER_REXMIT); 880 881 if (TCP_SEQ_GT (Tcb->SndUna, Tcb->Iss)) { 882 883 TcpSetState (Tcb, TCP_ESTABLISHED); 884 885 TcpClearTimer (Tcb, TCP_TIMER_CONNECT); 886 TcpDeliverData (Tcb); 887 888 if ((Tcb->CongestState == TCP_CONGEST_OPEN) && 889 TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) { 890 891 TcpComputeRtt (Tcb, Tcb->RttMeasure); 892 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON); 893 } 894 895 TcpTrimInWnd (Tcb, Nbuf); 896 897 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW); 898 899 DEBUG ((EFI_D_INFO, "TcpInput: connection established" 900 " for TCB %p in SYN_SENT\n", Tcb)); 901 902 goto StepSix; 903 } else { 904 // 905 // Received a SYN segment without ACK, simultaneous open. 906 // 907 TcpSetState (Tcb, TCP_SYN_RCVD); 908 909 ASSERT (Tcb->SndNxt == Tcb->Iss + 1); 910 TcpAdjustSndQue (Tcb, Tcb->SndNxt); 911 912 TcpTrimInWnd (Tcb, Nbuf); 913 914 DEBUG ((EFI_D_WARN, "TcpInput: simultaneous open " 915 "for TCB %p in SYN_SENT\n", Tcb)); 916 917 goto StepSix; 918 } 919 } 920 921 goto DISCARD; 922 } 923 924 // 925 // Process segment in SYN_RCVD or TCP_CONNECTED states 926 // 927 928 // 929 // Clear probe timer since the RecvWindow is opened. 930 // 931 if (Tcb->ProbeTimerOn && (Seg->Wnd != 0)) { 932 TcpClearTimer (Tcb, TCP_TIMER_PROBE); 933 Tcb->ProbeTimerOn = FALSE; 934 } 935 936 // 937 // First step: Check whether SEG.SEQ is acceptable 938 // 939 if (TcpSeqAcceptable (Tcb, Seg) == 0) { 940 DEBUG ((EFI_D_WARN, "TcpInput: sequence acceptance" 941 " test failed for segment of TCB %p\n", Tcb)); 942 943 if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) { 944 TcpSendAck (Tcb); 945 } 946 947 goto DISCARD; 948 } 949 950 if ((TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2)) && 951 (Tcb->RcvWl2 == Seg->End) && 952 !TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN)) { 953 954 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW); 955 } 956 957 // 958 // Second step: Check the RST 959 // 960 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) { 961 962 DEBUG ((EFI_D_WARN, "TcpInput: connection reset for TCB %p\n", Tcb)); 963 964 if (Tcb->State == TCP_SYN_RCVD) { 965 966 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_REFUSED); 967 968 // 969 // This TCB comes from either a LISTEN TCB, 970 // or active open TCB with simultanous open. 971 // Do NOT signal user CONNECTION refused 972 // if it comes from a LISTEN TCB. 973 // 974 } else if ((Tcb->State == TCP_ESTABLISHED) || 975 (Tcb->State == TCP_FIN_WAIT_1) || 976 (Tcb->State == TCP_FIN_WAIT_2) || 977 (Tcb->State == TCP_CLOSE_WAIT)) { 978 979 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET); 980 981 } else { 982 983 } 984 985 goto DROP_CONNECTION; 986 } 987 988 // 989 // Trim the data and flags. 990 // 991 TcpTrimInWnd (Tcb, Nbuf); 992 993 // 994 // Third step: Check security and precedence, Ignored 995 // 996 997 // 998 // Fourth step: Check the SYN bit. 999 // 1000 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) { 1001 1002 DEBUG ((EFI_D_WARN, "TcpInput: connection reset " 1003 "because received extra SYN for TCB %p\n", Tcb)); 1004 1005 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET); 1006 goto RESET_THEN_DROP; 1007 } 1008 1009 // 1010 // Fifth step: Check the ACK 1011 // 1012 if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) { 1013 DEBUG ((EFI_D_WARN, "TcpInput: segment discard because" 1014 " of no ACK for connected TCB %p\n", Tcb)); 1015 1016 goto DISCARD; 1017 1018 } 1019 1020 if (Tcb->State == TCP_SYN_RCVD) { 1021 1022 if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) && 1023 TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt)) { 1024 1025 Tcb->SndWnd = Seg->Wnd; 1026 Tcb->SndWndMax = MAX (Tcb->SndWnd, Tcb->SndWndMax); 1027 Tcb->SndWl1 = Seg->Seq; 1028 Tcb->SndWl2 = Seg->Ack; 1029 TcpSetState (Tcb, TCP_ESTABLISHED); 1030 1031 TcpClearTimer (Tcb, TCP_TIMER_CONNECT); 1032 TcpDeliverData (Tcb); 1033 1034 DEBUG ((EFI_D_INFO, "TcpInput: connection established " 1035 " for TCB %p in SYN_RCVD\n", Tcb)); 1036 1037 // 1038 // Continue the process as ESTABLISHED state 1039 // 1040 } else { 1041 DEBUG ((EFI_D_WARN, "TcpInput: send reset because of" 1042 " wrong ACK for TCB %p in SYN_RCVD\n", Tcb)); 1043 1044 goto SEND_RESET; 1045 } 1046 } 1047 1048 if (TCP_SEQ_LT (Seg->Ack, Tcb->SndUna)) { 1049 1050 DEBUG ((EFI_D_WARN, "TcpInput: ignore the out-of-data" 1051 " ACK for connected TCB %p\n", Tcb)); 1052 1053 goto StepSix; 1054 1055 } else if (TCP_SEQ_GT (Seg->Ack, Tcb->SndNxt)) { 1056 1057 DEBUG ((EFI_D_WARN, "TcpInput: discard segment for " 1058 "future ACK for connected TCB %p\n", Tcb)); 1059 1060 TcpSendAck (Tcb); 1061 goto DISCARD; 1062 } 1063 1064 // 1065 // From now on: SND.UNA <= SEG.ACK <= SND.NXT. 1066 // 1067 if (TCP_FLG_ON (Option.Flag, TCP_OPTION_RCVD_TS)) { 1068 // 1069 // update TsRecent as specified in page 16 RFC1323. 1070 // RcvWl2 equals to the variable "LastAckSent" 1071 // defined there. 1072 // 1073 if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) && 1074 TCP_SEQ_LT (Tcb->RcvWl2, Seg->End)) { 1075 1076 Tcb->TsRecent = Option.TSVal; 1077 Tcb->TsRecentAge = mTcpTick; 1078 } 1079 1080 TcpComputeRtt (Tcb, TCP_SUB_TIME (mTcpTick, Option.TSEcr)); 1081 1082 } else if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) { 1083 1084 ASSERT (Tcb->CongestState == TCP_CONGEST_OPEN); 1085 1086 TcpComputeRtt (Tcb, Tcb->RttMeasure); 1087 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON); 1088 } 1089 1090 if (Seg->Ack == Tcb->SndNxt) { 1091 1092 TcpClearTimer (Tcb, TCP_TIMER_REXMIT); 1093 } else { 1094 1095 TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto); 1096 } 1097 1098 // 1099 // Count duplicate acks. 1100 // 1101 if ((Seg->Ack == Tcb->SndUna) && 1102 (Tcb->SndUna != Tcb->SndNxt) && 1103 (Seg->Wnd == Tcb->SndWnd) && 1104 (0 == Len)) { 1105 1106 Tcb->DupAck++; 1107 } else { 1108 1109 Tcb->DupAck = 0; 1110 } 1111 1112 // 1113 // Congestion avoidance, fast recovery and fast retransmission. 1114 // 1115 if (((Tcb->CongestState == TCP_CONGEST_OPEN) && (Tcb->DupAck < 3)) || 1116 (Tcb->CongestState == TCP_CONGEST_LOSS)) { 1117 1118 if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) { 1119 1120 if (Tcb->CWnd < Tcb->Ssthresh) { 1121 1122 Tcb->CWnd += Tcb->SndMss; 1123 } else { 1124 1125 Tcb->CWnd += MAX (Tcb->SndMss * Tcb->SndMss / Tcb->CWnd, 1); 1126 } 1127 1128 Tcb->CWnd = MIN (Tcb->CWnd, TCP_MAX_WIN << Tcb->SndWndScale); 1129 } 1130 1131 if (Tcb->CongestState == TCP_CONGEST_LOSS) { 1132 TcpFastLossRecover (Tcb, Seg); 1133 } 1134 } else { 1135 1136 TcpFastRecover (Tcb, Seg); 1137 } 1138 1139 if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) { 1140 1141 TcpAdjustSndQue (Tcb, Seg->Ack); 1142 Tcb->SndUna = Seg->Ack; 1143 1144 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) && 1145 TCP_SEQ_LT (Tcb->SndUp, Seg->Ack)) { 1146 1147 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG); 1148 } 1149 } 1150 1151 // 1152 // Update window info 1153 // 1154 if (TCP_SEQ_LT (Tcb->SndWl1, Seg->Seq) || 1155 ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack))) { 1156 1157 Right = Seg->Ack + Seg->Wnd; 1158 1159 if (TCP_SEQ_LT (Right, Tcb->SndWl2 + Tcb->SndWnd)) { 1160 1161 if ((Tcb->SndWl1 == Seg->Seq) && 1162 (Tcb->SndWl2 == Seg->Ack) && 1163 (Len == 0)) { 1164 1165 goto NO_UPDATE; 1166 } 1167 1168 DEBUG ((EFI_D_WARN, "TcpInput: peer shrinks the" 1169 " window for connected TCB %p\n", Tcb)); 1170 1171 if ((Tcb->CongestState == TCP_CONGEST_RECOVER) && 1172 (TCP_SEQ_LT (Right, Tcb->Recover))) { 1173 1174 Tcb->Recover = Right; 1175 } 1176 1177 if ((Tcb->CongestState == TCP_CONGEST_LOSS) && 1178 (TCP_SEQ_LT (Right, Tcb->LossRecover))) { 1179 1180 Tcb->LossRecover = Right; 1181 } 1182 1183 if (TCP_SEQ_LT (Right, Tcb->SndNxt)) { 1184 1185 Tcb->SndNxt = Right; 1186 1187 if (Right == Tcb->SndUna) { 1188 1189 TcpClearTimer (Tcb, TCP_TIMER_REXMIT); 1190 TcpSetProbeTimer (Tcb); 1191 } 1192 } 1193 } 1194 1195 Tcb->SndWnd = Seg->Wnd; 1196 Tcb->SndWndMax = MAX (Tcb->SndWnd, Tcb->SndWndMax); 1197 Tcb->SndWl1 = Seg->Seq; 1198 Tcb->SndWl2 = Seg->Ack; 1199 } 1200 1201 NO_UPDATE: 1202 1203 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) && 1204 (Tcb->SndUna == Tcb->SndNxt)) { 1205 1206 DEBUG ((EFI_D_INFO, "TcpInput: local FIN is ACKed by" 1207 " peer for connected TCB %p\n", Tcb)); 1208 1209 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED); 1210 } 1211 1212 // 1213 // Transit the state if proper. 1214 // 1215 switch (Tcb->State) { 1216 case TCP_FIN_WAIT_1: 1217 1218 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) { 1219 1220 TcpSetState (Tcb, TCP_FIN_WAIT_2); 1221 1222 TcpClearAllTimer (Tcb); 1223 TcpSetTimer (Tcb, TCP_TIMER_FINWAIT2, Tcb->FinWait2Timeout); 1224 } 1225 1226 case TCP_FIN_WAIT_2: 1227 1228 break; 1229 1230 case TCP_CLOSE_WAIT: 1231 break; 1232 1233 case TCP_CLOSING: 1234 1235 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) { 1236 1237 TcpSetState (Tcb, TCP_TIME_WAIT); 1238 1239 TcpClearAllTimer (Tcb); 1240 1241 if (Tcb->TimeWaitTimeout != 0) { 1242 1243 TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout); 1244 } else { 1245 1246 DEBUG ((EFI_D_WARN, "Connection closed immediately " 1247 "because app disables TIME_WAIT timer for %p\n", Tcb)); 1248 1249 TcpClose (Tcb); 1250 } 1251 } 1252 break; 1253 1254 case TCP_LAST_ACK: 1255 1256 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) { 1257 1258 TcpSetState (Tcb, TCP_CLOSED); 1259 } 1260 1261 break; 1262 1263 case TCP_TIME_WAIT: 1264 1265 TcpSendAck (Tcb); 1266 1267 if (Tcb->TimeWaitTimeout != 0) { 1268 1269 TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout); 1270 } else { 1271 1272 DEBUG ((EFI_D_WARN, "Connection closed immediately " 1273 "because app disables TIME_WAIT timer for %p\n", Tcb)); 1274 1275 TcpClose (Tcb); 1276 } 1277 break; 1278 1279 default: 1280 break; 1281 } 1282 1283 // 1284 // Sixth step: Check the URG bit.update the Urg point 1285 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact. 1286 // 1287 StepSix: 1288 1289 Tcb->Idle = 0; 1290 TcpSetKeepaliveTimer (Tcb); 1291 1292 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) && 1293 !TCP_FIN_RCVD (Tcb->State)) 1294 { 1295 1296 DEBUG ((EFI_D_INFO, "TcpInput: received urgent data " 1297 "from peer for connected TCB %p\n", Tcb)); 1298 1299 Urg = Seg->Seq + Seg->Urg; 1300 1301 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) && 1302 TCP_SEQ_GT (Urg, Tcb->RcvUp)) { 1303 1304 Tcb->RcvUp = Urg; 1305 } else { 1306 1307 Tcb->RcvUp = Urg; 1308 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG); 1309 } 1310 } 1311 1312 // 1313 // Seventh step: Process the segment data 1314 // 1315 if (Seg->End != Seg->Seq) { 1316 1317 if (TCP_FIN_RCVD (Tcb->State)) { 1318 1319 DEBUG ((EFI_D_WARN, "TcpInput: connection reset because" 1320 " data is lost for connected TCB %p\n", Tcb)); 1321 1322 goto RESET_THEN_DROP; 1323 } 1324 1325 if (TCP_LOCAL_CLOSED (Tcb->State) && (Nbuf->TotalSize != 0)) { 1326 DEBUG ((EFI_D_WARN, "TcpInput: connection reset because" 1327 " data is lost for connected TCB %p\n", Tcb)); 1328 1329 goto RESET_THEN_DROP; 1330 } 1331 1332 TcpQueueData (Tcb, Nbuf); 1333 if (TcpDeliverData (Tcb) == -1) { 1334 goto RESET_THEN_DROP; 1335 } 1336 1337 if (!IsListEmpty (&Tcb->RcvQue)) { 1338 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW); 1339 } 1340 } 1341 1342 // 1343 // Eighth step: check the FIN. 1344 // This step is moved to TcpDeliverData. FIN will be 1345 // processed in sequence there. Check the comments in 1346 // the beginning of the file header for information. 1347 // 1348 1349 // 1350 // Tcb is a new child of the listening Parent, 1351 // commit it. 1352 // 1353 if (Parent != NULL) { 1354 Tcb->Parent = Parent; 1355 TcpInsertTcb (Tcb); 1356 } 1357 1358 if ((Tcb->State != TCP_CLOSED) && 1359 (TcpToSendData (Tcb, 0) == 0) && 1360 (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || (Nbuf->TotalSize != 0))) { 1361 1362 TcpToSendAck (Tcb); 1363 } 1364 1365 NetbufFree (Nbuf); 1366 return 0; 1367 1368 RESET_THEN_DROP: 1369 TcpSendReset (Tcb, Head, Len, Dst, Src); 1370 1371 DROP_CONNECTION: 1372 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL)); 1373 1374 NetbufFree (Nbuf); 1375 TcpClose (Tcb); 1376 1377 return -1; 1378 1379 SEND_RESET: 1380 1381 TcpSendReset (Tcb, Head, Len, Dst, Src); 1382 1383 DISCARD: 1384 1385 // 1386 // Tcb is a child of Parent, and it doesn't survive 1387 // 1388 DEBUG ((EFI_D_WARN, "Tcp4Input: Discard a packet\n")); 1389 NetbufFree (Nbuf); 1390 1391 if ((Parent != NULL) && (Tcb != NULL)) { 1392 1393 ASSERT (Tcb->Sk != NULL); 1394 TcpClose (Tcb); 1395 } 1396 1397 return 0; 1398 } 1399 1400 1401 /** 1402 Process the received ICMP error messages for TCP. 1403 1404 @param Nbuf Buffer that contains part of the TCP segment without IP header 1405 truncated from the ICMP error packet. 1406 @param IcmpErr The ICMP error code interpreted from ICMP error packet. 1407 @param Src Source address of the ICMP error message. 1408 @param Dst Destination address of the ICMP error message. 1409 1410 **/ 1411 VOID 1412 TcpIcmpInput ( 1413 IN NET_BUF *Nbuf, 1414 IN UINT8 IcmpErr, 1415 IN UINT32 Src, 1416 IN UINT32 Dst 1417 ) 1418 { 1419 TCP_HEAD *Head; 1420 TCP_CB *Tcb; 1421 TCP_SEQNO Seq; 1422 EFI_STATUS IcmpErrStatus; 1423 BOOLEAN IcmpErrIsHard; 1424 BOOLEAN IcmpErrNotify; 1425 1426 Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL); 1427 ASSERT (Head != NULL); 1428 Tcb = TcpLocateTcb ( 1429 Head->DstPort, 1430 Dst, 1431 Head->SrcPort, 1432 Src, 1433 FALSE 1434 ); 1435 if (Tcb == NULL || Tcb->State == TCP_CLOSED) { 1436 1437 goto CLEAN_EXIT; 1438 } 1439 1440 // 1441 // Validate the sequence number. 1442 // 1443 Seq = NTOHL (Head->Seq); 1444 if (!(TCP_SEQ_LEQ (Tcb->SndUna, Seq) && TCP_SEQ_LT (Seq, Tcb->SndNxt))) { 1445 1446 goto CLEAN_EXIT; 1447 } 1448 1449 IcmpErrStatus = IpIoGetIcmpErrStatus ( 1450 IcmpErr, 1451 IP_VERSION_4, 1452 &IcmpErrIsHard, 1453 &IcmpErrNotify 1454 ); 1455 1456 if (IcmpErrNotify) { 1457 1458 SOCK_ERROR (Tcb->Sk, IcmpErrStatus); 1459 } 1460 1461 if (IcmpErrIsHard) { 1462 1463 TcpClose (Tcb); 1464 } 1465 1466 CLEAN_EXIT: 1467 NetbufFree (Nbuf); 1468 } 1469