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 - 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