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 - 2016, 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 if (!EFI_ERROR (Ip6->GetModeData (Ip6, &Ip6Mode, NULL, NULL))) { 570 if (Ip6Mode.AddressList != NULL) { 571 FreePool (Ip6Mode.AddressList); 572 } 573 574 if (Ip6Mode.GroupTable != NULL) { 575 FreePool (Ip6Mode.GroupTable); 576 } 577 578 if (Ip6Mode.RouteTable != NULL) { 579 FreePool (Ip6Mode.RouteTable); 580 } 581 582 if (Ip6Mode.NeighborCache != NULL) { 583 FreePool (Ip6Mode.NeighborCache); 584 } 585 586 if (Ip6Mode.PrefixTable != NULL) { 587 FreePool (Ip6Mode.PrefixTable); 588 } 589 590 if (Ip6Mode.IcmpTypeList != NULL) { 591 FreePool (Ip6Mode.IcmpTypeList); 592 } 593 } 594 595 return (UINT16) (Ip6Mode.MaxPacketSize - sizeof (TCP_HEAD)); 596 } 597 } 598 599 /** 600 Set the Tcb's state. 601 602 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 603 @param[in] State The state to be set. 604 605 **/ 606 VOID 607 TcpSetState ( 608 IN TCP_CB *Tcb, 609 IN UINT8 State 610 ) 611 { 612 ASSERT (Tcb->State < (sizeof (mTcpStateName) / sizeof (CHAR16 *))); 613 ASSERT (State < (sizeof (mTcpStateName) / sizeof (CHAR16 *))); 614 615 DEBUG ( 616 (EFI_D_NET, 617 "Tcb (%p) state %s --> %s\n", 618 Tcb, 619 mTcpStateName[Tcb->State], 620 mTcpStateName[State]) 621 ); 622 623 Tcb->State = State; 624 625 switch (State) { 626 case TCP_ESTABLISHED: 627 628 SockConnEstablished (Tcb->Sk); 629 630 if (Tcb->Parent != NULL) { 631 // 632 // A new connection is accepted by a listening socket. Install 633 // the device path. 634 // 635 TcpInstallDevicePath (Tcb->Sk); 636 } 637 638 break; 639 640 case TCP_CLOSED: 641 642 SockConnClosed (Tcb->Sk); 643 644 break; 645 default: 646 break; 647 } 648 } 649 650 /** 651 Compute the TCP segment's checksum. 652 653 @param[in] Nbuf Pointer to the buffer that contains the TCP segment. 654 @param[in] HeadSum The checksum value of the fixed part of pseudo header. 655 656 @return The checksum value. 657 658 **/ 659 UINT16 660 TcpChecksum ( 661 IN NET_BUF *Nbuf, 662 IN UINT16 HeadSum 663 ) 664 { 665 UINT16 Checksum; 666 667 Checksum = NetbufChecksum (Nbuf); 668 Checksum = NetAddChecksum (Checksum, HeadSum); 669 670 Checksum = NetAddChecksum ( 671 Checksum, 672 HTONS ((UINT16) Nbuf->TotalSize) 673 ); 674 675 return (UINT16) (~Checksum); 676 } 677 678 /** 679 Translate the information from the head of the received TCP 680 segment Nbuf contents and fill it into a TCP_SEG structure. 681 682 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 683 @param[in, out] Nbuf Pointer to the buffer contains the TCP segment. 684 685 @return Pointer to the TCP_SEG that contains the translated TCP head information. 686 687 **/ 688 TCP_SEG * 689 TcpFormatNetbuf ( 690 IN TCP_CB *Tcb, 691 IN OUT NET_BUF *Nbuf 692 ) 693 { 694 TCP_SEG *Seg; 695 TCP_HEAD *Head; 696 697 Seg = TCPSEG_NETBUF (Nbuf); 698 Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL); 699 ASSERT (Head != NULL); 700 701 Nbuf->Tcp = Head; 702 703 Seg->Seq = NTOHL (Head->Seq); 704 Seg->Ack = NTOHL (Head->Ack); 705 Seg->End = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2)); 706 707 Seg->Urg = NTOHS (Head->Urg); 708 Seg->Wnd = (NTOHS (Head->Wnd) << Tcb->SndWndScale); 709 Seg->Flag = Head->Flag; 710 711 // 712 // SYN and FIN flag occupy one sequence space each. 713 // 714 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) { 715 // 716 // RFC requires that the initial window not be scaled. 717 // 718 Seg->Wnd = NTOHS (Head->Wnd); 719 Seg->End++; 720 } 721 722 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) { 723 Seg->End++; 724 } 725 726 return Seg; 727 } 728 729 /** 730 Initialize an active connection. 731 732 @param[in, out] Tcb Pointer to the TCP_CB that wants to initiate a 733 connection. 734 735 **/ 736 VOID 737 TcpOnAppConnect ( 738 IN OUT TCP_CB *Tcb 739 ) 740 { 741 TcpInitTcbLocal (Tcb); 742 TcpSetState (Tcb, TCP_SYN_SENT); 743 744 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout); 745 TcpToSendData (Tcb, 1); 746 } 747 748 /** 749 Initiate the connection close procedure, called when 750 applications want to close the connection. 751 752 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. 753 754 **/ 755 VOID 756 TcpOnAppClose ( 757 IN OUT TCP_CB *Tcb 758 ) 759 { 760 ASSERT (Tcb != NULL); 761 762 if (!IsListEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk) != 0) { 763 764 DEBUG ( 765 (EFI_D_WARN, 766 "TcpOnAppClose: connection reset because data is lost for TCB %p\n", 767 Tcb) 768 ); 769 770 TcpResetConnection (Tcb); 771 TcpClose (Tcb); 772 return; 773 } 774 775 switch (Tcb->State) { 776 case TCP_CLOSED: 777 case TCP_LISTEN: 778 case TCP_SYN_SENT: 779 TcpSetState (Tcb, TCP_CLOSED); 780 break; 781 782 case TCP_SYN_RCVD: 783 case TCP_ESTABLISHED: 784 TcpSetState (Tcb, TCP_FIN_WAIT_1); 785 break; 786 787 case TCP_CLOSE_WAIT: 788 TcpSetState (Tcb, TCP_LAST_ACK); 789 break; 790 default: 791 break; 792 } 793 794 TcpToSendData (Tcb, 1); 795 } 796 797 /** 798 Check whether the application's newly delivered data can be sent out. 799 800 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. 801 802 @retval 0 The data has been sent out successfully. 803 @retval -1 The Tcb is not in a state that data is permitted to 804 be sent out. 805 806 **/ 807 INTN 808 TcpOnAppSend ( 809 IN OUT TCP_CB *Tcb 810 ) 811 { 812 813 switch (Tcb->State) { 814 case TCP_CLOSED: 815 return -1; 816 817 case TCP_LISTEN: 818 return -1; 819 820 case TCP_SYN_SENT: 821 case TCP_SYN_RCVD: 822 return 0; 823 824 case TCP_ESTABLISHED: 825 case TCP_CLOSE_WAIT: 826 TcpToSendData (Tcb, 0); 827 return 0; 828 829 case TCP_FIN_WAIT_1: 830 case TCP_FIN_WAIT_2: 831 case TCP_CLOSING: 832 case TCP_LAST_ACK: 833 case TCP_TIME_WAIT: 834 return -1; 835 836 default: 837 break; 838 } 839 840 return 0; 841 } 842 843 /** 844 Application has consumed some data. Check whether 845 to send a window update ack or a delayed ack. 846 847 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. 848 849 **/ 850 VOID 851 TcpOnAppConsume ( 852 IN TCP_CB *Tcb 853 ) 854 { 855 UINT32 TcpOld; 856 857 switch (Tcb->State) { 858 case TCP_ESTABLISHED: 859 TcpOld = TcpRcvWinOld (Tcb); 860 if (TcpRcvWinNow (Tcb) > TcpOld) { 861 862 if (TcpOld < Tcb->RcvMss) { 863 864 DEBUG ( 865 (EFI_D_NET, 866 "TcpOnAppConsume: send a window update for a window closed Tcb %p\n", 867 Tcb) 868 ); 869 870 TcpSendAck (Tcb); 871 } else if (Tcb->DelayedAck == 0) { 872 873 DEBUG ( 874 (EFI_D_NET, 875 "TcpOnAppConsume: scheduled a delayed ACK to update window for Tcb %p\n", 876 Tcb) 877 ); 878 879 Tcb->DelayedAck = 1; 880 } 881 } 882 883 break; 884 885 default: 886 break; 887 } 888 } 889 890 /** 891 Abort the connection by sending a reset segment. Called 892 when the application wants to abort the connection. 893 894 @param[in] Tcb Pointer to the TCP_CB of the TCP instance. 895 896 **/ 897 VOID 898 TcpOnAppAbort ( 899 IN TCP_CB *Tcb 900 ) 901 { 902 DEBUG ( 903 (EFI_D_WARN, 904 "TcpOnAppAbort: connection reset issued by application for TCB %p\n", 905 Tcb) 906 ); 907 908 switch (Tcb->State) { 909 case TCP_SYN_RCVD: 910 case TCP_ESTABLISHED: 911 case TCP_FIN_WAIT_1: 912 case TCP_FIN_WAIT_2: 913 case TCP_CLOSE_WAIT: 914 TcpResetConnection (Tcb); 915 break; 916 default: 917 break; 918 } 919 920 TcpSetState (Tcb, TCP_CLOSED); 921 } 922 923 /** 924 Reset the connection related with Tcb. 925 926 @param[in] Tcb Pointer to the TCP_CB of the connection to be reset. 927 928 **/ 929 VOID 930 TcpResetConnection ( 931 IN TCP_CB *Tcb 932 ) 933 { 934 NET_BUF *Nbuf; 935 TCP_HEAD *Nhead; 936 937 Nbuf = NetbufAlloc (TCP_MAX_HEAD); 938 939 if (Nbuf == NULL) { 940 return ; 941 } 942 943 Nhead = (TCP_HEAD *) NetbufAllocSpace ( 944 Nbuf, 945 sizeof (TCP_HEAD), 946 NET_BUF_TAIL 947 ); 948 949 ASSERT (Nhead != NULL); 950 951 Nbuf->Tcp = Nhead; 952 953 Nhead->Flag = TCP_FLG_RST; 954 Nhead->Seq = HTONL (Tcb->SndNxt); 955 Nhead->Ack = HTONL (Tcb->RcvNxt); 956 Nhead->SrcPort = Tcb->LocalEnd.Port; 957 Nhead->DstPort = Tcb->RemoteEnd.Port; 958 Nhead->HeadLen = (UINT8) (sizeof (TCP_HEAD) >> 2); 959 Nhead->Res = 0; 960 Nhead->Wnd = HTONS (0xFFFF); 961 Nhead->Checksum = 0; 962 Nhead->Urg = 0; 963 Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum); 964 965 TcpSendIpPacket (Tcb, Nbuf, &Tcb->LocalEnd.Ip, &Tcb->RemoteEnd.Ip, Tcb->Sk->IpVersion); 966 967 NetbufFree (Nbuf); 968 } 969 970 /** 971 Install the device path protocol on the TCP instance. 972 973 @param[in] Sock Pointer to the socket representing the TCP instance. 974 975 @retval EFI_SUCCESS The device path protocol was installed. 976 @retval other Failed to install the device path protocol. 977 978 **/ 979 EFI_STATUS 980 TcpInstallDevicePath ( 981 IN SOCKET *Sock 982 ) 983 { 984 TCP_PROTO_DATA *TcpProto; 985 TCP_SERVICE_DATA *TcpService; 986 TCP_CB *Tcb; 987 IPv4_DEVICE_PATH Ip4DPathNode; 988 IPv6_DEVICE_PATH Ip6DPathNode; 989 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 990 EFI_STATUS Status; 991 TCP_PORTNO LocalPort; 992 TCP_PORTNO RemotePort; 993 994 TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved; 995 TcpService = TcpProto->TcpService; 996 Tcb = TcpProto->TcpPcb; 997 998 LocalPort = NTOHS (Tcb->LocalEnd.Port); 999 RemotePort = NTOHS (Tcb->RemoteEnd.Port); 1000 if (Sock->IpVersion == IP_VERSION_4) { 1001 NetLibCreateIPv4DPathNode ( 1002 &Ip4DPathNode, 1003 TcpService->ControllerHandle, 1004 Tcb->LocalEnd.Ip.Addr[0], 1005 LocalPort, 1006 Tcb->RemoteEnd.Ip.Addr[0], 1007 RemotePort, 1008 EFI_IP_PROTO_TCP, 1009 Tcb->UseDefaultAddr 1010 ); 1011 1012 IP4_COPY_ADDRESS (&Ip4DPathNode.SubnetMask, &Tcb->SubnetMask); 1013 1014 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode; 1015 } else { 1016 NetLibCreateIPv6DPathNode ( 1017 &Ip6DPathNode, 1018 TcpService->ControllerHandle, 1019 &Tcb->LocalEnd.Ip.v6, 1020 LocalPort, 1021 &Tcb->RemoteEnd.Ip.v6, 1022 RemotePort, 1023 EFI_IP_PROTO_TCP 1024 ); 1025 1026 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip6DPathNode; 1027 } 1028 1029 Sock->DevicePath = AppendDevicePathNode (Sock->ParentDevicePath, DevicePath); 1030 if (Sock->DevicePath == NULL) { 1031 return EFI_OUT_OF_RESOURCES; 1032 } 1033 1034 Status = gBS->InstallProtocolInterface ( 1035 &Sock->SockHandle, 1036 &gEfiDevicePathProtocolGuid, 1037 EFI_NATIVE_INTERFACE, 1038 Sock->DevicePath 1039 ); 1040 if (EFI_ERROR (Status)) { 1041 FreePool (Sock->DevicePath); 1042 Sock->DevicePath = NULL; 1043 } 1044 1045 return Status; 1046 } 1047 1048