v2: Handle error case in SockCreateChild and fix typo issue when we destroy the socket Sock and its associated protocol control block, we need to first close the parent protocol, then remove the protocol from childHandle and last to free any data structures that allocated in CreateChild. But currently, we free the socket data (Socket ConfigureState) before removing the protocol form the childhandle. So if the up layer want to send the tcp reset packet in it's driver binding stop function, it will failed. The IpInstance destroy state is redundant and may cause ip transmit failed if up layer want to send ip packet. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Zhang Lubo <lubo.zhang@intel.com> Cc: Wu Jiaxin <jiaxin.wu@intel.com> Cc: Ye Ting <ting.ye@intel.com> Cc: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Ye Ting <ting.ye@intel.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Wu Jiaxin <jiaxin.wu@intel.com>
		
			
				
	
	
		
			718 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			718 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Tcp request dispatcher implementation.
 | |
| 
 | |
| (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
 | |
| Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php<BR>
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "Tcp4Main.h"
 | |
| 
 | |
| #define TCP_COMP_VAL(Min, Max, Default, Val) \
 | |
|   ((((Val) <= (Max)) && ((Val) >= (Min))) ? (Val) : (Default))
 | |
| 
 | |
| /**
 | |
|   Add or remove a route entry in the IP route table associated with this TCP instance.
 | |
| 
 | |
|   @param  Tcb                   Pointer to the TCP_CB of this TCP instance.
 | |
|   @param  RouteInfo             Pointer to the route info to be processed.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The operation completed successfully.
 | |
|   @retval EFI_NOT_STARTED       The driver instance has not been started.
 | |
|   @retval EFI_NO_MAPPING        When using the default address, configuration(DHCP,
 | |
|                                 BOOTP, RARP, etc.) is not finished yet.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Could not add the entry to the routing table.
 | |
|   @retval EFI_NOT_FOUND         This route is not in the routing table
 | |
|                                 (when RouteInfo->DeleteRoute is TRUE).
 | |
|   @retval EFI_ACCESS_DENIED     The route is already defined in the routing table
 | |
|                                 (when RouteInfo->DeleteRoute is FALSE).
 | |
| **/
 | |
| EFI_STATUS
 | |
| Tcp4Route (
 | |
|   IN TCP_CB           *Tcb,
 | |
|   IN TCP4_ROUTE_INFO  *RouteInfo
 | |
|   )
 | |
| {
 | |
|   EFI_IP4_PROTOCOL  *Ip4;
 | |
| 
 | |
|   Ip4 = Tcb->IpInfo->Ip.Ip4;
 | |
| 
 | |
|   ASSERT (Ip4 != NULL);
 | |
| 
 | |
|   return Ip4->Routes (
 | |
|               Ip4,
 | |
|               RouteInfo->DeleteRoute,
 | |
|               RouteInfo->SubnetAddress,
 | |
|               RouteInfo->SubnetMask,
 | |
|               RouteInfo->GatewayAddress
 | |
|               );
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Get the operational settings of this TCP instance.
 | |
| 
 | |
|   @param  Tcb                    Pointer to the TCP_CB of this TCP instance.
 | |
|   @param  Mode                   Pointer to the buffer to store the operational
 | |
|                                  settings.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The mode data is read.
 | |
|   @retval EFI_NOT_STARTED        No configuration data is available because this
 | |
|                                  instance hasn't been started.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Tcp4GetMode (
 | |
|   IN     TCP_CB         *Tcb,
 | |
|   IN OUT TCP4_MODE_DATA *Mode
 | |
|   )
 | |
| {
 | |
|   SOCKET                *Sock;
 | |
|   EFI_TCP4_CONFIG_DATA  *ConfigData;
 | |
|   EFI_TCP4_ACCESS_POINT *AccessPoint;
 | |
|   EFI_TCP4_OPTION       *Option;
 | |
|   EFI_IP4_PROTOCOL      *Ip;
 | |
| 
 | |
|   Sock = Tcb->Sk;
 | |
| 
 | |
|   if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp4ConfigData != NULL)) {
 | |
|     return EFI_NOT_STARTED;
 | |
|   }
 | |
| 
 | |
|   if (Mode->Tcp4State != NULL) {
 | |
|     *(Mode->Tcp4State) = (EFI_TCP4_CONNECTION_STATE) Tcb->State;
 | |
|   }
 | |
| 
 | |
|   if (Mode->Tcp4ConfigData != NULL) {
 | |
| 
 | |
|     ConfigData                      = Mode->Tcp4ConfigData;
 | |
|     AccessPoint                     = &(ConfigData->AccessPoint);
 | |
|     Option                          = ConfigData->ControlOption;
 | |
| 
 | |
|     ConfigData->TypeOfService       = Tcb->Tos;
 | |
|     ConfigData->TimeToLive          = Tcb->Ttl;
 | |
| 
 | |
|     AccessPoint->UseDefaultAddress  = Tcb->UseDefaultAddr;
 | |
| 
 | |
|     IP4_COPY_ADDRESS (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip);
 | |
|     IP4_COPY_ADDRESS (&AccessPoint->SubnetMask, &Tcb->SubnetMask);
 | |
|     AccessPoint->StationPort        = NTOHS (Tcb->LocalEnd.Port);
 | |
| 
 | |
|     IP4_COPY_ADDRESS (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip);
 | |
|     AccessPoint->RemotePort         = NTOHS (Tcb->RemoteEnd.Port);
 | |
|     AccessPoint->ActiveFlag         = (BOOLEAN) (Tcb->State != TCP_LISTEN);
 | |
| 
 | |
|     if (Option != NULL) {
 | |
|       Option->ReceiveBufferSize       = GET_RCV_BUFFSIZE (Tcb->Sk);
 | |
|       Option->SendBufferSize          = GET_SND_BUFFSIZE (Tcb->Sk);
 | |
|       Option->MaxSynBackLog           = GET_BACKLOG (Tcb->Sk);
 | |
| 
 | |
|       Option->ConnectionTimeout       = Tcb->ConnectTimeout / TCP_TICK_HZ;
 | |
|       Option->DataRetries             = Tcb->MaxRexmit;
 | |
|       Option->FinTimeout              = Tcb->FinWait2Timeout / TCP_TICK_HZ;
 | |
|       Option->TimeWaitTimeout         = Tcb->TimeWaitTimeout / TCP_TICK_HZ;
 | |
|       Option->KeepAliveProbes         = Tcb->MaxKeepAlive;
 | |
|       Option->KeepAliveTime           = Tcb->KeepAliveIdle / TCP_TICK_HZ;
 | |
|       Option->KeepAliveInterval       = Tcb->KeepAlivePeriod / TCP_TICK_HZ;
 | |
| 
 | |
|       Option->EnableNagle         = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE));
 | |
|       Option->EnableTimeStamp     = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS));
 | |
|       Option->EnableWindowScaling = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS));
 | |
| 
 | |
|       Option->EnableSelectiveAck      = FALSE;
 | |
|       Option->EnablePathMtuDiscovery  = FALSE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Ip = Tcb->IpInfo->Ip.Ip4;
 | |
|   ASSERT (Ip != NULL);
 | |
| 
 | |
|   return Ip->GetModeData (Ip, Mode->Ip4ModeData, Mode->MnpConfigData, Mode->SnpModeData);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   If AP->StationPort isn't zero, check whether the access point
 | |
|   is registered, else generate a random station port for this
 | |
|   access point.
 | |
| 
 | |
|   @param  AP                     Pointer to the access point.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The check is passed or the port is assigned.
 | |
|   @retval EFI_INVALID_PARAMETER  The non-zero station port is already used.
 | |
|   @retval EFI_OUT_OF_RESOURCES   No port can be allocated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Tcp4Bind (
 | |
|   IN EFI_TCP4_ACCESS_POINT *AP
 | |
|   )
 | |
| {
 | |
|   BOOLEAN Cycle;
 | |
| 
 | |
|   if (0 != AP->StationPort) {
 | |
|     //
 | |
|     // check if a same endpoint is bound
 | |
|     //
 | |
|     if (TcpFindTcbByPeer (&AP->StationAddress, AP->StationPort)) {
 | |
| 
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // generate a random port
 | |
|     //
 | |
|     Cycle = FALSE;
 | |
| 
 | |
|     if (TCP4_PORT_USER_RESERVED == mTcp4RandomPort) {
 | |
|       mTcp4RandomPort = TCP4_PORT_KNOWN;
 | |
|     }
 | |
| 
 | |
|     mTcp4RandomPort++;
 | |
| 
 | |
|     while (TcpFindTcbByPeer (&AP->StationAddress, mTcp4RandomPort)) {
 | |
| 
 | |
|       mTcp4RandomPort++;
 | |
| 
 | |
|       if (mTcp4RandomPort <= TCP4_PORT_KNOWN) {
 | |
| 
 | |
|         if (Cycle) {
 | |
|           DEBUG ((EFI_D_ERROR, "Tcp4Bind: no port can be allocated "
 | |
|             "for this pcb\n"));
 | |
| 
 | |
|           return EFI_OUT_OF_RESOURCES;
 | |
|         }
 | |
| 
 | |
|         mTcp4RandomPort = TCP4_PORT_KNOWN + 1;
 | |
| 
 | |
|         Cycle = TRUE;
 | |
|       }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     AP->StationPort = mTcp4RandomPort;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Flush the Tcb add its associated protocols.
 | |
| 
 | |
|   @param  Tcb                    Pointer to the TCP_CB to be flushed.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| Tcp4FlushPcb (
 | |
|   IN TCP_CB *Tcb
 | |
|   )
 | |
| {
 | |
|   SOCKET           *Sock;
 | |
| 
 | |
|   IpIoConfigIp (Tcb->IpInfo, NULL);
 | |
| 
 | |
|   Sock     = Tcb->Sk;
 | |
| 
 | |
|   if (SOCK_IS_CONFIGURED (Sock)) {
 | |
|     RemoveEntryList (&Tcb->List);
 | |
| 
 | |
|     //
 | |
|     // Uninstall the device path protocol.
 | |
|     //
 | |
|     if (Sock->DevicePath != NULL) {
 | |
|       gBS->UninstallProtocolInterface (
 | |
|              Sock->SockHandle,
 | |
|              &gEfiDevicePathProtocolGuid,
 | |
|              Sock->DevicePath
 | |
|              );
 | |
|       FreePool (Sock->DevicePath);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   NetbufFreeList (&Tcb->SndQue);
 | |
|   NetbufFreeList (&Tcb->RcvQue);
 | |
|   Tcb->State = TCP_CLOSED;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Attach a Pcb to the socket.
 | |
| 
 | |
|   @param  Sk                     Pointer to the socket of this TCP instance.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The operation is completed successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES   Failed due to resource limit.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Tcp4AttachPcb (
 | |
|   IN SOCKET  *Sk
 | |
|   )
 | |
| {
 | |
|   TCP_CB            *Tcb;
 | |
|   TCP4_PROTO_DATA   *ProtoData;
 | |
|   IP_IO             *IpIo;
 | |
|   EFI_STATUS        Status;
 | |
|   VOID              *Ip;
 | |
| 
 | |
|   Tcb = AllocateZeroPool (sizeof (TCP_CB));
 | |
| 
 | |
|   if (Tcb == NULL) {
 | |
| 
 | |
|     DEBUG ((EFI_D_ERROR, "Tcp4ConfigurePcb: failed to allocate a TCB\n"));
 | |
| 
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   ProtoData  = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
 | |
|   IpIo       = ProtoData->TcpService->IpIo;
 | |
| 
 | |
|   //
 | |
|   // Create an IpInfo for this Tcb.
 | |
|   //
 | |
|   Tcb->IpInfo = IpIoAddIp (IpIo);
 | |
|   if (Tcb->IpInfo == NULL) {
 | |
| 
 | |
|     FreePool (Tcb);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Open the new created IP instance BY_CHILD.
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Tcb->IpInfo->ChildHandle,
 | |
|                   &gEfiIp4ProtocolGuid,
 | |
|                   &Ip,
 | |
|                   IpIo->Image,
 | |
|                   Sk->SockHandle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     IpIoRemoveIp (IpIo, Tcb->IpInfo);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   InitializeListHead (&Tcb->List);
 | |
|   InitializeListHead (&Tcb->SndQue);
 | |
|   InitializeListHead (&Tcb->RcvQue);
 | |
| 
 | |
|   Tcb->State        = TCP_CLOSED;
 | |
|   Tcb->Sk           = Sk;
 | |
|   ProtoData->TcpPcb = Tcb;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Detach the Pcb of the socket.
 | |
| 
 | |
|   @param  Sk                     Pointer to the socket of this TCP instance.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| Tcp4DetachPcb (
 | |
|   IN SOCKET  *Sk
 | |
|   )
 | |
| {
 | |
|   TCP4_PROTO_DATA  *ProtoData;
 | |
|   TCP_CB           *Tcb;
 | |
| 
 | |
|   ProtoData = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
 | |
|   Tcb       = ProtoData->TcpPcb;
 | |
| 
 | |
|   ASSERT (Tcb != NULL);
 | |
| 
 | |
|   Tcp4FlushPcb (Tcb);
 | |
|   
 | |
|   IpIoRemoveIp (ProtoData->TcpService->IpIo, Tcb->IpInfo);
 | |
| 
 | |
|   FreePool (Tcb);
 | |
| 
 | |
|   ProtoData->TcpPcb = NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Configure the Pcb using CfgData.
 | |
| 
 | |
|   @param  Sk                     Pointer to the socket of this TCP instance.
 | |
|   @param  CfgData                Pointer to the TCP configuration data.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The operation is completed successfully.
 | |
|   @retval EFI_INVALID_PARAMETER  A same access point has been configured in
 | |
|                                  another TCP instance.
 | |
|   @retval EFI_OUT_OF_RESOURCES   Failed due to resource limit.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Tcp4ConfigurePcb (
 | |
|   IN SOCKET               *Sk,
 | |
|   IN EFI_TCP4_CONFIG_DATA *CfgData
 | |
|   )
 | |
| {
 | |
|   EFI_IP4_CONFIG_DATA IpCfgData;
 | |
|   EFI_STATUS          Status;
 | |
|   EFI_TCP4_OPTION     *Option;
 | |
|   TCP4_PROTO_DATA     *TcpProto;
 | |
|   TCP_CB              *Tcb;
 | |
| 
 | |
|   ASSERT ((CfgData != NULL) && (Sk != NULL) && (Sk->SockHandle != NULL));
 | |
| 
 | |
|   TcpProto = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
 | |
|   Tcb      = TcpProto->TcpPcb;
 | |
| 
 | |
|   ASSERT (Tcb != NULL);
 | |
| 
 | |
|   //
 | |
|   // Add Ip for send pkt to the peer
 | |
|   //
 | |
|   CopyMem (&IpCfgData, &mIp4IoDefaultIpConfigData, sizeof (IpCfgData));
 | |
|   IpCfgData.DefaultProtocol   = EFI_IP_PROTO_TCP;
 | |
|   IpCfgData.UseDefaultAddress = CfgData->AccessPoint.UseDefaultAddress;
 | |
|   IpCfgData.StationAddress    = CfgData->AccessPoint.StationAddress;
 | |
|   IpCfgData.SubnetMask        = CfgData->AccessPoint.SubnetMask;
 | |
|   IpCfgData.ReceiveTimeout    = (UINT32) (-1);
 | |
| 
 | |
|   //
 | |
|   // Configure the IP instance this Tcb consumes.
 | |
|   //
 | |
|   Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto OnExit;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the default address info if the instance is configured to use default address.
 | |
|   //
 | |
|   if (CfgData->AccessPoint.UseDefaultAddress) {
 | |
|     CfgData->AccessPoint.StationAddress = IpCfgData.StationAddress;
 | |
|     CfgData->AccessPoint.SubnetMask     = IpCfgData.SubnetMask;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // check if we can bind this endpoint in CfgData
 | |
|   //
 | |
|   Status = Tcp4Bind (&(CfgData->AccessPoint));
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "Tcp4ConfigurePcb: Bind endpoint failed "
 | |
|       "with %r\n", Status));
 | |
| 
 | |
|     goto OnExit;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Initalize the operating information in this Tcb
 | |
|   //
 | |
|   ASSERT (Tcb->State == TCP_CLOSED &&
 | |
|     IsListEmpty (&Tcb->SndQue) &&
 | |
|     IsListEmpty (&Tcb->RcvQue));
 | |
| 
 | |
|   TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
 | |
|   Tcb->State            = TCP_CLOSED;
 | |
| 
 | |
|   Tcb->SndMss           = 536;
 | |
|   Tcb->RcvMss           = TcpGetRcvMss (Sk);
 | |
| 
 | |
|   Tcb->SRtt             = 0;
 | |
|   Tcb->Rto              = 3 * TCP_TICK_HZ;
 | |
| 
 | |
|   Tcb->CWnd             = Tcb->SndMss;
 | |
|   Tcb->Ssthresh         = 0xffffffff;
 | |
| 
 | |
|   Tcb->CongestState     = TCP_CONGEST_OPEN;
 | |
| 
 | |
|   Tcb->KeepAliveIdle    = TCP_KEEPALIVE_IDLE_MIN;
 | |
|   Tcb->KeepAlivePeriod  = TCP_KEEPALIVE_PERIOD;
 | |
|   Tcb->MaxKeepAlive     = TCP_MAX_KEEPALIVE;
 | |
|   Tcb->MaxRexmit        = TCP_MAX_LOSS;
 | |
|   Tcb->FinWait2Timeout  = TCP_FIN_WAIT2_TIME;
 | |
|   Tcb->TimeWaitTimeout  = TCP_TIME_WAIT_TIME;
 | |
|   Tcb->ConnectTimeout   = TCP_CONNECT_TIME;
 | |
| 
 | |
|   //
 | |
|   // initialize Tcb in the light of CfgData
 | |
|   //
 | |
|   Tcb->Ttl            = CfgData->TimeToLive;
 | |
|   Tcb->Tos            = CfgData->TypeOfService;
 | |
| 
 | |
|   Tcb->UseDefaultAddr = CfgData->AccessPoint.UseDefaultAddress;
 | |
| 
 | |
|   CopyMem (&Tcb->LocalEnd.Ip, &CfgData->AccessPoint.StationAddress, sizeof (IP4_ADDR));
 | |
|   Tcb->LocalEnd.Port  = HTONS (CfgData->AccessPoint.StationPort);
 | |
|   IP4_COPY_ADDRESS (&Tcb->SubnetMask, &CfgData->AccessPoint.SubnetMask);
 | |
| 
 | |
|   if (CfgData->AccessPoint.ActiveFlag) {
 | |
|     CopyMem (&Tcb->RemoteEnd.Ip, &CfgData->AccessPoint.RemoteAddress, sizeof (IP4_ADDR));
 | |
|     Tcb->RemoteEnd.Port = HTONS (CfgData->AccessPoint.RemotePort);
 | |
|   } else {
 | |
|     Tcb->RemoteEnd.Ip   = 0;
 | |
|     Tcb->RemoteEnd.Port = 0;
 | |
|   }
 | |
| 
 | |
|   Option              = CfgData->ControlOption;
 | |
| 
 | |
|   if (Option != NULL) {
 | |
|     SET_RCV_BUFFSIZE (
 | |
|       Sk,
 | |
|       (UINT32) (TCP_COMP_VAL (
 | |
|                   TCP_RCV_BUF_SIZE_MIN,
 | |
|                   TCP_RCV_BUF_SIZE,
 | |
|                   TCP_RCV_BUF_SIZE,
 | |
|                   Option->ReceiveBufferSize
 | |
|                   )
 | |
|                )
 | |
|       );
 | |
|     SET_SND_BUFFSIZE (
 | |
|       Sk,
 | |
|       (UINT32) (TCP_COMP_VAL (
 | |
|                   TCP_SND_BUF_SIZE_MIN,
 | |
|                   TCP_SND_BUF_SIZE,
 | |
|                   TCP_SND_BUF_SIZE,
 | |
|                   Option->SendBufferSize
 | |
|                   )
 | |
|                )
 | |
|       );
 | |
| 
 | |
|     SET_BACKLOG (
 | |
|       Sk,
 | |
|       (UINT32) (TCP_COMP_VAL (
 | |
|                   TCP_BACKLOG_MIN,
 | |
|                   TCP_BACKLOG,
 | |
|                   TCP_BACKLOG,
 | |
|                   Option->MaxSynBackLog
 | |
|                   )
 | |
|                )
 | |
|       );
 | |
| 
 | |
|     Tcb->MaxRexmit = (UINT16) TCP_COMP_VAL (
 | |
|                                 TCP_MAX_LOSS_MIN,
 | |
|                                 TCP_MAX_LOSS,
 | |
|                                 TCP_MAX_LOSS,
 | |
|                                 Option->DataRetries
 | |
|                                 );
 | |
|     Tcb->FinWait2Timeout = TCP_COMP_VAL (
 | |
|                               TCP_FIN_WAIT2_TIME,
 | |
|                               TCP_FIN_WAIT2_TIME_MAX,
 | |
|                               TCP_FIN_WAIT2_TIME,
 | |
|                               (UINT32) (Option->FinTimeout * TCP_TICK_HZ)
 | |
|                               );
 | |
| 
 | |
|     if (Option->TimeWaitTimeout != 0) {
 | |
|       Tcb->TimeWaitTimeout = TCP_COMP_VAL (
 | |
|                                TCP_TIME_WAIT_TIME,
 | |
|                                TCP_TIME_WAIT_TIME_MAX,
 | |
|                                TCP_TIME_WAIT_TIME,
 | |
|                                (UINT32) (Option->TimeWaitTimeout * TCP_TICK_HZ)
 | |
|                                );
 | |
|     } else {
 | |
|       Tcb->TimeWaitTimeout = 0;
 | |
|     }
 | |
| 
 | |
|     if (Option->KeepAliveProbes != 0) {
 | |
|       TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
 | |
| 
 | |
|       Tcb->MaxKeepAlive = (UINT8) TCP_COMP_VAL (
 | |
|                                     TCP_MAX_KEEPALIVE_MIN,
 | |
|                                     TCP_MAX_KEEPALIVE,
 | |
|                                     TCP_MAX_KEEPALIVE,
 | |
|                                     Option->KeepAliveProbes
 | |
|                                     );
 | |
|       Tcb->KeepAliveIdle = TCP_COMP_VAL (
 | |
|                              TCP_KEEPALIVE_IDLE_MIN,
 | |
|                              TCP_KEEPALIVE_IDLE_MAX,
 | |
|                              TCP_KEEPALIVE_IDLE_MIN,
 | |
|                              (UINT32) (Option->KeepAliveTime * TCP_TICK_HZ)
 | |
|                              );
 | |
|       Tcb->KeepAlivePeriod = TCP_COMP_VAL (
 | |
|                                TCP_KEEPALIVE_PERIOD_MIN,
 | |
|                                TCP_KEEPALIVE_PERIOD,
 | |
|                                TCP_KEEPALIVE_PERIOD,
 | |
|                                (UINT32) (Option->KeepAliveInterval * TCP_TICK_HZ)
 | |
|                                );
 | |
|     }
 | |
| 
 | |
|     Tcb->ConnectTimeout = TCP_COMP_VAL (
 | |
|                             TCP_CONNECT_TIME_MIN,
 | |
|                             TCP_CONNECT_TIME,
 | |
|                             TCP_CONNECT_TIME,
 | |
|                             (UINT32) (Option->ConnectionTimeout * TCP_TICK_HZ)
 | |
|                             );
 | |
| 
 | |
|     if (!Option->EnableNagle) {
 | |
|       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);
 | |
|     }
 | |
| 
 | |
|     if (!Option->EnableTimeStamp) {
 | |
|       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_TS);
 | |
|     }
 | |
| 
 | |
|     if (!Option->EnableWindowScaling) {
 | |
|       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_WS);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // The socket is bound, the <SrcIp, SrcPort, DstIp, DstPort> is
 | |
|   // determined, construct the IP device path and install it.
 | |
|   //
 | |
|   Status = TcpInstallDevicePath (Sk);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto OnExit;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // update state of Tcb and socket
 | |
|   //
 | |
|   if (!CfgData->AccessPoint.ActiveFlag) {
 | |
| 
 | |
|     TcpSetState (Tcb, TCP_LISTEN);
 | |
|     SockSetState (Sk, SO_LISTENING);
 | |
| 
 | |
|     Sk->ConfigureState = SO_CONFIGURED_PASSIVE;
 | |
|   } else {
 | |
| 
 | |
|     Sk->ConfigureState = SO_CONFIGURED_ACTIVE;
 | |
|   }
 | |
| 
 | |
|   TcpInsertTcb (Tcb);
 | |
| 
 | |
| OnExit:
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   The procotol handler provided to the socket layer, used to
 | |
|   dispatch the socket level requests by calling the corresponding
 | |
|   TCP layer functions.
 | |
| 
 | |
|   @param  Sock                   Pointer to the socket of this TCP instance.
 | |
|   @param  Request                The code of this operation request.
 | |
|   @param  Data                   Pointer to the operation specific data passed in
 | |
|                                  together with the operation request.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The socket request is completed successfully.
 | |
|   @retval other                  The error status returned by the corresponding TCP
 | |
|                                  layer function.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Tcp4Dispatcher (
 | |
|   IN SOCKET                  *Sock,
 | |
|   IN UINT8                   Request,
 | |
|   IN VOID                    *Data    OPTIONAL
 | |
|   )
 | |
| {
 | |
|   TCP_CB            *Tcb;
 | |
|   TCP4_PROTO_DATA   *ProtoData;
 | |
|   EFI_IP4_PROTOCOL  *Ip;
 | |
| 
 | |
|   ProtoData = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
 | |
|   Tcb       = ProtoData->TcpPcb;
 | |
| 
 | |
|   switch (Request) {
 | |
|   case SOCK_POLL:
 | |
|     Ip = ProtoData->TcpService->IpIo->Ip.Ip4;
 | |
|     Ip->Poll (Ip);
 | |
|     break;
 | |
| 
 | |
|   case SOCK_CONSUMED:
 | |
|     //
 | |
|     // After user received data from socket buffer, socket will
 | |
|     // notify TCP using this message to give it a chance to send out
 | |
|     // window update information
 | |
|     //
 | |
|     ASSERT (Tcb != NULL);
 | |
|     TcpOnAppConsume (Tcb);
 | |
|     break;
 | |
| 
 | |
|   case SOCK_SND:
 | |
| 
 | |
|     ASSERT (Tcb != NULL);
 | |
|     TcpOnAppSend (Tcb);
 | |
|     break;
 | |
| 
 | |
|   case SOCK_CLOSE:
 | |
| 
 | |
|     TcpOnAppClose (Tcb);
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case SOCK_ABORT:
 | |
| 
 | |
|     TcpOnAppAbort (Tcb);
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case SOCK_SNDPUSH:
 | |
|     Tcb->SndPsh = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk);
 | |
|     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case SOCK_SNDURG:
 | |
|     Tcb->SndUp = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk) - 1;
 | |
|     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case SOCK_CONNECT:
 | |
| 
 | |
|     TcpOnAppConnect (Tcb);
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case SOCK_ATTACH:
 | |
| 
 | |
|     return Tcp4AttachPcb (Sock);
 | |
| 
 | |
|   case SOCK_FLUSH:
 | |
| 
 | |
|     Tcp4FlushPcb (Tcb);
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case SOCK_DETACH:
 | |
| 
 | |
|     Tcp4DetachPcb (Sock);
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case SOCK_CONFIGURE:
 | |
| 
 | |
|     return Tcp4ConfigurePcb (
 | |
|             Sock,
 | |
|             (EFI_TCP4_CONFIG_DATA *) Data
 | |
|             );
 | |
| 
 | |
|   case SOCK_MODE:
 | |
| 
 | |
|     ASSERT ((Data != NULL) && (Tcb != NULL));
 | |
| 
 | |
|     return Tcp4GetMode (Tcb, (TCP4_MODE_DATA *) Data);
 | |
| 
 | |
|   case SOCK_ROUTE:
 | |
| 
 | |
|     ASSERT ((Data != NULL) && (Tcb != NULL));
 | |
| 
 | |
|     return Tcp4Route (Tcb, (TCP4_ROUTE_INFO *) Data);
 | |
| 
 | |
|   default:
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| }
 |