/** @file | |
The implementation of a dispatch routine for processing TCP requests. | |
(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR> | |
Copyright (c) 2009 - 2014, 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. | |
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 "TcpMain.h" | |
/** | |
Add or remove a route entry in the IP route table associated with this TCP instance. | |
@param[in] Tcb Pointer to the TCP_CB of this TCP instance. | |
@param[in] RouteInfo Pointer to the route information 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 | |
) | |
{ | |
IP_IO_IP_PROTOCOL Ip; | |
Ip = Tcb->IpInfo->Ip; | |
ASSERT (Ip.Ip4!= NULL); | |
return Ip.Ip4->Routes ( | |
Ip.Ip4, | |
RouteInfo->DeleteRoute, | |
RouteInfo->SubnetAddress, | |
RouteInfo->SubnetMask, | |
RouteInfo->GatewayAddress | |
); | |
} | |
/** | |
Get the operational settings of this TCPv4 instance. | |
@param[in] Tcb Pointer to the TCP_CB of this TCP instance. | |
@param[in, out] Mode Pointer to the buffer to store the operational | |
settings. | |
@retval EFI_SUCCESS The mode data was 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); | |
} | |
/** | |
Get the operational settings of this TCPv6 instance. | |
@param[in] Tcb Pointer to the TCP_CB of this TCP instance. | |
@param[in, out] Mode Pointer to the buffer to store the operational | |
settings. | |
@retval EFI_SUCCESS The mode data was read. | |
@retval EFI_NOT_STARTED No configuration data is available because this | |
instance hasn't been started. | |
**/ | |
EFI_STATUS | |
Tcp6GetMode ( | |
IN TCP_CB *Tcb, | |
IN OUT TCP6_MODE_DATA *Mode | |
) | |
{ | |
SOCKET *Sock; | |
EFI_TCP6_CONFIG_DATA *ConfigData; | |
EFI_TCP6_ACCESS_POINT *AccessPoint; | |
EFI_TCP6_OPTION *Option; | |
EFI_IP6_PROTOCOL *Ip; | |
Sock = Tcb->Sk; | |
if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp6ConfigData != NULL)) { | |
return EFI_NOT_STARTED; | |
} | |
if (Mode->Tcp6State != NULL) { | |
*(Mode->Tcp6State) = (EFI_TCP6_CONNECTION_STATE) (Tcb->State); | |
} | |
if (Mode->Tcp6ConfigData != NULL) { | |
ConfigData = Mode->Tcp6ConfigData; | |
AccessPoint = &(ConfigData->AccessPoint); | |
Option = ConfigData->ControlOption; | |
ConfigData->TrafficClass = Tcb->Tos; | |
ConfigData->HopLimit = Tcb->Ttl; | |
AccessPoint->StationPort = NTOHS (Tcb->LocalEnd.Port); | |
AccessPoint->RemotePort = NTOHS (Tcb->RemoteEnd.Port); | |
AccessPoint->ActiveFlag = (BOOLEAN) (Tcb->State != TCP_LISTEN); | |
IP6_COPY_ADDRESS (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip); | |
IP6_COPY_ADDRESS (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip); | |
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.Ip6; | |
ASSERT (Ip != NULL); | |
return Ip->GetModeData (Ip, Mode->Ip6ModeData, Mode->MnpConfigData, Mode->SnpModeData); | |
} | |
/** | |
If TcpAp->StationPort isn't zero, check whether the access point | |
is registered, else generate a random station port for this | |
access point. | |
@param[in] TcpAp Pointer to the access point. | |
@param[in] IpVersion IP_VERSION_4 or IP_VERSION_6 | |
@retval EFI_SUCCESS The check 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 | |
TcpBind ( | |
IN TCP_ACCESS_POINT *TcpAp, | |
IN UINT8 IpVersion | |
) | |
{ | |
BOOLEAN Cycle; | |
EFI_IP_ADDRESS Local; | |
UINT16 *Port; | |
UINT16 *RandomPort; | |
if (IpVersion == IP_VERSION_4) { | |
IP4_COPY_ADDRESS (&Local, &TcpAp->Tcp4Ap.StationAddress); | |
Port = &TcpAp->Tcp4Ap.StationPort; | |
RandomPort = &mTcp4RandomPort; | |
} else { | |
IP6_COPY_ADDRESS (&Local, &TcpAp->Tcp6Ap.StationAddress); | |
Port = &TcpAp->Tcp6Ap.StationPort; | |
RandomPort = &mTcp6RandomPort; | |
} | |
if (0 != *Port) { | |
// | |
// Check if a same endpoing is bound. | |
// | |
if (TcpFindTcbByPeer (&Local, *Port, IpVersion)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
} else { | |
// | |
// generate a random port | |
// | |
Cycle = FALSE; | |
if (TCP_PORT_USER_RESERVED == *RandomPort) { | |
*RandomPort = TCP_PORT_KNOWN; | |
} | |
(*RandomPort)++; | |
while (TcpFindTcbByPeer (&Local, *RandomPort, IpVersion)) { | |
(*RandomPort)++; | |
if (*RandomPort <= TCP_PORT_KNOWN) { | |
if (Cycle) { | |
DEBUG ( | |
(EFI_D_ERROR, | |
"TcpBind: no port can be allocated for this pcb\n") | |
); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
*RandomPort = TCP_PORT_KNOWN + 1; | |
Cycle = TRUE; | |
} | |
} | |
*Port = *RandomPort; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Flush the Tcb add its associated protocols. | |
@param[in, out] Tcb Pointer to the TCP_CB to be flushed. | |
**/ | |
VOID | |
TcpFlushPcb ( | |
IN OUT TCP_CB *Tcb | |
) | |
{ | |
SOCKET *Sock; | |
IpIoConfigIp (Tcb->IpInfo, NULL); | |
Sock = Tcb->Sk; | |
if (SOCK_IS_CONFIGURED (Sock)) { | |
RemoveEntryList (&Tcb->List); | |
if (Sock->DevicePath != NULL) { | |
// | |
// Uninstall the device path protocl. | |
// | |
gBS->UninstallProtocolInterface ( | |
Sock->SockHandle, | |
&gEfiDevicePathProtocolGuid, | |
Sock->DevicePath | |
); | |
FreePool (Sock->DevicePath); | |
Sock->DevicePath = NULL; | |
} | |
} | |
NetbufFreeList (&Tcb->SndQue); | |
NetbufFreeList (&Tcb->RcvQue); | |
Tcb->State = TCP_CLOSED; | |
Tcb->RemoteIpZero = FALSE; | |
} | |
/** | |
Attach a Pcb to the socket. | |
@param[in] Sk Pointer to the socket of this TCP instance. | |
@retval EFI_SUCCESS The operation completed successfully. | |
@retval EFI_OUT_OF_RESOURCES Failed due to resource limits. | |
**/ | |
EFI_STATUS | |
TcpAttachPcb ( | |
IN SOCKET *Sk | |
) | |
{ | |
TCP_CB *Tcb; | |
TCP_PROTO_DATA *ProtoData; | |
IP_IO *IpIo; | |
EFI_STATUS Status; | |
VOID *Ip; | |
EFI_GUID *IpProtocolGuid; | |
if (Sk->IpVersion == IP_VERSION_4) { | |
IpProtocolGuid = &gEfiIp4ProtocolGuid; | |
} else { | |
IpProtocolGuid = &gEfiIp6ProtocolGuid; | |
} | |
Tcb = AllocateZeroPool (sizeof (TCP_CB)); | |
if (Tcb == NULL) { | |
DEBUG ((EFI_D_ERROR, "TcpConfigurePcb: failed to allocate a TCB\n")); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
ProtoData = (TCP_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, | |
IpProtocolGuid, | |
&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[in, out] Sk Pointer to the socket of this TCP instance. | |
**/ | |
VOID | |
TcpDetachPcb ( | |
IN OUT SOCKET *Sk | |
) | |
{ | |
TCP_PROTO_DATA *ProtoData; | |
TCP_CB *Tcb; | |
EFI_GUID *IpProtocolGuid; | |
if (Sk->IpVersion == IP_VERSION_4) { | |
IpProtocolGuid = &gEfiIp4ProtocolGuid; | |
} else { | |
IpProtocolGuid = &gEfiIp6ProtocolGuid; | |
} | |
ProtoData = (TCP_PROTO_DATA *) Sk->ProtoReserved; | |
Tcb = ProtoData->TcpPcb; | |
ASSERT (Tcb != NULL); | |
TcpFlushPcb (Tcb); | |
// | |
// Close the IP protocol. | |
// | |
gBS->CloseProtocol ( | |
Tcb->IpInfo->ChildHandle, | |
IpProtocolGuid, | |
ProtoData->TcpService->IpIo->Image, | |
Sk->SockHandle | |
); | |
IpIoRemoveIp (ProtoData->TcpService->IpIo, Tcb->IpInfo); | |
FreePool (Tcb); | |
ProtoData->TcpPcb = NULL; | |
} | |
/** | |
Configure the Pcb using CfgData. | |
@param[in] Sk Pointer to the socket of this TCP instance. | |
@param[in] CfgData Pointer to the TCP configuration data. | |
@retval EFI_SUCCESS The operation 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 limits. | |
**/ | |
EFI_STATUS | |
TcpConfigurePcb ( | |
IN SOCKET *Sk, | |
IN TCP_CONFIG_DATA *CfgData | |
) | |
{ | |
IP_IO_IP_CONFIG_DATA IpCfgData; | |
EFI_STATUS Status; | |
EFI_TCP4_OPTION *Option; | |
TCP_PROTO_DATA *TcpProto; | |
TCP_CB *Tcb; | |
TCP_ACCESS_POINT *TcpAp; | |
ASSERT ((CfgData != NULL) && (Sk != NULL) && (Sk->SockHandle != NULL)); | |
TcpProto = (TCP_PROTO_DATA *) Sk->ProtoReserved; | |
Tcb = TcpProto->TcpPcb; | |
ASSERT (Tcb != NULL); | |
if (Sk->IpVersion == IP_VERSION_4) { | |
// | |
// Add Ip for send pkt to the peer | |
// | |
CopyMem (&IpCfgData.Ip4CfgData, &mIp4IoDefaultIpConfigData, sizeof (EFI_IP4_CONFIG_DATA)); | |
IpCfgData.Ip4CfgData.DefaultProtocol = EFI_IP_PROTO_TCP; | |
IpCfgData.Ip4CfgData.TypeOfService = CfgData->Tcp4CfgData.TypeOfService; | |
IpCfgData.Ip4CfgData.TimeToLive = CfgData->Tcp4CfgData.TimeToLive; | |
IpCfgData.Ip4CfgData.UseDefaultAddress = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress; | |
IP4_COPY_ADDRESS ( | |
&IpCfgData.Ip4CfgData.SubnetMask, | |
&CfgData->Tcp4CfgData.AccessPoint.SubnetMask | |
); | |
IpCfgData.Ip4CfgData.ReceiveTimeout = (UINT32) (-1); | |
IP4_COPY_ADDRESS ( | |
&IpCfgData.Ip4CfgData.StationAddress, | |
&CfgData->Tcp4CfgData.AccessPoint.StationAddress | |
); | |
} else { | |
ASSERT (Sk->IpVersion == IP_VERSION_6); | |
CopyMem (&IpCfgData.Ip6CfgData, &mIp6IoDefaultIpConfigData, sizeof (EFI_IP6_CONFIG_DATA)); | |
IpCfgData.Ip6CfgData.DefaultProtocol = EFI_IP_PROTO_TCP; | |
IpCfgData.Ip6CfgData.TrafficClass = CfgData->Tcp6CfgData.TrafficClass; | |
IpCfgData.Ip6CfgData.HopLimit = CfgData->Tcp6CfgData.HopLimit; | |
IpCfgData.Ip6CfgData.ReceiveTimeout = (UINT32) (-1); | |
IP6_COPY_ADDRESS ( | |
&IpCfgData.Ip6CfgData.StationAddress, | |
&CfgData->Tcp6CfgData.AccessPoint.StationAddress | |
); | |
IP6_COPY_ADDRESS ( | |
&IpCfgData.Ip6CfgData.DestinationAddress, | |
&CfgData->Tcp6CfgData.AccessPoint.RemoteAddress | |
); | |
} | |
// | |
// Configure the IP instance this Tcb consumes. | |
// | |
Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData); | |
if (EFI_ERROR (Status)) { | |
goto OnExit; | |
} | |
if (Sk->IpVersion == IP_VERSION_4) { | |
// | |
// Get the default address information if the instance is configured to use default address. | |
// | |
IP4_COPY_ADDRESS ( | |
&CfgData->Tcp4CfgData.AccessPoint.StationAddress, | |
&IpCfgData.Ip4CfgData.StationAddress | |
); | |
IP4_COPY_ADDRESS ( | |
&CfgData->Tcp4CfgData.AccessPoint.SubnetMask, | |
&IpCfgData.Ip4CfgData.SubnetMask | |
); | |
TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp4CfgData.AccessPoint; | |
} else { | |
IP6_COPY_ADDRESS ( | |
&CfgData->Tcp6CfgData.AccessPoint.StationAddress, | |
&IpCfgData.Ip6CfgData.StationAddress | |
); | |
TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp6CfgData.AccessPoint; | |
} | |
// | |
// check if we can bind this endpoint in CfgData | |
// | |
Status = TcpBind (TcpAp, Sk->IpVersion); | |
if (EFI_ERROR (Status)) { | |
DEBUG ( | |
(EFI_D_ERROR, | |
"TcpConfigurePcb: 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; | |
if (Sk->IpVersion == IP_VERSION_4) { | |
// | |
// initialize Tcb in the light of CfgData | |
// | |
Tcb->Ttl = CfgData->Tcp4CfgData.TimeToLive; | |
Tcb->Tos = CfgData->Tcp4CfgData.TypeOfService; | |
Tcb->UseDefaultAddr = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress; | |
CopyMem (&Tcb->LocalEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.StationAddress, sizeof (IP4_ADDR)); | |
Tcb->LocalEnd.Port = HTONS (CfgData->Tcp4CfgData.AccessPoint.StationPort); | |
IP4_COPY_ADDRESS (&Tcb->SubnetMask, &CfgData->Tcp4CfgData.AccessPoint.SubnetMask); | |
CopyMem (&Tcb->RemoteEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.RemoteAddress, sizeof (IP4_ADDR)); | |
Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp4CfgData.AccessPoint.RemotePort); | |
Option = CfgData->Tcp4CfgData.ControlOption; | |
} else { | |
Tcb->Ttl = CfgData->Tcp6CfgData.HopLimit; | |
Tcb->Tos = CfgData->Tcp6CfgData.TrafficClass; | |
IP6_COPY_ADDRESS (&Tcb->LocalEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.StationAddress); | |
Tcb->LocalEnd.Port = HTONS (CfgData->Tcp6CfgData.AccessPoint.StationPort); | |
IP6_COPY_ADDRESS (&Tcb->RemoteEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.RemoteAddress); | |
Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp6CfgData.AccessPoint.RemotePort); | |
// | |
// Type EFI_TCP4_OPTION and EFI_TCP6_OPTION are the same. | |
// | |
Option = (EFI_TCP4_OPTION *) CfgData->Tcp6CfgData.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 (((Sk->IpVersion == IP_VERSION_4) && !CfgData->Tcp4CfgData.AccessPoint.ActiveFlag) || | |
((Sk->IpVersion == IP_VERSION_6) && !CfgData->Tcp6CfgData.AccessPoint.ActiveFlag) | |
) { | |
TcpSetState (Tcb, TCP_LISTEN); | |
SockSetState (Sk, SO_LISTENING); | |
Sk->ConfigureState = SO_CONFIGURED_PASSIVE; | |
} else { | |
Sk->ConfigureState = SO_CONFIGURED_ACTIVE; | |
} | |
if (Sk->IpVersion == IP_VERSION_6) { | |
Tcb->Tick = TCP6_REFRESH_NEIGHBOR_TICK; | |
if (NetIp6IsUnspecifiedAddr (&Tcb->RemoteEnd.Ip.v6)) { | |
Tcb->RemoteIpZero = TRUE; | |
} | |
} | |
TcpInsertTcb (Tcb); | |
OnExit: | |
return Status; | |
} | |
/** | |
The procotol handler provided to the socket layer, which is used to | |
dispatch the socket level requests by calling the corresponding | |
TCP layer functions. | |
@param[in] Sock Pointer to the socket of this TCP instance. | |
@param[in] Request The code of this operation request. | |
@param[in] Data Pointer to the operation specific data passed in | |
together with the operation request. This is an | |
optional parameter that may be NULL. | |
@retval EFI_SUCCESS The socket request completed successfully. | |
@retval other The error status returned by the corresponding TCP | |
layer function. | |
**/ | |
EFI_STATUS | |
TcpDispatcher ( | |
IN SOCKET *Sock, | |
IN UINT8 Request, | |
IN VOID *Data OPTIONAL | |
) | |
{ | |
TCP_CB *Tcb; | |
TCP_PROTO_DATA *ProtoData; | |
ProtoData = (TCP_PROTO_DATA *) Sock->ProtoReserved; | |
Tcb = ProtoData->TcpPcb; | |
switch (Request) { | |
case SOCK_POLL: | |
if (Tcb->Sk->IpVersion == IP_VERSION_4) { | |
ProtoData->TcpService->IpIo->Ip.Ip4->Poll (ProtoData->TcpService->IpIo->Ip.Ip4); | |
} else { | |
ProtoData->TcpService->IpIo->Ip.Ip6->Poll (ProtoData->TcpService->IpIo->Ip.Ip6); | |
} | |
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 TcpAttachPcb (Sock); | |
break; | |
case SOCK_FLUSH: | |
TcpFlushPcb (Tcb); | |
break; | |
case SOCK_DETACH: | |
TcpDetachPcb (Sock); | |
break; | |
case SOCK_CONFIGURE: | |
return TcpConfigurePcb ( | |
Sock, | |
(TCP_CONFIG_DATA *) Data | |
); | |
break; | |
case SOCK_MODE: | |
ASSERT ((Data != NULL) && (Tcb != NULL)); | |
if (Tcb->Sk->IpVersion == IP_VERSION_4) { | |
return Tcp4GetMode (Tcb, (TCP4_MODE_DATA *) Data); | |
} else { | |
return Tcp6GetMode (Tcb, (TCP6_MODE_DATA *) Data); | |
} | |
break; | |
case SOCK_ROUTE: | |
ASSERT ((Data != NULL) && (Tcb != NULL) && (Tcb->Sk->IpVersion == IP_VERSION_4)); | |
return Tcp4Route (Tcb, (TCP4_ROUTE_INFO *) Data); | |
default: | |
return EFI_UNSUPPORTED; | |
} | |
return EFI_SUCCESS; | |
} |