Add NetworkPkg (P.UDK2010.UP3.Network.P1)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10986 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
861
NetworkPkg/TcpDxe/TcpDispatcher.c
Normal file
861
NetworkPkg/TcpDxe/TcpDispatcher.c
Normal file
@@ -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;
|
||||
}
|
Reference in New Issue
Block a user