Home | History | Annotate | Download | only in TcpDxe
      1 /** @file
      2   The implementation of a dispatch routine for processing TCP requests.
      3 
      4   (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2009 - 2014, 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 /**
     20   Add or remove a route entry in the IP route table associated with this TCP instance.
     21 
     22   @param[in]  Tcb               Pointer to the TCP_CB of this TCP instance.
     23   @param[in]  RouteInfo         Pointer to the route information to be processed.
     24 
     25   @retval EFI_SUCCESS           The operation completed successfully.
     26   @retval EFI_NOT_STARTED       The driver instance has not been started.
     27   @retval EFI_NO_MAPPING        When using the default address, configuration(DHCP,
     28                                 BOOTP, RARP, etc.) is not finished yet.
     29   @retval EFI_OUT_OF_RESOURCES  Could not add the entry to the routing table.
     30   @retval EFI_NOT_FOUND         This route is not in the routing table
     31                                 (when RouteInfo->DeleteRoute is TRUE).
     32   @retval EFI_ACCESS_DENIED     The route is already defined in the routing table
     33                                 (when RouteInfo->DeleteRoute is FALSE).
     34 **/
     35 EFI_STATUS
     36 Tcp4Route (
     37   IN TCP_CB           *Tcb,
     38   IN TCP4_ROUTE_INFO  *RouteInfo
     39   )
     40 {
     41   IP_IO_IP_PROTOCOL   Ip;
     42 
     43   Ip = Tcb->IpInfo->Ip;
     44 
     45   ASSERT (Ip.Ip4!= NULL);
     46 
     47   return Ip.Ip4->Routes (
     48                    Ip.Ip4,
     49                    RouteInfo->DeleteRoute,
     50                    RouteInfo->SubnetAddress,
     51                    RouteInfo->SubnetMask,
     52                    RouteInfo->GatewayAddress
     53                    );
     54 
     55 }
     56 
     57 /**
     58   Get the operational settings of this TCPv4 instance.
     59 
     60   @param[in]       Tcb           Pointer to the TCP_CB of this TCP instance.
     61   @param[in, out]  Mode          Pointer to the buffer to store the operational
     62                                  settings.
     63 
     64   @retval EFI_SUCCESS            The mode data was read.
     65   @retval EFI_NOT_STARTED        No configuration data is available because this
     66                                  instance hasn't been started.
     67 
     68 **/
     69 EFI_STATUS
     70 Tcp4GetMode (
     71   IN     TCP_CB         *Tcb,
     72   IN OUT TCP4_MODE_DATA *Mode
     73   )
     74 {
     75   SOCKET                *Sock;
     76   EFI_TCP4_CONFIG_DATA  *ConfigData;
     77   EFI_TCP4_ACCESS_POINT *AccessPoint;
     78   EFI_TCP4_OPTION       *Option;
     79   EFI_IP4_PROTOCOL      *Ip;
     80 
     81   Sock = Tcb->Sk;
     82 
     83   if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp4ConfigData != NULL)) {
     84     return EFI_NOT_STARTED;
     85   }
     86 
     87   if (Mode->Tcp4State != NULL) {
     88     *(Mode->Tcp4State) = (EFI_TCP4_CONNECTION_STATE) Tcb->State;
     89   }
     90 
     91   if (Mode->Tcp4ConfigData != NULL) {
     92 
     93     ConfigData                       = Mode->Tcp4ConfigData;
     94     AccessPoint                      = &(ConfigData->AccessPoint);
     95     Option                           = ConfigData->ControlOption;
     96 
     97     ConfigData->TypeOfService        = Tcb->Tos;
     98     ConfigData->TimeToLive           = Tcb->Ttl;
     99 
    100     AccessPoint->UseDefaultAddress   = Tcb->UseDefaultAddr;
    101 
    102     IP4_COPY_ADDRESS (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip);
    103 
    104     IP4_COPY_ADDRESS (&AccessPoint->SubnetMask, &Tcb->SubnetMask);
    105     AccessPoint->StationPort         = NTOHS (Tcb->LocalEnd.Port);
    106 
    107     IP4_COPY_ADDRESS (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip);
    108 
    109     AccessPoint->RemotePort          = NTOHS (Tcb->RemoteEnd.Port);
    110     AccessPoint->ActiveFlag          = (BOOLEAN) (Tcb->State != TCP_LISTEN);
    111 
    112     if (Option != NULL) {
    113       Option->ReceiveBufferSize      = GET_RCV_BUFFSIZE (Tcb->Sk);
    114       Option->SendBufferSize         = GET_SND_BUFFSIZE (Tcb->Sk);
    115       Option->MaxSynBackLog          = GET_BACKLOG (Tcb->Sk);
    116 
    117       Option->ConnectionTimeout      = Tcb->ConnectTimeout / TCP_TICK_HZ;
    118       Option->DataRetries            = Tcb->MaxRexmit;
    119       Option->FinTimeout             = Tcb->FinWait2Timeout / TCP_TICK_HZ;
    120       Option->TimeWaitTimeout        = Tcb->TimeWaitTimeout / TCP_TICK_HZ;
    121       Option->KeepAliveProbes        = Tcb->MaxKeepAlive;
    122       Option->KeepAliveTime          = Tcb->KeepAliveIdle / TCP_TICK_HZ;
    123       Option->KeepAliveInterval      = Tcb->KeepAlivePeriod / TCP_TICK_HZ;
    124 
    125       Option->EnableNagle            = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE));
    126       Option->EnableTimeStamp        = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS));
    127       Option->EnableWindowScaling    = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS));
    128 
    129       Option->EnableSelectiveAck     = FALSE;
    130       Option->EnablePathMtuDiscovery = FALSE;
    131     }
    132   }
    133 
    134   Ip = Tcb->IpInfo->Ip.Ip4;
    135   ASSERT (Ip != NULL);
    136 
    137   return Ip->GetModeData (Ip, Mode->Ip4ModeData, Mode->MnpConfigData, Mode->SnpModeData);
    138 }
    139 
    140 /**
    141   Get the operational settings of this TCPv6 instance.
    142 
    143   @param[in]       Tcb           Pointer to the TCP_CB of this TCP instance.
    144   @param[in, out]  Mode          Pointer to the buffer to store the operational
    145                                  settings.
    146 
    147   @retval EFI_SUCCESS            The mode data was read.
    148   @retval EFI_NOT_STARTED        No configuration data is available because this
    149                                  instance hasn't been started.
    150 
    151 **/
    152 EFI_STATUS
    153 Tcp6GetMode (
    154   IN     TCP_CB         *Tcb,
    155   IN OUT TCP6_MODE_DATA *Mode
    156   )
    157 {
    158   SOCKET                *Sock;
    159   EFI_TCP6_CONFIG_DATA  *ConfigData;
    160   EFI_TCP6_ACCESS_POINT *AccessPoint;
    161   EFI_TCP6_OPTION       *Option;
    162   EFI_IP6_PROTOCOL      *Ip;
    163 
    164   Sock = Tcb->Sk;
    165 
    166   if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp6ConfigData != NULL)) {
    167     return EFI_NOT_STARTED;
    168   }
    169 
    170   if (Mode->Tcp6State != NULL) {
    171     *(Mode->Tcp6State) = (EFI_TCP6_CONNECTION_STATE) (Tcb->State);
    172   }
    173 
    174   if (Mode->Tcp6ConfigData != NULL) {
    175 
    176     ConfigData                       = Mode->Tcp6ConfigData;
    177     AccessPoint                      = &(ConfigData->AccessPoint);
    178     Option                           = ConfigData->ControlOption;
    179 
    180     ConfigData->TrafficClass         = Tcb->Tos;
    181     ConfigData->HopLimit             = Tcb->Ttl;
    182 
    183     AccessPoint->StationPort         = NTOHS (Tcb->LocalEnd.Port);
    184     AccessPoint->RemotePort          = NTOHS (Tcb->RemoteEnd.Port);
    185     AccessPoint->ActiveFlag          = (BOOLEAN) (Tcb->State != TCP_LISTEN);
    186 
    187     IP6_COPY_ADDRESS (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip);
    188     IP6_COPY_ADDRESS (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip);
    189 
    190     if (Option != NULL) {
    191       Option->ReceiveBufferSize      = GET_RCV_BUFFSIZE (Tcb->Sk);
    192       Option->SendBufferSize         = GET_SND_BUFFSIZE (Tcb->Sk);
    193       Option->MaxSynBackLog          = GET_BACKLOG (Tcb->Sk);
    194 
    195       Option->ConnectionTimeout      = Tcb->ConnectTimeout / TCP_TICK_HZ;
    196       Option->DataRetries            = Tcb->MaxRexmit;
    197       Option->FinTimeout             = Tcb->FinWait2Timeout / TCP_TICK_HZ;
    198       Option->TimeWaitTimeout        = Tcb->TimeWaitTimeout / TCP_TICK_HZ;
    199       Option->KeepAliveProbes        = Tcb->MaxKeepAlive;
    200       Option->KeepAliveTime          = Tcb->KeepAliveIdle / TCP_TICK_HZ;
    201       Option->KeepAliveInterval      = Tcb->KeepAlivePeriod / TCP_TICK_HZ;
    202 
    203       Option->EnableNagle            = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE));
    204       Option->EnableTimeStamp        = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS));
    205       Option->EnableWindowScaling    = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS));
    206 
    207       Option->EnableSelectiveAck     = FALSE;
    208       Option->EnablePathMtuDiscovery = FALSE;
    209     }
    210   }
    211 
    212   Ip = Tcb->IpInfo->Ip.Ip6;
    213   ASSERT (Ip != NULL);
    214 
    215   return Ip->GetModeData (Ip, Mode->Ip6ModeData, Mode->MnpConfigData, Mode->SnpModeData);
    216 }
    217 
    218 /**
    219   If TcpAp->StationPort isn't zero, check whether the access point
    220   is registered, else generate a random station port for this
    221   access point.
    222 
    223   @param[in]  TcpAp              Pointer to the access point.
    224   @param[in]  IpVersion          IP_VERSION_4 or IP_VERSION_6
    225 
    226   @retval EFI_SUCCESS            The check passed or the port is assigned.
    227   @retval EFI_INVALID_PARAMETER  The non-zero station port is already used.
    228   @retval EFI_OUT_OF_RESOURCES   No port can be allocated.
    229 
    230 **/
    231 EFI_STATUS
    232 TcpBind (
    233   IN TCP_ACCESS_POINT  *TcpAp,
    234   IN UINT8             IpVersion
    235   )
    236 {
    237   BOOLEAN         Cycle;
    238   EFI_IP_ADDRESS  Local;
    239   UINT16          *Port;
    240   UINT16          *RandomPort;
    241 
    242   if (IpVersion == IP_VERSION_4) {
    243     IP4_COPY_ADDRESS (&Local, &TcpAp->Tcp4Ap.StationAddress);
    244     Port       = &TcpAp->Tcp4Ap.StationPort;
    245     RandomPort = &mTcp4RandomPort;
    246   } else {
    247     IP6_COPY_ADDRESS (&Local, &TcpAp->Tcp6Ap.StationAddress);
    248     Port       = &TcpAp->Tcp6Ap.StationPort;
    249     RandomPort = &mTcp6RandomPort;
    250   }
    251 
    252   if (0 != *Port) {
    253     //
    254     // Check if a same endpoing is bound.
    255     //
    256     if (TcpFindTcbByPeer (&Local, *Port, IpVersion)) {
    257 
    258       return EFI_INVALID_PARAMETER;
    259     }
    260   } else {
    261     //
    262     // generate a random port
    263     //
    264     Cycle = FALSE;
    265 
    266     if (TCP_PORT_USER_RESERVED == *RandomPort) {
    267       *RandomPort = TCP_PORT_KNOWN;
    268     }
    269 
    270     (*RandomPort)++;
    271 
    272     while (TcpFindTcbByPeer (&Local, *RandomPort, IpVersion)) {
    273       (*RandomPort)++;
    274 
    275       if (*RandomPort <= TCP_PORT_KNOWN) {
    276         if (Cycle) {
    277           DEBUG (
    278             (EFI_D_ERROR,
    279             "TcpBind: no port can be allocated for this pcb\n")
    280             );
    281           return EFI_OUT_OF_RESOURCES;
    282         }
    283 
    284         *RandomPort = TCP_PORT_KNOWN + 1;
    285 
    286         Cycle       = TRUE;
    287       }
    288     }
    289 
    290     *Port = *RandomPort;
    291   }
    292 
    293   return EFI_SUCCESS;
    294 }
    295 
    296 /**
    297   Flush the Tcb add its associated protocols.
    298 
    299   @param[in, out]  Tcb      Pointer to the TCP_CB to be flushed.
    300 
    301 **/
    302 VOID
    303 TcpFlushPcb (
    304   IN OUT TCP_CB *Tcb
    305   )
    306 {
    307   SOCKET                    *Sock;
    308 
    309   IpIoConfigIp (Tcb->IpInfo, NULL);
    310 
    311   Sock     = Tcb->Sk;
    312 
    313   if (SOCK_IS_CONFIGURED (Sock)) {
    314     RemoveEntryList (&Tcb->List);
    315 
    316     if (Sock->DevicePath != NULL) {
    317       //
    318       // Uninstall the device path protocl.
    319       //
    320       gBS->UninstallProtocolInterface (
    321              Sock->SockHandle,
    322              &gEfiDevicePathProtocolGuid,
    323              Sock->DevicePath
    324              );
    325 
    326       FreePool (Sock->DevicePath);
    327       Sock->DevicePath = NULL;
    328     }
    329   }
    330 
    331   NetbufFreeList (&Tcb->SndQue);
    332   NetbufFreeList (&Tcb->RcvQue);
    333   Tcb->State = TCP_CLOSED;
    334   Tcb->RemoteIpZero = FALSE;
    335 }
    336 
    337 /**
    338   Attach a Pcb to the socket.
    339 
    340   @param[in]  Sk                 Pointer to the socket of this TCP instance.
    341 
    342   @retval EFI_SUCCESS            The operation completed successfully.
    343   @retval EFI_OUT_OF_RESOURCES   Failed due to resource limits.
    344 
    345 **/
    346 EFI_STATUS
    347 TcpAttachPcb (
    348   IN SOCKET  *Sk
    349   )
    350 {
    351   TCP_CB          *Tcb;
    352   TCP_PROTO_DATA  *ProtoData;
    353   IP_IO           *IpIo;
    354   EFI_STATUS      Status;
    355   VOID            *Ip;
    356   EFI_GUID        *IpProtocolGuid;
    357 
    358   if (Sk->IpVersion == IP_VERSION_4) {
    359     IpProtocolGuid = &gEfiIp4ProtocolGuid;
    360   } else {
    361     IpProtocolGuid = &gEfiIp6ProtocolGuid;
    362   }
    363 
    364   Tcb = AllocateZeroPool (sizeof (TCP_CB));
    365 
    366   if (Tcb == NULL) {
    367 
    368     DEBUG ((EFI_D_ERROR, "TcpConfigurePcb: failed to allocate a TCB\n"));
    369 
    370     return EFI_OUT_OF_RESOURCES;
    371   }
    372 
    373   ProtoData = (TCP_PROTO_DATA *) Sk->ProtoReserved;
    374   IpIo      = ProtoData->TcpService->IpIo;
    375 
    376   //
    377   // Create an IpInfo for this Tcb.
    378   //
    379   Tcb->IpInfo = IpIoAddIp (IpIo);
    380   if (Tcb->IpInfo == NULL) {
    381 
    382     FreePool (Tcb);
    383     return EFI_OUT_OF_RESOURCES;
    384   }
    385 
    386   //
    387   // Open the new created IP instance BY_CHILD.
    388   //
    389   Status = gBS->OpenProtocol (
    390                   Tcb->IpInfo->ChildHandle,
    391                   IpProtocolGuid,
    392                   &Ip,
    393                   IpIo->Image,
    394                   Sk->SockHandle,
    395                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    396                   );
    397   if (EFI_ERROR (Status)) {
    398     IpIoRemoveIp (IpIo, Tcb->IpInfo);
    399     return Status;
    400   }
    401 
    402   InitializeListHead (&Tcb->List);
    403   InitializeListHead (&Tcb->SndQue);
    404   InitializeListHead (&Tcb->RcvQue);
    405 
    406   Tcb->State        = TCP_CLOSED;
    407   Tcb->Sk           = Sk;
    408   ProtoData->TcpPcb = Tcb;
    409 
    410   return EFI_SUCCESS;
    411 }
    412 
    413 /**
    414   Detach the Pcb of the socket.
    415 
    416   @param[in, out]  Sk           Pointer to the socket of this TCP instance.
    417 
    418 **/
    419 VOID
    420 TcpDetachPcb (
    421   IN OUT SOCKET    *Sk
    422   )
    423 {
    424   TCP_PROTO_DATA   *ProtoData;
    425   TCP_CB           *Tcb;
    426   EFI_GUID         *IpProtocolGuid;
    427 
    428   if (Sk->IpVersion == IP_VERSION_4) {
    429     IpProtocolGuid = &gEfiIp4ProtocolGuid;
    430   } else {
    431     IpProtocolGuid = &gEfiIp6ProtocolGuid;
    432   }
    433 
    434   ProtoData = (TCP_PROTO_DATA *) Sk->ProtoReserved;
    435   Tcb       = ProtoData->TcpPcb;
    436 
    437   ASSERT (Tcb != NULL);
    438 
    439   TcpFlushPcb (Tcb);
    440 
    441   //
    442   // Close the IP protocol.
    443   //
    444   gBS->CloseProtocol (
    445          Tcb->IpInfo->ChildHandle,
    446          IpProtocolGuid,
    447          ProtoData->TcpService->IpIo->Image,
    448          Sk->SockHandle
    449          );
    450 
    451   IpIoRemoveIp (ProtoData->TcpService->IpIo, Tcb->IpInfo);
    452 
    453   FreePool (Tcb);
    454 
    455   ProtoData->TcpPcb = NULL;
    456 }
    457 
    458 /**
    459   Configure the Pcb using CfgData.
    460 
    461   @param[in]  Sk                 Pointer to the socket of this TCP instance.
    462   @param[in]  CfgData            Pointer to the TCP configuration data.
    463 
    464   @retval EFI_SUCCESS            The operation completed successfully.
    465   @retval EFI_INVALID_PARAMETER  A same access point has been configured in
    466                                  another TCP instance.
    467   @retval EFI_OUT_OF_RESOURCES   Failed due to resource limits.
    468 
    469 **/
    470 EFI_STATUS
    471 TcpConfigurePcb (
    472   IN SOCKET           *Sk,
    473   IN TCP_CONFIG_DATA  *CfgData
    474   )
    475 {
    476   IP_IO_IP_CONFIG_DATA IpCfgData;
    477   EFI_STATUS           Status;
    478   EFI_TCP4_OPTION      *Option;
    479   TCP_PROTO_DATA       *TcpProto;
    480   TCP_CB               *Tcb;
    481   TCP_ACCESS_POINT     *TcpAp;
    482 
    483   ASSERT ((CfgData != NULL) && (Sk != NULL) && (Sk->SockHandle != NULL));
    484 
    485   TcpProto = (TCP_PROTO_DATA *) Sk->ProtoReserved;
    486   Tcb      = TcpProto->TcpPcb;
    487 
    488   ASSERT (Tcb != NULL);
    489 
    490   if (Sk->IpVersion == IP_VERSION_4) {
    491     //
    492     // Add Ip for send pkt to the peer
    493     //
    494     CopyMem (&IpCfgData.Ip4CfgData, &mIp4IoDefaultIpConfigData, sizeof (EFI_IP4_CONFIG_DATA));
    495     IpCfgData.Ip4CfgData.DefaultProtocol    = EFI_IP_PROTO_TCP;
    496     IpCfgData.Ip4CfgData.TypeOfService      = CfgData->Tcp4CfgData.TypeOfService;
    497     IpCfgData.Ip4CfgData.TimeToLive         = CfgData->Tcp4CfgData.TimeToLive;
    498     IpCfgData.Ip4CfgData.UseDefaultAddress  = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress;
    499     IP4_COPY_ADDRESS (
    500       &IpCfgData.Ip4CfgData.SubnetMask,
    501       &CfgData->Tcp4CfgData.AccessPoint.SubnetMask
    502       );
    503     IpCfgData.Ip4CfgData.ReceiveTimeout     = (UINT32) (-1);
    504     IP4_COPY_ADDRESS (
    505       &IpCfgData.Ip4CfgData.StationAddress,
    506       &CfgData->Tcp4CfgData.AccessPoint.StationAddress
    507       );
    508 
    509   } else {
    510     ASSERT (Sk->IpVersion == IP_VERSION_6);
    511 
    512     CopyMem (&IpCfgData.Ip6CfgData, &mIp6IoDefaultIpConfigData, sizeof (EFI_IP6_CONFIG_DATA));
    513     IpCfgData.Ip6CfgData.DefaultProtocol    = EFI_IP_PROTO_TCP;
    514     IpCfgData.Ip6CfgData.TrafficClass       = CfgData->Tcp6CfgData.TrafficClass;
    515     IpCfgData.Ip6CfgData.HopLimit           = CfgData->Tcp6CfgData.HopLimit;
    516     IpCfgData.Ip6CfgData.ReceiveTimeout     = (UINT32) (-1);
    517     IP6_COPY_ADDRESS (
    518       &IpCfgData.Ip6CfgData.StationAddress,
    519       &CfgData->Tcp6CfgData.AccessPoint.StationAddress
    520       );
    521     IP6_COPY_ADDRESS (
    522       &IpCfgData.Ip6CfgData.DestinationAddress,
    523       &CfgData->Tcp6CfgData.AccessPoint.RemoteAddress
    524       );
    525   }
    526 
    527   //
    528   // Configure the IP instance this Tcb consumes.
    529   //
    530   Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData);
    531   if (EFI_ERROR (Status)) {
    532     goto OnExit;
    533   }
    534 
    535   if (Sk->IpVersion == IP_VERSION_4) {
    536     //
    537     // Get the default address information if the instance is configured to use default address.
    538     //
    539     IP4_COPY_ADDRESS (
    540       &CfgData->Tcp4CfgData.AccessPoint.StationAddress,
    541       &IpCfgData.Ip4CfgData.StationAddress
    542       );
    543     IP4_COPY_ADDRESS (
    544       &CfgData->Tcp4CfgData.AccessPoint.SubnetMask,
    545       &IpCfgData.Ip4CfgData.SubnetMask
    546       );
    547 
    548     TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp4CfgData.AccessPoint;
    549   } else {
    550     IP6_COPY_ADDRESS (
    551       &CfgData->Tcp6CfgData.AccessPoint.StationAddress,
    552       &IpCfgData.Ip6CfgData.StationAddress
    553       );
    554 
    555     TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp6CfgData.AccessPoint;
    556   }
    557 
    558   //
    559   // check if we can bind this endpoint in CfgData
    560   //
    561   Status = TcpBind (TcpAp, Sk->IpVersion);
    562 
    563   if (EFI_ERROR (Status)) {
    564     DEBUG (
    565       (EFI_D_ERROR,
    566       "TcpConfigurePcb: Bind endpoint failed with %r\n",
    567       Status)
    568       );
    569 
    570     goto OnExit;
    571   }
    572 
    573   //
    574   // Initalize the operating information in this Tcb
    575   //
    576   ASSERT (Tcb->State == TCP_CLOSED &&
    577     IsListEmpty (&Tcb->SndQue) &&
    578     IsListEmpty (&Tcb->RcvQue));
    579 
    580   TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
    581   Tcb->State            = TCP_CLOSED;
    582 
    583   Tcb->SndMss           = 536;
    584   Tcb->RcvMss           = TcpGetRcvMss (Sk);
    585 
    586   Tcb->SRtt             = 0;
    587   Tcb->Rto              = 3 * TCP_TICK_HZ;
    588 
    589   Tcb->CWnd             = Tcb->SndMss;
    590   Tcb->Ssthresh         = 0xffffffff;
    591 
    592   Tcb->CongestState     = TCP_CONGEST_OPEN;
    593 
    594   Tcb->KeepAliveIdle    = TCP_KEEPALIVE_IDLE_MIN;
    595   Tcb->KeepAlivePeriod  = TCP_KEEPALIVE_PERIOD;
    596   Tcb->MaxKeepAlive     = TCP_MAX_KEEPALIVE;
    597   Tcb->MaxRexmit        = TCP_MAX_LOSS;
    598   Tcb->FinWait2Timeout  = TCP_FIN_WAIT2_TIME;
    599   Tcb->TimeWaitTimeout  = TCP_TIME_WAIT_TIME;
    600   Tcb->ConnectTimeout   = TCP_CONNECT_TIME;
    601 
    602   if (Sk->IpVersion == IP_VERSION_4) {
    603     //
    604     // initialize Tcb in the light of CfgData
    605     //
    606     Tcb->Ttl            = CfgData->Tcp4CfgData.TimeToLive;
    607     Tcb->Tos            = CfgData->Tcp4CfgData.TypeOfService;
    608 
    609     Tcb->UseDefaultAddr = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress;
    610 
    611     CopyMem (&Tcb->LocalEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.StationAddress, sizeof (IP4_ADDR));
    612     Tcb->LocalEnd.Port  = HTONS (CfgData->Tcp4CfgData.AccessPoint.StationPort);
    613     IP4_COPY_ADDRESS (&Tcb->SubnetMask, &CfgData->Tcp4CfgData.AccessPoint.SubnetMask);
    614 
    615     CopyMem (&Tcb->RemoteEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.RemoteAddress, sizeof (IP4_ADDR));
    616     Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp4CfgData.AccessPoint.RemotePort);
    617 
    618     Option              = CfgData->Tcp4CfgData.ControlOption;
    619   } else {
    620     Tcb->Ttl            = CfgData->Tcp6CfgData.HopLimit;
    621     Tcb->Tos            = CfgData->Tcp6CfgData.TrafficClass;
    622 
    623     IP6_COPY_ADDRESS (&Tcb->LocalEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.StationAddress);
    624     Tcb->LocalEnd.Port  = HTONS (CfgData->Tcp6CfgData.AccessPoint.StationPort);
    625 
    626     IP6_COPY_ADDRESS (&Tcb->RemoteEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.RemoteAddress);
    627     Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp6CfgData.AccessPoint.RemotePort);
    628 
    629     //
    630     // Type EFI_TCP4_OPTION and EFI_TCP6_OPTION are the same.
    631     //
    632     Option              = (EFI_TCP4_OPTION *) CfgData->Tcp6CfgData.ControlOption;
    633   }
    634 
    635   if (Option != NULL) {
    636     SET_RCV_BUFFSIZE (
    637       Sk,
    638       (UINT32) (TCP_COMP_VAL (
    639                   TCP_RCV_BUF_SIZE_MIN,
    640                   TCP_RCV_BUF_SIZE,
    641                   TCP_RCV_BUF_SIZE,
    642                   Option->ReceiveBufferSize
    643                   )
    644                )
    645       );
    646     SET_SND_BUFFSIZE (
    647       Sk,
    648       (UINT32) (TCP_COMP_VAL (
    649                   TCP_SND_BUF_SIZE_MIN,
    650                   TCP_SND_BUF_SIZE,
    651                   TCP_SND_BUF_SIZE,
    652                   Option->SendBufferSize
    653                   )
    654                )
    655       );
    656 
    657     SET_BACKLOG (
    658       Sk,
    659       (UINT32) (TCP_COMP_VAL (
    660                   TCP_BACKLOG_MIN,
    661                   TCP_BACKLOG,
    662                   TCP_BACKLOG,
    663                   Option->MaxSynBackLog
    664                   )
    665                )
    666       );
    667 
    668     Tcb->MaxRexmit = (UINT16) TCP_COMP_VAL (
    669                                 TCP_MAX_LOSS_MIN,
    670                                 TCP_MAX_LOSS,
    671                                 TCP_MAX_LOSS,
    672                                 Option->DataRetries
    673                                 );
    674     Tcb->FinWait2Timeout = TCP_COMP_VAL (
    675                               TCP_FIN_WAIT2_TIME,
    676                               TCP_FIN_WAIT2_TIME_MAX,
    677                               TCP_FIN_WAIT2_TIME,
    678                               (UINT32) (Option->FinTimeout * TCP_TICK_HZ)
    679                               );
    680 
    681     if (Option->TimeWaitTimeout != 0) {
    682       Tcb->TimeWaitTimeout = TCP_COMP_VAL (
    683                                TCP_TIME_WAIT_TIME,
    684                                TCP_TIME_WAIT_TIME_MAX,
    685                                TCP_TIME_WAIT_TIME,
    686                                (UINT32) (Option->TimeWaitTimeout * TCP_TICK_HZ)
    687                                );
    688     } else {
    689       Tcb->TimeWaitTimeout = 0;
    690     }
    691 
    692     if (Option->KeepAliveProbes != 0) {
    693       TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
    694 
    695       Tcb->MaxKeepAlive = (UINT8) TCP_COMP_VAL (
    696                                     TCP_MAX_KEEPALIVE_MIN,
    697                                     TCP_MAX_KEEPALIVE,
    698                                     TCP_MAX_KEEPALIVE,
    699                                     Option->KeepAliveProbes
    700                                     );
    701       Tcb->KeepAliveIdle = TCP_COMP_VAL (
    702                              TCP_KEEPALIVE_IDLE_MIN,
    703                              TCP_KEEPALIVE_IDLE_MAX,
    704                              TCP_KEEPALIVE_IDLE_MIN,
    705                              (UINT32) (Option->KeepAliveTime * TCP_TICK_HZ)
    706                              );
    707       Tcb->KeepAlivePeriod = TCP_COMP_VAL (
    708                                TCP_KEEPALIVE_PERIOD_MIN,
    709                                TCP_KEEPALIVE_PERIOD,
    710                                TCP_KEEPALIVE_PERIOD,
    711                                (UINT32) (Option->KeepAliveInterval * TCP_TICK_HZ)
    712                                );
    713     }
    714 
    715     Tcb->ConnectTimeout = TCP_COMP_VAL (
    716                             TCP_CONNECT_TIME_MIN,
    717                             TCP_CONNECT_TIME,
    718                             TCP_CONNECT_TIME,
    719                             (UINT32) (Option->ConnectionTimeout * TCP_TICK_HZ)
    720                             );
    721 
    722     if (!Option->EnableNagle) {
    723       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);
    724     }
    725 
    726     if (!Option->EnableTimeStamp) {
    727       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_TS);
    728     }
    729 
    730     if (!Option->EnableWindowScaling) {
    731       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_WS);
    732     }
    733   }
    734 
    735   //
    736   // The socket is bound, the <SrcIp, SrcPort, DstIp, DstPort> is
    737   // determined, construct the IP device path and install it.
    738   //
    739   Status = TcpInstallDevicePath (Sk);
    740   if (EFI_ERROR (Status)) {
    741     goto OnExit;
    742   }
    743 
    744   //
    745   // update state of Tcb and socket
    746   //
    747   if (((Sk->IpVersion == IP_VERSION_4) && !CfgData->Tcp4CfgData.AccessPoint.ActiveFlag) ||
    748       ((Sk->IpVersion == IP_VERSION_6) && !CfgData->Tcp6CfgData.AccessPoint.ActiveFlag)
    749       ) {
    750 
    751     TcpSetState (Tcb, TCP_LISTEN);
    752     SockSetState (Sk, SO_LISTENING);
    753 
    754     Sk->ConfigureState = SO_CONFIGURED_PASSIVE;
    755   } else {
    756 
    757     Sk->ConfigureState = SO_CONFIGURED_ACTIVE;
    758   }
    759 
    760   if (Sk->IpVersion == IP_VERSION_6) {
    761     Tcb->Tick          = TCP6_REFRESH_NEIGHBOR_TICK;
    762 
    763     if (NetIp6IsUnspecifiedAddr (&Tcb->RemoteEnd.Ip.v6)) {
    764       Tcb->RemoteIpZero = TRUE;
    765     }
    766   }
    767 
    768   TcpInsertTcb (Tcb);
    769 
    770 OnExit:
    771 
    772   return Status;
    773 }
    774 
    775 /**
    776   The procotol handler provided to the socket layer, which is used to
    777   dispatch the socket level requests by calling the corresponding
    778   TCP layer functions.
    779 
    780   @param[in]  Sock               Pointer to the socket of this TCP instance.
    781   @param[in]  Request            The code of this operation request.
    782   @param[in]  Data               Pointer to the operation specific data passed in
    783                                  together with the operation request. This is an
    784                                  optional parameter that may be NULL.
    785 
    786   @retval EFI_SUCCESS            The socket request completed successfully.
    787   @retval other                  The error status returned by the corresponding TCP
    788                                  layer function.
    789 
    790 **/
    791 EFI_STATUS
    792 TcpDispatcher (
    793   IN SOCKET                  *Sock,
    794   IN UINT8                   Request,
    795   IN VOID                    *Data    OPTIONAL
    796   )
    797 {
    798   TCP_CB          *Tcb;
    799   TCP_PROTO_DATA  *ProtoData;
    800 
    801   ProtoData = (TCP_PROTO_DATA *) Sock->ProtoReserved;
    802   Tcb       = ProtoData->TcpPcb;
    803 
    804   switch (Request) {
    805   case SOCK_POLL:
    806     if (Tcb->Sk->IpVersion == IP_VERSION_4) {
    807       ProtoData->TcpService->IpIo->Ip.Ip4->Poll (ProtoData->TcpService->IpIo->Ip.Ip4);
    808     } else {
    809       ProtoData->TcpService->IpIo->Ip.Ip6->Poll (ProtoData->TcpService->IpIo->Ip.Ip6);
    810     }
    811 
    812     break;
    813 
    814   case SOCK_CONSUMED:
    815     //
    816     // After user received data from socket buffer, socket will
    817     // notify TCP using this message to give it a chance to send out
    818     // window update information
    819     //
    820     ASSERT (Tcb != NULL);
    821     TcpOnAppConsume (Tcb);
    822     break;
    823 
    824   case SOCK_SND:
    825 
    826     ASSERT (Tcb != NULL);
    827     TcpOnAppSend (Tcb);
    828     break;
    829 
    830   case SOCK_CLOSE:
    831 
    832     TcpOnAppClose (Tcb);
    833 
    834     break;
    835 
    836   case SOCK_ABORT:
    837 
    838     TcpOnAppAbort (Tcb);
    839 
    840     break;
    841 
    842   case SOCK_SNDPUSH:
    843     Tcb->SndPsh = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk);
    844     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);
    845 
    846     break;
    847 
    848   case SOCK_SNDURG:
    849     Tcb->SndUp = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk) - 1;
    850     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
    851 
    852     break;
    853 
    854   case SOCK_CONNECT:
    855 
    856     TcpOnAppConnect (Tcb);
    857 
    858     break;
    859 
    860   case SOCK_ATTACH:
    861 
    862     return TcpAttachPcb (Sock);
    863 
    864     break;
    865 
    866   case SOCK_FLUSH:
    867 
    868     TcpFlushPcb (Tcb);
    869 
    870     break;
    871 
    872   case SOCK_DETACH:
    873 
    874     TcpDetachPcb (Sock);
    875 
    876     break;
    877 
    878   case SOCK_CONFIGURE:
    879 
    880     return TcpConfigurePcb (
    881             Sock,
    882             (TCP_CONFIG_DATA *) Data
    883             );
    884 
    885     break;
    886 
    887   case SOCK_MODE:
    888 
    889     ASSERT ((Data != NULL) && (Tcb != NULL));
    890 
    891     if (Tcb->Sk->IpVersion == IP_VERSION_4) {
    892 
    893       return Tcp4GetMode (Tcb, (TCP4_MODE_DATA *) Data);
    894     } else {
    895 
    896       return Tcp6GetMode (Tcb, (TCP6_MODE_DATA *) Data);
    897     }
    898 
    899     break;
    900 
    901   case SOCK_ROUTE:
    902 
    903     ASSERT ((Data != NULL) && (Tcb != NULL) && (Tcb->Sk->IpVersion == IP_VERSION_4));
    904 
    905     return Tcp4Route (Tcb, (TCP4_ROUTE_INFO *) Data);
    906 
    907   default:
    908 
    909     return EFI_UNSUPPORTED;
    910   }
    911 
    912   return EFI_SUCCESS;
    913 }
    914