summaryrefslogtreecommitdiff
path: root/NetworkPkg/TcpDxe/TcpDispatcher.c
diff options
context:
space:
mode:
Diffstat (limited to 'NetworkPkg/TcpDxe/TcpDispatcher.c')
-rw-r--r--NetworkPkg/TcpDxe/TcpDispatcher.c861
1 files changed, 861 insertions, 0 deletions
diff --git a/NetworkPkg/TcpDxe/TcpDispatcher.c b/NetworkPkg/TcpDxe/TcpDispatcher.c
new file mode 100644
index 0000000000..eaa75a4ec4
--- /dev/null
+++ b/NetworkPkg/TcpDxe/TcpDispatcher.c
@@ -0,0 +1,861 @@
+/** @file
+ The implementation of a dispatch routine for processing TCP requests.
+
+ Copyright (c) 2009 - 2010, 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;
+
+ CopyMem (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
+
+ AccessPoint->SubnetMask = Tcb->SubnetMask;
+ AccessPoint->StationPort = NTOHS (Tcb->LocalEnd.Port);
+
+ CopyMem (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
+
+ 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) {
+ CopyMem (&Local, &TcpAp->Tcp4Ap.StationAddress, sizeof (EFI_IPv4_ADDRESS));
+ 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;
+ TCP_PROTO_DATA *TcpProto;
+
+ IpIoConfigIp (Tcb->IpInfo, NULL);
+
+ Sock = Tcb->Sk;
+ TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved;
+
+ 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;
+ }
+
+ TcpSetVariableData (TcpProto->TcpService);
+ }
+
+ NetbufFreeList (&Tcb->SndQue);
+ NetbufFreeList (&Tcb->RcvQue);
+ Tcb->State = TCP_CLOSED;
+}
+
+/**
+ 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;
+
+ 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;
+ }
+
+ 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;
+
+ ProtoData = (TCP_PROTO_DATA *) Sk->ProtoReserved;
+ Tcb = ProtoData->TcpPcb;
+
+ ASSERT (Tcb != NULL);
+
+ TcpFlushPcb (Tcb);
+
+ 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;
+ IpCfgData.Ip4CfgData.SubnetMask = CfgData->Tcp4CfgData.AccessPoint.SubnetMask;
+ IpCfgData.Ip4CfgData.ReceiveTimeout = (UINT32) (-1);
+ CopyMem (
+ &IpCfgData.Ip4CfgData.StationAddress,
+ &CfgData->Tcp4CfgData.AccessPoint.StationAddress,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+
+ } 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.
+ //
+ CfgData->Tcp4CfgData.AccessPoint.StationAddress = IpCfgData.Ip4CfgData.StationAddress;
+ 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);
+ 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;
+ }
+
+ 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;
+}