Home | History | Annotate | Download | only in TcpDxe
      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