1 /** @file 2 Misc support routines for TCP driver. 3 4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR> 5 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR> 6 7 This program and the accompanying materials 8 are licensed and made available under the terms and conditions of the BSD License 9 which accompanies this distribution. The full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php. 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 #include "TcpMain.h" 18 19 LIST_ENTRY mTcpRunQue = { 20 &mTcpRunQue, 21 &mTcpRunQue 22 }; 23 24 LIST_ENTRY mTcpListenQue = { 25 &mTcpListenQue, 26 &mTcpListenQue 27 }; 28 29 TCP_SEQNO mTcpGlobalIss = TCP_BASE_ISS; 30 31 CHAR16 *mTcpStateName[] = { 32 L"TCP_CLOSED", 33 L"TCP_LISTEN", 34 L"TCP_SYN_SENT", 35 L"TCP_SYN_RCVD", 36 L"TCP_ESTABLISHED", 37 L"TCP_FIN_WAIT_1", 38 L"TCP_FIN_WAIT_2", 39 L"TCP_CLOSING", 40 L"TCP_TIME_WAIT", 41 L"TCP_CLOSE_WAIT", 42 L"TCP_LAST_ACK" 43 }; 44 45 46 /** 47 Initialize the Tcb local related members. 48 49 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. 50 51 **/ 52 VOID 53 TcpInitTcbLocal ( 54 IN OUT TCP_CB *Tcb 55 ) 56 { 57 // 58 // Compute the checksum of the fixed parts of pseudo header 59 // 60 if (Tcb->Sk->IpVersion == IP_VERSION_4) { 61 Tcb->HeadSum = NetPseudoHeadChecksum ( 62 Tcb->LocalEnd.Ip.Addr[0], 63 Tcb->RemoteEnd.Ip.Addr[0], 64 0x06, 65 0 66 ); 67 } else { 68 Tcb->HeadSum = NetIp6PseudoHeadChecksum ( 69 &Tcb->LocalEnd.Ip.v6, 70 &Tcb->RemoteEnd.Ip.v6, 71 0x06, 72 0 73 ); 74 } 75 76 Tcb->Iss = TcpGetIss (); 77 Tcb->SndUna = Tcb->Iss; 78 Tcb->SndNxt = Tcb->Iss; 79 80 Tcb->SndWl2 = Tcb->Iss; 81 Tcb->SndWnd = 536; 82 83 Tcb->RcvWnd = GET_RCV_BUFFSIZE (Tcb->Sk); 84 85 // 86 // First window size is never scaled 87 // 88 Tcb->RcvWndScale = 0; 89 90 Tcb->ProbeTimerOn = FALSE; 91 } 92 93 /** 94 Initialize the peer related members. 95 96 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. 97 @param[in] Seg Pointer to the segment that contains the peer's intial info. 98 @param[in] Opt Pointer to the options announced by the peer. 99 100 **/ 101 VOID 102 TcpInitTcbPeer ( 103 IN OUT TCP_CB *Tcb, 104 IN TCP_SEG *Seg, 105 IN TCP_OPTION *Opt 106 ) 107 { 108 UINT16 RcvMss; 109 110 ASSERT ((Tcb != NULL) && (Seg != NULL) && (Opt != NULL)); 111 ASSERT (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)); 112 113 Tcb->SndWnd = Seg->Wnd; 114 Tcb->SndWndMax = Tcb->SndWnd; 115 Tcb->SndWl1 = Seg->Seq; 116 117 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) { 118 Tcb->SndWl2 = Seg->Ack; 119 } else { 120 Tcb->SndWl2 = Tcb->Iss + 1; 121 } 122 123 if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_MSS)) { 124 Tcb->SndMss = (UINT16) MAX (64, Opt->Mss); 125 126 RcvMss = TcpGetRcvMss (Tcb->Sk); 127 if (Tcb->SndMss > RcvMss) { 128 Tcb->SndMss = RcvMss; 129 } 130 131 } else { 132 // 133 // One end doesn't support MSS option, use default. 134 // 135 Tcb->RcvMss = 536; 136 } 137 138 Tcb->CWnd = Tcb->SndMss; 139 140 Tcb->Irs = Seg->Seq; 141 Tcb->RcvNxt = Tcb->Irs + 1; 142 143 Tcb->RcvWl2 = Tcb->RcvNxt; 144 145 if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_WS) && !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS)) { 146 147 Tcb->SndWndScale = Opt->WndScale; 148 149 Tcb->RcvWndScale = TcpComputeScale (Tcb); 150 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS); 151 152 } else { 153 // 154 // One end doesn't support window scale option. use zero. 155 // 156 Tcb->RcvWndScale = 0; 157 } 158 159 if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_TS) && !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS)) { 160 161 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_TS); 162 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS); 163 164 Tcb->TsRecent = Opt->TSVal; 165 166 // 167 // Compute the effective SndMss per RFC1122 168 // section 4.2.2.6. If timestamp option is 169 // enabled, it will always occupy 12 bytes. 170 // 171 Tcb->SndMss -= TCP_OPTION_TS_ALIGNED_LEN; 172 } 173 } 174 175 /** 176 Check whether one IP address equals the other. 177 178 @param[in] Ip1 Pointer to IP address to be checked. 179 @param[in] Ip2 Pointer to IP address to be checked. 180 @param[in] Version IP_VERSION_4 indicates the IP address is an IPv4 address, 181 IP_VERSION_6 indicates the IP address is an IPv6 address. 182 183 @retval TRUE Ip1 equals Ip2. 184 @retval FALSE Ip1 does not equal Ip2. 185 186 **/ 187 BOOLEAN 188 TcpIsIpEqual ( 189 IN EFI_IP_ADDRESS *Ip1, 190 IN EFI_IP_ADDRESS *Ip2, 191 IN UINT8 Version 192 ) 193 { 194 ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6)); 195 196 if (Version == IP_VERSION_4) { 197 return (BOOLEAN) (Ip1->Addr[0] == Ip2->Addr[0]); 198 } else { 199 return (BOOLEAN) EFI_IP6_EQUAL (&Ip1->v6, &Ip2->v6); 200 } 201 } 202 203 /** 204 Check whether one IP address is filled with ZERO. 205 206 @param[in] Ip Pointer to the IP address to be checked. 207 @param[in] Version IP_VERSION_4 indicates the IP address is an IPv4 address, 208 IP_VERSION_6 indicates the IP address is an IPv6 address. 209 210 @retval TRUE Ip is all zero address. 211 @retval FALSE Ip is not all zero address. 212 213 **/ 214 BOOLEAN 215 TcpIsIpZero ( 216 IN EFI_IP_ADDRESS *Ip, 217 IN UINT8 Version 218 ) 219 { 220 ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6)); 221 222 if (Version == IP_VERSION_4) { 223 return (BOOLEAN) (Ip->Addr[0] == 0); 224 } else { 225 return (BOOLEAN) ((Ip->Addr[0] == 0) && (Ip->Addr[1] == 0) && 226 (Ip->Addr[2] == 0) && (Ip->Addr[3] == 0)); 227 } 228 } 229 230 /** 231 Locate a listen TCB that matchs the Local and Remote. 232 233 @param[in] Local Pointer to the local (IP, Port). 234 @param[in] Remote Pointer to the remote (IP, Port). 235 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack, 236 IP_VERSION_6 indicates TCP is running on IP6 stack. 237 238 @return Pointer to the TCP_CB with the least number of wildcards, 239 if NULL no match is found. 240 241 **/ 242 TCP_CB * 243 TcpLocateListenTcb ( 244 IN TCP_PEER *Local, 245 IN TCP_PEER *Remote, 246 IN UINT8 Version 247 ) 248 { 249 LIST_ENTRY *Entry; 250 TCP_CB *Node; 251 TCP_CB *Match; 252 INTN Last; 253 INTN Cur; 254 255 Last = 4; 256 Match = NULL; 257 258 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) { 259 Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List); 260 261 if ((Version != Node->Sk->IpVersion) || 262 (Local->Port != Node->LocalEnd.Port) || 263 !TCP_PEER_MATCH (Remote, &Node->RemoteEnd, Version) || 264 !TCP_PEER_MATCH (Local, &Node->LocalEnd, Version) 265 ) { 266 267 continue; 268 } 269 270 // 271 // Compute the number of wildcard 272 // 273 Cur = 0; 274 if (TcpIsIpZero (&Node->RemoteEnd.Ip, Version)) { 275 Cur++; 276 } 277 278 if (Node->RemoteEnd.Port == 0) { 279 Cur++; 280 } 281 282 if (TcpIsIpZero (&Node->LocalEnd.Ip, Version)) { 283 Cur++; 284 } 285 286 if (Cur < Last) { 287 if (Cur == 0) { 288 return Node; 289 } 290 291 Last = Cur; 292 Match = Node; 293 } 294 } 295 296 return Match; 297 } 298 299 /** 300 Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>. 301 302 @param[in] Addr Pointer to the IP address needs to match. 303 @param[in] Port The port number needs to match. 304 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack, 305 IP_VERSION_6 indicates TCP is running on IP6 stack. 306 307 308 @retval TRUE The Tcb which matches the <Addr Port> pair exists. 309 @retval FALSE Otherwise 310 311 **/ 312 BOOLEAN 313 TcpFindTcbByPeer ( 314 IN EFI_IP_ADDRESS *Addr, 315 IN TCP_PORTNO Port, 316 IN UINT8 Version 317 ) 318 { 319 TCP_PORTNO LocalPort; 320 LIST_ENTRY *Entry; 321 TCP_CB *Tcb; 322 323 ASSERT ((Addr != NULL) && (Port != 0)); 324 325 LocalPort = HTONS (Port); 326 327 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) { 328 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List); 329 330 if ((Version == Tcb->Sk->IpVersion) && 331 TcpIsIpEqual (Addr, &Tcb->LocalEnd.Ip, Version) && 332 (LocalPort == Tcb->LocalEnd.Port) 333 ) { 334 335 return TRUE; 336 } 337 } 338 339 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) { 340 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List); 341 342 if ((Version == Tcb->Sk->IpVersion) && 343 TcpIsIpEqual (Addr, &Tcb->LocalEnd.Ip, Version) && 344 (LocalPort == Tcb->LocalEnd.Port) 345 ) { 346 347 return TRUE; 348 } 349 } 350 351 return FALSE; 352 } 353 354 /** 355 Locate the TCP_CB related to the socket pair. 356 357 @param[in] LocalPort The local port number. 358 @param[in] LocalIp The local IP address. 359 @param[in] RemotePort The remote port number. 360 @param[in] RemoteIp The remote IP address. 361 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack, 362 IP_VERSION_6 indicates TCP is running on IP6 stack. 363 @param[in] Syn If TRUE, the listen sockets are searched. 364 365 @return Pointer to the related TCP_CB. If NULL, no match is found. 366 367 **/ 368 TCP_CB * 369 TcpLocateTcb ( 370 IN TCP_PORTNO LocalPort, 371 IN EFI_IP_ADDRESS *LocalIp, 372 IN TCP_PORTNO RemotePort, 373 IN EFI_IP_ADDRESS *RemoteIp, 374 IN UINT8 Version, 375 IN BOOLEAN Syn 376 ) 377 { 378 TCP_PEER Local; 379 TCP_PEER Remote; 380 LIST_ENTRY *Entry; 381 TCP_CB *Tcb; 382 383 Local.Port = LocalPort; 384 Remote.Port = RemotePort; 385 386 CopyMem (&Local.Ip, LocalIp, sizeof (EFI_IP_ADDRESS)); 387 CopyMem (&Remote.Ip, RemoteIp, sizeof (EFI_IP_ADDRESS)); 388 389 // 390 // First check for exact match. 391 // 392 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) { 393 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List); 394 395 if ((Version == Tcb->Sk->IpVersion) && 396 TCP_PEER_EQUAL (&Remote, &Tcb->RemoteEnd, Version) && 397 TCP_PEER_EQUAL (&Local, &Tcb->LocalEnd, Version) 398 ) { 399 400 RemoveEntryList (&Tcb->List); 401 InsertHeadList (&mTcpRunQue, &Tcb->List); 402 403 return Tcb; 404 } 405 } 406 407 // 408 // Only check the listen queue when the SYN flag is on. 409 // 410 if (Syn) { 411 return TcpLocateListenTcb (&Local, &Remote, Version); 412 } 413 414 return NULL; 415 } 416 417 /** 418 Insert a Tcb into the proper queue. 419 420 @param[in] Tcb Pointer to the TCP_CB to be inserted. 421 422 @retval 0 The Tcb was inserted successfully. 423 @retval -1 Error condition occurred. 424 425 **/ 426 INTN 427 TcpInsertTcb ( 428 IN TCP_CB *Tcb 429 ) 430 { 431 LIST_ENTRY *Entry; 432 LIST_ENTRY *Head; 433 TCP_CB *Node; 434 435 ASSERT ( 436 (Tcb != NULL) && 437 ( 438 (Tcb->State == TCP_LISTEN) || 439 (Tcb->State == TCP_SYN_SENT) || 440 (Tcb->State == TCP_SYN_RCVD) || 441 (Tcb->State == TCP_CLOSED) 442 ) 443 ); 444 445 if (Tcb->LocalEnd.Port == 0) { 446 return -1; 447 } 448 449 Head = &mTcpRunQue; 450 451 if (Tcb->State == TCP_LISTEN) { 452 Head = &mTcpListenQue; 453 } 454 455 // 456 // Check that the Tcb isn't already on the list. 457 // 458 NET_LIST_FOR_EACH (Entry, Head) { 459 Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List); 460 461 if (TCP_PEER_EQUAL (&Tcb->LocalEnd, &Node->LocalEnd, Tcb->Sk->IpVersion) && 462 TCP_PEER_EQUAL (&Tcb->RemoteEnd, &Node->RemoteEnd, Tcb->Sk->IpVersion) 463 ) { 464 465 return -1; 466 } 467 } 468 469 InsertHeadList (Head, &Tcb->List); 470 471 472 return 0; 473 } 474 475 /** 476 Clone a TCP_CB from Tcb. 477 478 @param[in] Tcb Pointer to the TCP_CB to be cloned. 479 480 @return Pointer to the new cloned TCP_CB; if NULL, error condition occurred. 481 482 **/ 483 TCP_CB * 484 TcpCloneTcb ( 485 IN TCP_CB *Tcb 486 ) 487 { 488 TCP_CB *Clone; 489 490 Clone = AllocateZeroPool (sizeof (TCP_CB)); 491 492 if (Clone == NULL) { 493 return NULL; 494 } 495 496 CopyMem (Clone, Tcb, sizeof (TCP_CB)); 497 498 // 499 // Increase the reference count of the shared IpInfo. 500 // 501 NET_GET_REF (Tcb->IpInfo); 502 503 InitializeListHead (&Clone->List); 504 InitializeListHead (&Clone->SndQue); 505 InitializeListHead (&Clone->RcvQue); 506 507 Clone->Sk = SockClone (Tcb->Sk); 508 if (Clone->Sk == NULL) { 509 DEBUG ((EFI_D_ERROR, "TcpCloneTcb: failed to clone a sock\n")); 510 FreePool (Clone); 511 return NULL; 512 } 513 514 ((TCP_PROTO_DATA *) (Clone->Sk->ProtoReserved))->TcpPcb = Clone; 515 516 return Clone; 517 } 518 519 /** 520 Compute an ISS to be used by a new connection. 521 522 @return The resulting ISS. 523 524 **/ 525 TCP_SEQNO 526 TcpGetIss ( 527 VOID 528 ) 529 { 530 mTcpGlobalIss += TCP_ISS_INCREMENT_1; 531 return mTcpGlobalIss; 532 } 533 534 /** 535 Get the local mss. 536 537 @param[in] Sock Pointer to the socket to get mss. 538 539 @return The mss size. 540 541 **/ 542 UINT16 543 TcpGetRcvMss ( 544 IN SOCKET *Sock 545 ) 546 { 547 EFI_IP4_MODE_DATA Ip4Mode; 548 EFI_IP6_MODE_DATA Ip6Mode; 549 EFI_IP4_PROTOCOL *Ip4; 550 EFI_IP6_PROTOCOL *Ip6; 551 TCP_PROTO_DATA *TcpProto; 552 553 ASSERT (Sock != NULL); 554 555 ZeroMem (&Ip4Mode, sizeof (EFI_IP4_MODE_DATA)); 556 ZeroMem (&Ip6Mode, sizeof (EFI_IP6_MODE_DATA)); 557 558 TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved; 559 560 if (Sock->IpVersion == IP_VERSION_4) { 561 Ip4 = TcpProto->TcpService->IpIo->Ip.Ip4; 562 ASSERT (Ip4 != NULL); 563 Ip4->GetModeData (Ip4, &Ip4Mode, NULL, NULL); 564 565 return (UINT16) (Ip4Mode.MaxPacketSize - sizeof (TCP_HEAD)); 566 } else { 567 Ip6 = TcpProto->TcpService->IpIo->Ip.Ip6; 568 ASSERT (Ip6 != NULL); 569 Ip6->GetModeData (Ip6, &Ip6Mode, NULL, NULL); 570 571 return (UINT16) (Ip6Mode.MaxPacketSize - sizeof (TCP_HEAD)); 572 } 573 } 574 575 /** 576 Set the Tcb's state. 577 578 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 579 @param[in] State The state to be set. 580 581 **/ 582 VOID 583 TcpSetState ( 584 IN TCP_CB *Tcb, 585 IN UINT8 State 586 ) 587 { 588 ASSERT (Tcb->State < (sizeof (mTcpStateName) / sizeof (CHAR16 *))); 589 ASSERT (State < (sizeof (mTcpStateName) / sizeof (CHAR16 *))); 590 591 DEBUG ( 592 (EFI_D_INFO, 593 "Tcb (%p) state %s --> %s\n", 594 Tcb, 595 mTcpStateName[Tcb->State], 596 mTcpStateName[State]) 597 ); 598 599 Tcb->State = State; 600 601 switch (State) { 602 case TCP_ESTABLISHED: 603 604 SockConnEstablished (Tcb->Sk); 605 606 if (Tcb->Parent != NULL) { 607 // 608 // A new connection is accepted by a listening socket. Install 609 // the device path. 610 // 611 TcpInstallDevicePath (Tcb->Sk); 612 } 613 614 break; 615 616 case TCP_CLOSED: 617 618 SockConnClosed (Tcb->Sk); 619 620 break; 621 default: 622 break; 623 } 624 } 625 626 /** 627 Compute the TCP segment's checksum. 628 629 @param[in] Nbuf Pointer to the buffer that contains the TCP segment. 630 @param[in] HeadSum The checksum value of the fixed part of pseudo header. 631 632 @return The checksum value. 633 634 **/ 635 UINT16 636 TcpChecksum ( 637 IN NET_BUF *Nbuf, 638 IN UINT16 HeadSum 639 ) 640 { 641 UINT16 Checksum; 642 643 Checksum = NetbufChecksum (Nbuf); 644 Checksum = NetAddChecksum (Checksum, HeadSum); 645 646 Checksum = NetAddChecksum ( 647 Checksum, 648 HTONS ((UINT16) Nbuf->TotalSize) 649 ); 650 651 return (UINT16) (~Checksum); 652 } 653 654 /** 655 Translate the information from the head of the received TCP 656 segment Nbuf contents and fill it into a TCP_SEG structure. 657 658 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 659 @param[in, out] Nbuf Pointer to the buffer contains the TCP segment. 660 661 @return Pointer to the TCP_SEG that contains the translated TCP head information. 662 663 **/ 664 TCP_SEG * 665 TcpFormatNetbuf ( 666 IN TCP_CB *Tcb, 667 IN OUT NET_BUF *Nbuf 668 ) 669 { 670 TCP_SEG *Seg; 671 TCP_HEAD *Head; 672 673 Seg = TCPSEG_NETBUF (Nbuf); 674 Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL); 675 ASSERT (Head != NULL); 676 677 Nbuf->Tcp = Head; 678 679 Seg->Seq = NTOHL (Head->Seq); 680 Seg->Ack = NTOHL (Head->Ack); 681 Seg->End = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2)); 682 683 Seg->Urg = NTOHS (Head->Urg); 684 Seg->Wnd = (NTOHS (Head->Wnd) << Tcb->SndWndScale); 685 Seg->Flag = Head->Flag; 686 687 // 688 // SYN and FIN flag occupy one sequence space each. 689 // 690 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) { 691 // 692 // RFC requires that the initial window not be scaled. 693 // 694 Seg->Wnd = NTOHS (Head->Wnd); 695 Seg->End++; 696 } 697 698 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) { 699 Seg->End++; 700 } 701 702 return Seg; 703 } 704 705 /** 706 Initialize an active connection. 707 708 @param[in, out] Tcb Pointer to the TCP_CB that wants to initiate a 709 connection. 710 711 **/ 712 VOID 713 TcpOnAppConnect ( 714 IN OUT TCP_CB *Tcb 715 ) 716 { 717 TcpInitTcbLocal (Tcb); 718 TcpSetState (Tcb, TCP_SYN_SENT); 719 720 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout); 721 TcpToSendData (Tcb, 1); 722 } 723 724 /** 725 Initiate the connection close procedure, called when 726 applications want to close the connection. 727 728 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. 729 730 **/ 731 VOID 732 TcpOnAppClose ( 733 IN OUT TCP_CB *Tcb 734 ) 735 { 736 ASSERT (Tcb != NULL); 737 738 if (!IsListEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk) != 0) { 739 740 DEBUG ( 741 (EFI_D_WARN, 742 "TcpOnAppClose: connection reset because data is lost for TCB %p\n", 743 Tcb) 744 ); 745 746 TcpResetConnection (Tcb); 747 TcpClose (Tcb); 748 return; 749 } 750 751 switch (Tcb->State) { 752 case TCP_CLOSED: 753 case TCP_LISTEN: 754 case TCP_SYN_SENT: 755 TcpSetState (Tcb, TCP_CLOSED); 756 break; 757 758 case TCP_SYN_RCVD: 759 case TCP_ESTABLISHED: 760 TcpSetState (Tcb, TCP_FIN_WAIT_1); 761 break; 762 763 case TCP_CLOSE_WAIT: 764 TcpSetState (Tcb, TCP_LAST_ACK); 765 break; 766 default: 767 break; 768 } 769 770 TcpToSendData (Tcb, 1); 771 } 772 773 /** 774 Check whether the application's newly delivered data can be sent out. 775 776 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. 777 778 @retval 0 The data has been sent out successfully. 779 @retval -1 The Tcb is not in a state that data is permitted to 780 be sent out. 781 782 **/ 783 INTN 784 TcpOnAppSend ( 785 IN OUT TCP_CB *Tcb 786 ) 787 { 788 789 switch (Tcb->State) { 790 case TCP_CLOSED: 791 return -1; 792 793 case TCP_LISTEN: 794 return -1; 795 796 case TCP_SYN_SENT: 797 case TCP_SYN_RCVD: 798 return 0; 799 800 case TCP_ESTABLISHED: 801 case TCP_CLOSE_WAIT: 802 TcpToSendData (Tcb, 0); 803 return 0; 804 805 case TCP_FIN_WAIT_1: 806 case TCP_FIN_WAIT_2: 807 case TCP_CLOSING: 808 case TCP_LAST_ACK: 809 case TCP_TIME_WAIT: 810 return -1; 811 812 default: 813 break; 814 } 815 816 return 0; 817 } 818 819 /** 820 Application has consumed some data. Check whether 821 to send a window update ack or a delayed ack. 822 823 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 824 825 **/ 826 VOID 827 TcpOnAppConsume ( 828 IN TCP_CB *Tcb 829 ) 830 { 831 UINT32 TcpOld; 832 833 switch (Tcb->State) { 834 case TCP_ESTABLISHED: 835 TcpOld = TcpRcvWinOld (Tcb); 836 if (TcpRcvWinNow (Tcb) > TcpOld) { 837 838 if (TcpOld < Tcb->RcvMss) { 839 840 DEBUG ( 841 (EFI_D_INFO, 842 "TcpOnAppConsume: send a window update for a window closed Tcb %p\n", 843 Tcb) 844 ); 845 846 TcpSendAck (Tcb); 847 } else if (Tcb->DelayedAck == 0) { 848 849 DEBUG ( 850 (EFI_D_INFO, 851 "TcpOnAppConsume: scheduled a delayed ACK to update window for Tcb %p\n", 852 Tcb) 853 ); 854 855 Tcb->DelayedAck = 1; 856 } 857 } 858 859 break; 860 861 default: 862 break; 863 } 864 } 865 866 /** 867 Abort the connection by sending a reset segment. Called 868 when the application wants to abort the connection. 869 870 @param[in] Tcb Pointer to the TCP_CB of the TCP instance. 871 872 **/ 873 VOID 874 TcpOnAppAbort ( 875 IN TCP_CB *Tcb 876 ) 877 { 878 DEBUG ( 879 (EFI_D_WARN, 880 "TcpOnAppAbort: connection reset issued by application for TCB %p\n", 881 Tcb) 882 ); 883 884 switch (Tcb->State) { 885 case TCP_SYN_RCVD: 886 case TCP_ESTABLISHED: 887 case TCP_FIN_WAIT_1: 888 case TCP_FIN_WAIT_2: 889 case TCP_CLOSE_WAIT: 890 TcpResetConnection (Tcb); 891 break; 892 default: 893 break; 894 } 895 896 TcpSetState (Tcb, TCP_CLOSED); 897 } 898 899 /** 900 Reset the connection related with Tcb. 901 902 @param[in] Tcb Pointer to the TCP_CB of the connection to be reset. 903 904 **/ 905 VOID 906 TcpResetConnection ( 907 IN TCP_CB *Tcb 908 ) 909 { 910 NET_BUF *Nbuf; 911 TCP_HEAD *Nhead; 912 913 Nbuf = NetbufAlloc (TCP_MAX_HEAD); 914 915 if (Nbuf == NULL) { 916 return ; 917 } 918 919 Nhead = (TCP_HEAD *) NetbufAllocSpace ( 920 Nbuf, 921 sizeof (TCP_HEAD), 922 NET_BUF_TAIL 923 ); 924 925 ASSERT (Nhead != NULL); 926 927 Nbuf->Tcp = Nhead; 928 929 Nhead->Flag = TCP_FLG_RST; 930 Nhead->Seq = HTONL (Tcb->SndNxt); 931 Nhead->Ack = HTONL (Tcb->RcvNxt); 932 Nhead->SrcPort = Tcb->LocalEnd.Port; 933 Nhead->DstPort = Tcb->RemoteEnd.Port; 934 Nhead->HeadLen = (UINT8) (sizeof (TCP_HEAD) >> 2); 935 Nhead->Res = 0; 936 Nhead->Wnd = HTONS (0xFFFF); 937 Nhead->Checksum = 0; 938 Nhead->Urg = 0; 939 Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum); 940 941 TcpSendIpPacket (Tcb, Nbuf, &Tcb->LocalEnd.Ip, &Tcb->RemoteEnd.Ip, Tcb->Sk->IpVersion); 942 943 NetbufFree (Nbuf); 944 } 945 946 /** 947 Install the device path protocol on the TCP instance. 948 949 @param[in] Sock Pointer to the socket representing the TCP instance. 950 951 @retval EFI_SUCCESS The device path protocol was installed. 952 @retval other Failed to install the device path protocol. 953 954 **/ 955 EFI_STATUS 956 TcpInstallDevicePath ( 957 IN SOCKET *Sock 958 ) 959 { 960 TCP_PROTO_DATA *TcpProto; 961 TCP_SERVICE_DATA *TcpService; 962 TCP_CB *Tcb; 963 IPv4_DEVICE_PATH Ip4DPathNode; 964 IPv6_DEVICE_PATH Ip6DPathNode; 965 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 966 EFI_STATUS Status; 967 TCP_PORTNO LocalPort; 968 TCP_PORTNO RemotePort; 969 970 TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved; 971 TcpService = TcpProto->TcpService; 972 Tcb = TcpProto->TcpPcb; 973 974 LocalPort = NTOHS (Tcb->LocalEnd.Port); 975 RemotePort = NTOHS (Tcb->RemoteEnd.Port); 976 if (Sock->IpVersion == IP_VERSION_4) { 977 NetLibCreateIPv4DPathNode ( 978 &Ip4DPathNode, 979 TcpService->ControllerHandle, 980 Tcb->LocalEnd.Ip.Addr[0], 981 LocalPort, 982 Tcb->RemoteEnd.Ip.Addr[0], 983 RemotePort, 984 EFI_IP_PROTO_TCP, 985 Tcb->UseDefaultAddr 986 ); 987 988 IP4_COPY_ADDRESS (&Ip4DPathNode.SubnetMask, &Tcb->SubnetMask); 989 990 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode; 991 } else { 992 NetLibCreateIPv6DPathNode ( 993 &Ip6DPathNode, 994 TcpService->ControllerHandle, 995 &Tcb->LocalEnd.Ip.v6, 996 LocalPort, 997 &Tcb->RemoteEnd.Ip.v6, 998 RemotePort, 999 EFI_IP_PROTO_TCP 1000 ); 1001 1002 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip6DPathNode; 1003 } 1004 1005 Sock->DevicePath = AppendDevicePathNode (Sock->ParentDevicePath, DevicePath); 1006 if (Sock->DevicePath == NULL) { 1007 return EFI_OUT_OF_RESOURCES; 1008 } 1009 1010 Status = gBS->InstallProtocolInterface ( 1011 &Sock->SockHandle, 1012 &gEfiDevicePathProtocolGuid, 1013 EFI_NATIVE_INTERFACE, 1014 Sock->DevicePath 1015 ); 1016 if (EFI_ERROR (Status)) { 1017 FreePool (Sock->DevicePath); 1018 Sock->DevicePath = NULL; 1019 } 1020 1021 return Status; 1022 } 1023 1024