mirror of https://github.com/acidanthera/audk.git
914 lines
27 KiB
C
914 lines
27 KiB
C
/** @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;
|
|
}
|