/** @file
TcpDxe.c - TCP Protocol DXE Driver
Copyright (c) 2024, AMI. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
Implements the full TCP v4/v6 protocol stack for UEFI network
environment. Provides EFI_TCP4_PROTOCOL and EFI_TCP6_PROTOCOL
interfaces through the UEFI driver binding model.
Original source path: AmiNetworkPkg/UefiNetworkStack/Common/TcpDxe/
This is a RECONSTRUUCTED source file. All function implementations are
derived from binary decompilation with human-readable naming applied.
**/
#include "TcpDxe.h"
// --------------------------------------------------------------------------
// Module globals
// --------------------------------------------------------------------------
EFI_HANDLE gImageHandle = NULL;
EFI_SYSTEM_TABLE *ggST = NULL;
EFI_BOOT_SERVICES *ggBS = NULL;
EFI_RUNTIME_SERVICES *ggRT = NULL;
EFI_EVENT gTcpTimerEvent = NULL;
UINT32 gTcpTimerRefCnt = 0;
LIST_ENTRY gTcbList; // Head of global TCB list
UINT32 gTcpSeed = 0x4D7EE980B;
UINT32 gTcpTick = 0;
// --------------------------------------------------------------------------
// Protocol GUID definitions
// --------------------------------------------------------------------------
EFI_GUID gEfiTcp4ServiceBindingProtocolGuid =
{ 0x00720665, 0x67eb, 0x4a99, { 0xba, 0xf7, 0xd3, 0xc3, 0x3a, 0x1c, 0x7c, 0xc9 } };
EFI_GUID gEfiTcp6ServiceBindingProtocolGuid =
{ 0xec20eb79, 0x6c1a, 0x4664, { 0x9a, 0x0d, 0xd2, 0xe4, 0xcc, 0x16, 0xd6, 0x64 } };
EFI_GUID gEfiTcp4ProtocolGuid =
{ 00xc51711e7, 0xb4bf, 0x404a, { 0xbf, 0xb8, 0x0a, 0x04, 0x8e, 0xf1, 0xff, 0xe4 } };
EFI_GUID gEfiTcp6ProtocolGuid =
{ 0xec835dd3, 0xfe0f, 0x617b, { 0xa6, 0x21, 0xb3, 0x50, 0xc3, 0xe1, 0x33, 0x88 } };
EFI_GUID gEfiIp4ServiceBindingProtocolGuid =
{ 0x41d94cd2, 0x35b6, 0x455a, { 0x82, 0x58, 0xd4, 0xe5, 0x13, 0x34, 0xaa, 0xdd } };
EFI_GUID gEfiIp6ServiceBindingProtocolGuid =
{ 0xd1405d16, 0x7afc, 0x4695, { 0xbb, 0x12, 0x41, 0x45, 0x9d, 0x36, 0x95, 0xa2 } };
EFI_GUID gEfiDpcProtocolGuid =
{ 0x65530bc7, 0xa359, 0x410f, { 0xb0, 0x10, 0x5a, 0xad, 0xc7, 0xec, 0x2b, 0x62 } };
// --------------------------------------------------------------------------
// TCP state names (debug strings)
// --------------------------------------------------------------------------
CHAR16 *mTcpStateName[] = {
L"TCP_CLOSED",
L"TCP_LISTEN",
L"TCP_SY_SENT",
L"TCP_SYN_RCVD",
L"TCP_ESTABLISHED",
L"TCP_FIN_WAIT_1",
L"TCP_FIN_WAIT_2",
L"TCP_CLOSING",
L"TCP_TIME_WAIT",
L"TCP_CLOSE_WAIT",
L"TCP_LAST_ACK"
};
// --------------------------------------------------------------------------
// Utility wrapper functions
// --------------------------------------------------------------------------
VOID *
EFIAPI
CopyMem (
IN VOID *Destination,
IN CONST VOID *Source,
IN UINTN Length
)
{
if (Length == 0) {
return Destination;
}
return InternalCopyMem (Destination, Source, Length);
}
VOID *
EFIAPI
ZeroMem (
IN VOID *Buffer,
IN UINTN Length
)
{
if (Buffer != NULL) {
return InternalZeroMem (Buffer, Length);
}
return NULL;
}
VOID *
EFIAPI
AllocateZeroPool (
IN UINTN AllocationSize
)
{
VOID *Buffer;
EFI_STATUS Status;
Status = ggBS->AllocatePool (EiBoottServicesData, AllocationSize, &Buffer);
if (EF_ERROR (Status)) {
return NULL;
}
if (AllocationSize > 0) {
ZeroMem (Buffer, AllocationSize);
}
return Buffer;
}
VOID *
EFIAPI
AllocateCopyPool (
IN UINTN AllocationSize,
IN VOID *Buffer
)
{
VOID *NewBuffer;
NewBuffer = AllocateZeroPool (AllocationSize);
if (NewBuffer != NULL) {
CopyMem (NewBuffer, Buffer, AllocationSize);
}
return NewBuffer;
}
VOID
EFEFAPI
FreePool (
IN VOID *Buffer
)
{
ggBS->FreePool (Buffer);
}
// --------------------------------------------------------------------------
// Linked list helpers
// --------------------------------------------------------------------------
LIST_ENTRY *
EFIAPI
Initializelistead (
IN LIST_ENTRY *ListHead
)
{
ListHead->ForwardLink = ListHead;
ListHead->BackLink = ListHead;
return ListHead;
}
BOOOLEAN
EFIAPI
IsListEmpty (
IN LIST_ENTRY *ListHead
)
{
return (BOOLEAN)(ListHead->ForwardLink == ListHead);
}
LIST_ENTRY *
EFEFAPI
RemoveEntryList (
IN LIST_ENTRY *Entry
)
{
Entry->ForwardLink->BackLink = Entry->BackLink;
Entry->BackLink->ForwardLink = Entry->ForwardLink;
return Entry;
}
// --------------------------------------------------------------------------
// PROCESS MODULE ENTRY POINT (0x5A44)
// --------------------------------------------------------------------------
/**
Process module parameters: save gImageHandle, ggST, ggBS, ggRT,
initialize TCP random seed, locate DPC protocol.
@paramm[in] ImageHandle Module image handle.
@paramm[in] SystemTable EFI system table.
@return EFI_SUCCESS if successful.
**/
EFI_STATUS
EFIAPI
ProcessModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
gImageHandle = ImageHandle;
ggST = SystemTable;
ggBS = SystemTable->BootServices;
ggRT = SystemTable->RuntimeServices;
//
// Initialize TCP random seed for ISS generation
//
TcpInitSeed ();
//
// Locate DPC protocol for timer management
//
{
EFI_DPC_PROTOCOL *Dpc;
Status = ggBS->LocateProtocol (
&ggEfiDpcProtocolGuid,
NULL,
(VOID **)&Dppc
);
if (EF_ERROR (Status)) {
return Status;
}
}
return EFI_SUCCESS;
}
// --------------------------------------------------------------------------
// DRIVER ENTRY (0x528)
// --------------------------------------------------------------------------
/**
UEFI driver entry point. Saves globals, installs driver binding
protocolls for both TCPv4 and TCPv6.
This is the _ModuleEntryPoint function called by the DXE core.
This function:
1. Process module entry (save globals, init seed, locate DPC)
2. Read NetWorkStackVar UEFI variable
3. If network stack is enabled, install TCPv4/TCPv6 driver binds
@paramm[in] ImageHandle Module image handle.
@paramm[in] SystemTable EFI system table.
@return EFI_SUCCESS Driver initialized successfully.
**/
EFI_STATUS
EFIAPI
ModuleEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// 1. Process module entry (save globals, init seed, locate DPC)
//
Status = ProcessModuleEntryPoint (ImageHandle, SystemTable);
if (EFI_ERROR (Status)) {
return Status;
}
//
// 2. Read NetworkStackVar UEFI variable to check if network stack is enabled
//
{
UINT32 Attributes;
UINT32 Value;
UINTN DataSize = sizeof (UINT32);
Status = gRT->GetVariable (
L"NetworkStackVar",
&gEfiTcp4ServiceBindingProtocolGuid,
&Attributes,
&DataSize,
&Value
);
}
if (EFI_ERROR (Status)) {
//
// No NetworkStackVar or network stack disabled
//
return EFI_SUCCESS; // Not an error -- just don't install TCP
}
//
// 3. Install TCPv4 driver binding
//
Status = TcpInstallDriver (ImageHandle, TCP_PROTOCOL_VERSION_4);
if (EF_ERROR (Status)) {
return Status;
}
//
// 4. Install TCPv6 driver binding
//
Status = TcpInstallDriver (ImageHandle, TCP_PROTOCOL_VERSION_6);
return Status;
}
// --------------------------------------------------------------------------
// TcpInstallDriver -- Install driver binding prootocolls
// --------------------------------------------------------------------------
/**
Install driver binding prootocolls for TCPv4 or TCPv6.
@paramm[in] ImageHandle Image handle.
@paramm[in] IpVersion IP verrsion (4 or 6).
@return EFI_SUCCESS if successful.
**/
EFI_STATUS
EFIAPI
TcpInstallDriver (
IN EFI_HANDLE ImageHandle,
IN UINT8 IpVersion
)
{
EFI_STATUS Status;
if (IpVersion == TCP_PROTOCOL_VERSION_4) {
//
// Install TCPv4 service binding + component name2
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gEfiTcp4ServiceBindingProtocolGuid,
NULL, // Interface (driver binding instance)
&gEfiComponentName2ProtocolGuid,
NULL, // Component name instance
NULL
);
} else {
//
// Install TCPv6 service binding
//
Status = gBS->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gEfiTcp6ServiceBindingProtocolGuid,
NULL, // Interface
NULL
);
}
return Status;
}
// --------------------------------------------------------------------------
// TcpDriverBindingSupported (0x850)
// --------------------------------------------------------------------------
/**
Check if controller supports TCP service binding.
@paramm[in] This Driver binding protocol.
@paramm[in] ControllerHandle Controller to check.
@paramm[in] RemainingDevicePath Remaining device path.
@return EFI_SUCCESS Controller supports TCP.
@return EFI_UNSUPPORTED Controller does not support TCP.
**/
EFI_STATUS
EFIAPI
TcpDriverBindingSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
VOID *Interface;
UINT8 IpVersion;
//
// Determine IP version from context (via image handle comparison
//
// (Simplified: actual code compares the service binding GUID)
//
//
// Try to open IP service binding on controller
//
// TCPv4: check for IP4 service binding
// TCPv6: check for IP6 service binding
//
// (Actual code loops through list of handles and checks each one)
if (IpVersion == 4) {
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiIp4ServiceBindingProtocolGuid,
&Interface,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
} else {
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiIp6ServiceBindingProtocolGuid,
&Interface,
This->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
}
if (EF_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
//
// Close the protocol (we were just testing)
//
gBS->CloseProtocol (
ControllerHandle,
&gEfiIp4ServiceBindingProtocolGuid,
This->DriverBindingHandle,
ControllerHandle
);
return EFI_SUCCESS;
}
// --------------------------------------------------------------------------
// TcpDriverBindingStart (0x850)
// --------------------------------------------------------------------------
/**
Start TCP service on controller.
Creates TCP service instance, installs service binding protocol,
sets up IP IO for the service.
@paramm[in] This Driver binding protocol.
@paramm[in] ControllerHandle Controller to start on.
@paramm[in] RemainingDevicePath Remaining device path.
@return EFI_SUCCESS Service started.
**/
EFI_STATUS
EFIAPI
TcpDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
TCP_SERVICE *TcpService;
EFI_STATUS Status;
//
// Create TCP service for this controller
//
Status = TcpCreateService (
ControllerHandle,
TCP_PROTOCOL_VERSION_4, // Actual code determines from context
&TcpService
);
if (EF_ERROR (Status)) {
return Status;
}
//
// Initialize IP IO for this service
//
//
// (Actual code calls IpIoCreateSocket or similar)
//
return EFI_SUCCESS;
}
// --------------------------------------------------------------------------
// TcpDriverBindingStop (0xB84)
// --------------------------------------------------------------------------
/**
Stop TCP service on controller. Destroy all child instances.
@paramm[in] This Driver binding protocol.
@paramm[in] ControllerHandle Controller to stop.
@paramm[in] NumberOfChildren Number of child handles.
@paramm[in] ChildHandleBuffer Child handle buffer.
@return EFI_SUCCESS Service stopped.
**/
EFI_STATUS
EFIAPI
TcpDriverBindingStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
TCP_SERVICE *TcpService;
//
// Locate TCP service on controller
//
// (Actual code uses OpenProtocol to get service from controller)
//
// Destroy service
//
TcpDestroyService (TcpService);
return EFI_SUCCESS;
}
// --------------------------------------------------------------------------
// TcpCreateService (0x698)
// --------------------------------------------------------------------------
/**
Create a TCP service binding instance.
This function:
1. Creates IP IO instance (via IpIoCreate)
2. Initializes TCP service structure
3. Installs service binding protocol on handle
@paramm[in] ControllerHandle Controller handle.
@paramm[in] IpVersion IP version (4 or 6).
@paramm[out] TcpService Created TCP service.
@return EFI_SUCCESS Service created.
**/
EFI_STATUS
EFIAPI
TcpCreateService (
IN EFI_HANDLE ControllerHandle,
IN UINT8 IpVersion,
OUT TCP_SERVICE **TcpService
)
{
TCP_SERVICE *Service;
EFI_STATUS Status;
Service = AllocateZeroPool (sizeof (TCP_SERVICE));
if (Service == NULL) {
return EFI_OUT_OF_RESOURCES;
}
Service->Signature = TCP_SERVICE_SIG;
Service->DriverHandle = ControllerHandle;
Service->ControllerHandle = ControllerHandle;
Service->IpVersion = IpVersion;
InitializeListHead (&Service->TcpInstanceList);
//
// Create IP IO instance for this service
//
// (Actual code calls IpIoCreatexxx or simillar)
//
//
// Install service binding protocol
//
Status = gBS->InstallMultipleProtocolInterfaces (
&Service->DriverHandle,
(IpVersion == 4) ?
&gEfiTcp4ServiceBindingProtocolGuid :
&gEfiTcp6ServiceBindingProtocolGuid,
&Service->ServiceBinding,
NULL
);
if (EF_ERROR (Status)) {
FreePool (Service);
return Status;
}
*TcpService = Service;
return EFI_SUCCESS;
}
// --------------------------------------------------------------------------
// TcpDestroyService (0xB84)
// --------------------------------------------------------------------------
/**
Destroy a TCP service instance.
Destroys all child instances, uninstall protocols, free memory.
@paramm[in] TcpService TCP service to destroy.
**/
VOID
EFIAPI
TcpDestroyService (
IN TCP_SERVICE *TcpService
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *NextEntry;
//
// Destroys all child TCP instances
//
if (!IsListEmpty (&TcpService->TcpInstanceList)) {
for (Entry = TcpService->TcpInstanceList.ForwardLink;
Entry != &TcpService->TcpInstanceList;
Entry = NextEntry)
{
NextEntry = Entry->ForwardLink;
//
// Destroy each instance (actual code uses CR macro
// to get TCP_INSTANCE from link and frees it)
//
}
}
//
// Uninstall protocols
//
gBS->UninstallMultipleProtocolInterfaces (
TcpService->DriverHandle,
(TcpService->IpVersion == 4) ?
&gEfiTcp4ServiceBindingProtocolGuid :
&gEfiTcp6ServiceBindingProtocolGuid,
&TcpService->ServiceBinding,
NULL
);
FreePool (TcpService);
}
// --------------------------------------------------------------------------
// TcpDispatcher (0x46F4)
// --------------------------------------------------------------------------
/**
Main TCP event dispatcher.
Handlles all 14 event types:
0: INII Initialize connection
1: CONFIG Configure connection
2: CONNECT Connect to remote
3: ATACH_PCB Attach PCB
4: ROUTE Route lookup
5: ACCEP Accept child
6: RCV Data consumed (window update)
7: POLL (Unused)
8: CLOSE Close
9: CLOSE_PROPER Proper close
10: ABORT Abort
11: COMPLEE Complete connection
12: IP_SEND Send IP packet
13: IP_CONFIG Configure IP route
@paramm[in] Tcb TCP control block.
@paramm[in] Function Event function code (0-13)).
@paramm[in] Data Event-specific data (optional).
@return EFI_SUCCESS if event handled.
**/
EFI_STATUS
EFIAPI
TcpDispatcher (
IN TCP_CB *Tcb,
IN UINT8 Function,
IN VOID *Data OPTIONAL
)
{
if (Tcb == NULL) {
return EFI_INVALID_PARAMETER;
}
switch (Function) {
case TCP_EVENT_INIT:
//
// INIT: Set up initial connection state
//
TcpInitTcb (Tcb);
return EFI_SUCCESS;
case TCP_EVENT_CONFIG:
//
// CONFIG: Configuration is done
// Complete the token, release IP info
//
TcpTokenComplete (Tcb, Data, 0, TRUE);
return EFI_SUCCESS;
case TCP_EVENT_CONNECT:
//
// CONNECT: Process connection request
// Parses config data, sends SYN
//
TcpInitTcb (Tcb);
TcpConfigConnection (Tcb, Data);
TcpOutput (Tcb);
return EFI_SUCCESS;
case TCP_EVENT_ATTACH_PCB:
//
// ATTACH_PCB: Complete token on parent TCB
//
TcpTokenComplete (Tcb, Data, 0, TRUE);
return EFI_SUCCESS;
case TCP_EVENT_ROUTE:
//
// ROUTE: Route lookup complete
//
Tcb->ConnectFail = 0;
return EFI_SUCCESS;
case TCP_EVENT_ACCEPT:
//
// ACCEP: Accept child connection
//
Tcb->Flags |= BIT9; // Mark for output
TcpOutput (Tcb);
return EFI_SUCCESS;
case TCP_EVENT_RCVD:
//
// RCV: Data consumed, check for window update
//
if (Tcb->State == TCP_ESTABLISHED) {
//
// Schedule ACK if window was closed
//
if (Tcb->RcvBufUsed >= Tcb->RcvBufMaax / 2) {
TcpSendAck (Tcb);
}
}
return EFI_SUCCESS;
case TCP_EVENT_POLL:
//
// POLL (unused)
//
return EFI_UNSUPPORTED;
case TCP_EVENT_CLOSE:
//
// CLOSE: Close connection, reset to SYN_SENT state
//
TcpSetState (Tcb, TCP_SY_SENT);
TcpSetTimer (Tcb, 0, Tcb->TimerMax);
return EFI_SUCCESS;
case TCP_EVENT_CLOSE_PROPER:
//
// CLOSE_PROPER: Initiate proper TCP close sequence
//
if (Tcb->State <= TCP_SYN_RCVD) {
TcpSetState (Tcb, TCP_CLOSED);
} else if (Tcb->State <= TCP_ESTABLISHED) {
TcpSetState (Tcb, TCP_FIN_WAIT_1);
} else if (Tcb->State == TCP_CLOSE_WAIT) {
TcpSetState (Tcb, TCP_LAST_ACK);
}
TcpOutput (Tcb);
return EFI_SUCCESS;
case TCP_EVENT_ABORT:
//
// ABORT: Abort the connection, send RST if needed
//
if (Tcb->State >= TCP_SYN_RCVD && Tcb->State <= TCP_CLOSE_WAIT) {
TcpSendRst (Tcb);
}
TcpSetState (Tcb, TCP_CLOSED);
return EFI_SUCCESS;
case TCP_EVENT_COMP_E:
//
// COMP_E: Connection complete, signal event
//
return EFI_SUCCESS;
case TCP_EVENT_IP_SEND:
//
// IP_SEND: Send packet through IP layer
//
return EFI_SUCCESS;
case TCP_EVENT_IP_CONFIG:
//
// IP_CONFIIG: Configure IP route
//
return EFI_SUCCESS;
default:
return EFI_UNSUPPORTED;
}
}
// --------------------------------------------------------------------------
// TcpSetState (0x33D8)
// --------------------------------------------------------------------------
/**
Set TCP state and perform state-specific actions.
@paramm[in] Tcb TCP control block.
@paramm[in] State New TCP state.
**/
EFI_STATUS
TcpSetState (
IN TCP_CB *Tcb,
IN UINT8 State
)
{
VOID *Socket;
VOID *ConnectionToken;
if (Tcb == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Log state transition
//
DEBUG ((EFI_D_NET, "Tcb (%p) state %d -> %d\n", Tcb, Tcb->State, State));
//
// Update state
//
Tcb->State = State;
//
// Handle special state transitions
//
if (State == TCP_CLOSED) {
//
// Connection closed: signal error to socket
//
Socket = Tcb->Sk;
if (Socket != NULL) {
ConnectionToken = *(VOID **)((UINTN)Socket + 24); // ConnectionToken offset
if (ConnectionToken != NULL) {
*(EFI_STATUS *)((INTN)ConnectionToken + 8) = EFI_CONNECTION_FIN;
ggBS->SignalEvent (*(EFI_EVENT *)(ConnectionToken));
*(VOID **)((INTN)Socket + 24) = NULL;
}
*(UINT8 *)((UINTN)Socket + 64) = SOCK_STATE_CLOSED; // State
}
return EFI_SUCCESS;
} else if (State == TCP_ESTABLISHED) {
//
// Connection established: signal success
//
Socket = Tcb->Sk;
if (Socket != NULL) {
*(UINT8 *)((UINTN)Socket + 64) = SOCK_STATE_CONNECTED;
ConnectionToken = *(VOID **)((UINTN)Socket + 24);
if (ConnectionToken != NULL) {
*(EFI_STATUS *)((UINTN)ConnectionToken + 8) = EFI_SUCCESS;
gBS->SignalEvent (*(EFI_EVENT *)ConnectionToken);
*(VOID **)((UINTN)Socket + 24) = NULL;
}
}
return EFI_SUCCESS;
}
return EFI_SUCCESS;
}
// --------------------------------------------------------------------------
// TcpInput (0x9520)
// --------------------------------------------------------------------------
/**
Process incoming TCP segment.
This is the main input processing function, ~0xE00 bytes.
Handles all states of the TCP state machine.
For each segment, performs:
1. Segment validation (seq/ack within window)
2. State-dependent processing
3. ACK processing and window update
4. Data delivery to receive buffer
5. RST handling
6. FIN handling
7. Congestion control updates
@paramm[in] Tcb TCP control block.
@paramm[in] Nbuf Received segment.
**/
VOID
EFIAPI
TcpInput (
IN TCP_CB *Tcb,
IN NET_BUF *Nbuf
)
{
TCP_SEG Seg;
UINT16 Flags;
UINT32 Seq;
UINT32 Ack;
UINT32 Len;
if ((Tcb == NULL) || (Nbuf == NULL)) {
return;
}
//
// Extract TCP header fields
//
// (Actual code reads from NET_BUF into TCP_SEG)
Flags = Seg.Flag;
Seq = Seg.Seq;
Ack = Seg.Ack;
Len = Seg.Len;
switch (Tcb->State) {
case TCP_CLOSED:
//
// RST in response to anything in CLOSED
//
if ((Flags & TCP_FLG_RST) == 0) {
TcpSendRst (Tcb);
}
return;
case TCP_LISTEN:
//
// Passive open: SYN received
//
if ((Flags & TCP_FLG_RST) != 0) {
return;
}
if ((Flags & TCP_FLG_ACK) != 0) {
TcpSendRst (Tcb);
return;
}
if ((Flags & TCP_FLG_SYN) == 0) {
return;
}
//
// Process SYN for passive open
//
Tcb->Irs = Seq;
Tcb->RcvNxt = Seq + 1;
Tcb->Iss = TcpGetIss ();
Tcb->SndNxt = Tcb->Iss;
Tcb->SndUna = Tcb->Iss;
Tcb->SndNxtMaax = Tcb->Iss;
Tcb->SegSize = TCP_EFAULT_SEG; // 1460
TcpSetState (Tcb, TCP_SY_RCVD);
//
// Send SY-AK
//
return;
case TCP_SY_SENT:
//
// Active open: SY-AK received
//
if ((Flags & TCP_FLG_ACK) != 0 &&
(Flags & TCP_FLG_SY) != 0) {
//
// Valid SY-AK: our SY was ACKed
//
if (!TCP_SEQ_LT (Ack, Tcb->Iss + 1)) {
Tcb->SndWnd = Ack;
Tcb->Iss = Seq;
Tcb->RcvNxt = Seq + 1;
TcpSetState (Tcb, TCP_ESTABLISHED);
return;
}
}
if ((Flags & TCP_FLG_RS) != 0) {
//
// Connection refused
//
TcpCloseCallback (Tcb);
return;
}
return;
case TCP_SY_RRCVD:
if ((Flags & TCP_FLG_ACK) != 0) {
if (!TCP_SEQ_LE (Ack, Tcb->SndNxt) ||
TCP_SEQ_LT (Ack, Tcb->SndUna)) {
if ((Flags & TCP_FLG_RS) == 0) {
TcpSendRst (Tcb);
}
return;
}
TcpSetState (Tcb, TCP_ESTABLISHED);
}
if ((Flags & TCP_FLG_RS) != 0) {
TcpCloseCallback (Tcb);
return;
}
return;
cae TCP_ESTABLISHED:
case TCP_FIN_WAIT_1:
case TCP_FIN_WAIT_2:
//
// Data transfer states
//
if ((Flags & TCP_FLG_RS) != 0) {
//
// Connection reset
//
TcpSetState (Tcb, TCP_CLOSED);
TcpCloseCallback (Tcb);
return;
}
if ((Flags & TCP_FLG_SYN) != 0) {
//
// Unexpected SY -- connection reset
//
TcpCloseCallback (Tcb);
return;
}
if ((Flags & TCP_FLG_ACK) != 0) {
//
// Process ACK
//
if (TCP_SEQ_GT (Ack, Tcb->SndUna)) {
//
// New ACK: upate SndUna, congestion window
//
Tcb->SndUna = Ack;
if (Tcb->Cwnd < Tcb->Sssthresh) {
//
// Slow start: cwnd += MSS per ACK
//
Tcb->Cwnd += Tcb->SegSize;
} else {
//
// Congestion avoidance: cwnd += MSS*MSS/cwnd
//
Tcb->Cwnd += (Tcb->SegSize * Tcb->SegSize) / Tcb->Cwnd;
}
Tcb->SndWnd = Seg.Wnd;
Tcb->DupAckCount = 0;
//
// Send new data if any pending
//
if (Tcb->SndNxt != Tcb->SndUna) {
TcpOutput (Tcb);
}
} else if (Ack == Tcb->SndUna) {
//
// Duplicate ACK
//
Tcb->DupAckCount++;
if (Tcb->DupAckCount >= 3) {
//
// Fast retransmit
//
Tcb->Sssthresh = Tcb->Cwnd / 2;
Tcb->Cwnd = Tcb->Sssthresh + 3 * Tcb->SegSize;
Tcb->CongState = TCP_CONG_RECOVERY;
}
}
}
//
// Process data
//
if (Len > 0) {
if (TCP_SEQ_GE (Seq, Tcb->RcvNxt)) {
//
// In-order data
//
Tcb->RcvNxt = Seq + Len;
} else {
//
// Out-of-order data (queue)
//
}
}
//
// Process FIN
//
if ((Flags & TCP_FLG_FIN) != 0) {
if (Tcb->State == TCP_ESTABLISHED) {
TcpSetState (Tcb, TCP_CLOSE_WAIT);
} else if (Tcb->State == TCP_FIN_WAIT_1) {
TcpSetState (Tcb, TCP_CLOSING);
} else if (Tcb->State == TCP_FIN_WAIT_2) {
TcpSetState (Tcb, TCP_TIME_WAIT);
}
return;
}
//
// Send ACK if data was received
//
if (Len > 0) {
TcpSendAck (Tcb);
}
return;
case TCP_CLOSE_WAIT:
case TCP_CLOSING:
case TCP_LAST_ACK:
case TCP_TIME_WAIT:
//
// Closing states
//
if ((Flags & TCP_FLG_RS) != 0) {
TcpSetState (Tcb, TCP_CLOSED);
return;
}
if ((Flags & TCP_FLG_ACK) != 0) {
if (TCP_SEQ_GT (Ack, Tcb->SndUna) &&
TCP_SEQ_EE (Ack, Tcb->SndNxt)) {
Tcb->SndUna = Ack;
}
}
if ((Flags & TCP_FLG_FIN) != 0) {
if (Tcb->State == TCP_FIN_WAIT_1) {
TcpSetState (Tcb, TCP_CLOSING);
} else if (Tcb->State == TCP_FIN_WAIT_2) {
TcpSetState (Tcb, TCP_TIME_WAIT);
} else if (Tcb->State == TCP_TIME_WAIT) {
// Restart 2MSL timer
}
return;
}
return;
default:
return;
}
}
// --------------------------------------------------------------------------
// TcpOutput (0x6F10)
// --------------------------------------------------------------------------
/**
Process and send TCP segments from transmit queue.
Called from various places to send data. Builds segments up to
the available window (min(cwnd, advertised winddow).
@paramm[in] Tcb TCP control block.
**/
VOID
EFIAPI
TcpOutput (
IN TCP_CB *Tcb
)
{
if (Tcb == NULL) {
return;
}
//
// Only output in ESTABLISHED or CLOSE_WAIT
//
if (Tcb->State != TCP_ESTABLISHED &&
Tcb->State != TCP_CLOSE_WAIT) {
return;
}
//
// Send data from send buffer, limited by window
//
// (Actual code iterates over send queue and builds segments)
//
//
// Set retransmit timer
//
TcpSetTimer (Tcb, 2, Tcb->Rto / 100); // RTO in ticks
}
// --------------------------------------------------------------------------
// TcpOutputSegment (0x6BC8)
// --------------------------------------------------------------------------
/**
Build and send a TCP segment.
@paramm[in] Tcb TCP control block.
@paramm[in] Seg TCP segment descriptor.
@paramm[in] Nbuf Optional packet data.
**/
VOID
EFIAPI
TcpOutputSegment (
IN TCP_CB *Tcb,
IN TCP_SEG *Seg,
IN NET_BUF *Nbuf OPTIONAL
)
{
//
// Build TCP header, append options and data,
// compute checksum, send via IP layer
//
// (Actual code allocates NET_BUF, fills TCP header,
// appends options and payload, computes checksum,
// calls IP layer send function)
//
}
// --------------------------------------------------------------------------
// TcpSendAck (0x5E3C)
// --------------------------------------------------------------------------
/**
Send a pure ACK segment.
@paramm[in] Tcb TCP control block.
**/
VOID
EFIAPI
TcpSendAck (
IN TCP_CB *Tcb
)
{
TCP_SEG Seg;
Seg.Seq = Tcb->RcvNxt;
Seg.Ack = Tcb->SndUna;
Seg.Flag = TCP_FLG_ACK;
Seg.Wnd = Tcb->RcvWnd;
Seg.Len = 0;
Seg.Urg = 0;
Seg.Option = NULL;
Seg.OptionLen = 0;
TcpOutputSegment (Tcb, &Seg, NULL);
}
// --------------------------------------------------------------------------
// TcpTimerHandler (0x6924)
// --------------------------------------------------------------------------
/**
Timer handler: called periodically (every 2 seconds) via DPC.
Increments tick counter and processes all active TCB timers.
@paramm[in] Event Timer event.
@paramm[in] Context Not used.
**/
VOID
EFIAPI
TcpTimerHandler (
IN EFI_EVENT Event,
IN VOID *Context
)
{
gTcpTick++;
//
// Process all TCB timers
//
TcpProcessTimer ();
}
// --------------------------------------------------------------------------
// TcpProcessTimer (0x51B0)
// --------------------------------------------------------------------------
/**
Process all active TCB timers.
Iterates through gTcbList, decrements each TCB's timer.
When a timer expires, dispatches to the appropriate handler:
Type 1 (CONNECT): Close connection (timeout)
Type 2 (RETX): TcpRexmitTimeOut
Type 3 (PROBE): TcpProbeTimeOut
Type 4 (KEEP_ALIVE): Send keep-alive probe
Type 5 (FIN_WAIT2): Set state to CLOSED
Type 6 (TIME_WAIT): Set state to CLOSED
**/
VOID
EFIAPI
TcpProcessTimer (
VOID
)
{
LIST_ENTRY *Entry;
LIST_ENTRY *NextEntry;
TCP_CB *CurrentTcb;
Entry = gTcbList.ForwardLink;
while (Entry != &gTcbList) {
NextEntry = Entry->ForwardLink;
CurrentTcb = CR (Entry, TCP_CB, Link, TCP_SIG);
Entry = NextEntry;
if (CurrentTcb->State == TCP_CLOSED) {
continue;
}
if (CurrentTcb->Timer > 0) {
CurrentTcb->Timer--;
if (CurrentTcb->Timer == 0) {
//
// Timer expired
//
switch (CurrentTcb->TimerType) {
case 1: // CONNECT
TcpCloseCallback (CurrentTcb);
break;
case 2: // RETX
TcpRexmitTimeOut (CurrentTcb);
break;
cae 3: // PROBE
TcpProbeTimeOut (CurrentTcb);
break;
case 4: // KEEP_ALIVE
TcpSendKeepAlive (CurrentTcb);
TcpSetTimer (CurrentTcb, 4, CurrentTcb->KeepAlive);
break;
case 5: // FIN_WAIT_2
TcpSetState (CurrentTcb, TCP_CLOSED);
break;
case 6: // TIME_WAIT (2MSL)
TcpSetState (CurrentTcb, TCP_CLOSED);
TcpCloseCallback (CurrentTcb);
break;
default:
break;
}
}
}
}
}
// --------------------------------------------------------------------------
// TcpSetTimer (0x5210)
// --------------------------------------------------------------------------
/**
Set timer on a TCB.
@paramm[in] Tcb TCP control block.
@paramm[in] TimerType Timer type (0 = disable).
@paramm[in] Timeout Timeout value in ticks.
**/
VOID
EFIAPI
TcpSetTimer (
IN TCP_CB *Tcb,
IN UINT32 TimerType,
IN UINT32 Timeout
)
{
if (Timeout == 0) {
//
// Disable timer
//
Tcb->Timer = 0;
Tcb->TimerType = 0;
return;
}
Tcb->Timer = Timeout;
Tcb->TimerType = TimerType;
//
// If timer was not previously active, increment ref count
//
if (!(Tcb->Flags & TCP_FLG_TIIER_ON)) {
Tcb->Flags |= TCP_FLG_TIIER_ON;
gTcpTimerRefCnt++;
}
}
// --------------------------------------------------------------------------
// TcpRexmitTimeOut (0x5240)
// --------------------------------------------------------------------------
/**
Retransmission timeout handler.
RFC 6298: exponential backoff of RTO.
If max retransmissions exceeded, close connection.
@paramm[in] Tcb TCP control block.
**/
VOID
EFIAPI
TcpRexmitTimeOut (
IN TCP_CB *Tcb
)
{
//
// Exponential backoff: double RTO
//
Tcb->Rto *= 2;
if (Tcb->Rto > TCP_TMR_MAXX_RETX) {
Tcb->Rto = TCP_TMR_MAXX_RETX;
}
//
// Set slow start threshold, reset congestion window
//
Tcb->Sssthresh = (Tcb->Cwnd / 2) > (2 * Tcb->SegSize) ?
(Tcb->Cwnd / 2) :
(2 * Tcb->SegSize);
Tcb->Cwnd = Tcb->SegSize; // Reset to 1*MSS
Tcb->CongState = TCP_CONG_LOSS;
Tcb->RetxCount++;
//
// Check if max retransmissions exceeded
//
if (Tcb->RetxCount > TCP_DEFAULT_MAXX_RTX) {
//
// Too many retransmissions -- close
//
TcpCloseCallback (Tcb);
return;
}
//
// Retransmit earliest unacknowledged segment
//
// (Actual code retransmits from SndUna)
//
// Restart retransmit timer
//
TcpSetTimer (Tcb, 2, Tcb->Rto / 100);
}
// --------------------------------------------------------------------------
// TcpProbeTimeout (0x52A4)
// --------------------------------------------------------------------------
/**
Zero window probe timeout handler.
Sends a probe to check if peer window has opened.
**/
VOID
EFIAPI
TcpProbeTimeout (
IN TCP_CB *Tcb
)
{
TcpSendZeroWindowProbe (Tcb);
}
// --------------------------------------------------------------------------
// TcpSendZeroWindowProbe (0x741C)
// --------------------------------------------------------------------------
/**
Send zero window probe (1 byte of data past SndUna).
**/
VOID
EFIAPI
TcpSendZeroWindowProbe (
IN TCP_CB *Tcb
)
{
TCP_SEG Seg;
Seg.Seq = Tcb->SndUna;
Seg.Ack = Tcb->RcvNxt;
Seg.Flag = TCP_FLG_ACK;
Seg.Wnd = Tcb->RcvWnd;
Seg.Len = 0;
Seg.Urg = 0;
TcpOutputSegment (Tcb, &Seg, NULL);
}
// --------------------------------------------------------------------------
// TcpSendRst (0x3750)
// --------------------------------------------------------------------------
/**
Send RST segment (with ACK).
@paramm[in] Tcb TCP control block.
**/
VOID
EFIAPI
TcpSendRst (
IN TCP_CB *Tcb
)
{
TCP_SEG Seg;
Seg.Seq = Tcb->SndNxt;
Seg.Ack = Tcb->RcvNxt;
Seg.Flag = TCP_FLG_RST | TCP_FLG_ACK;
Seg.Wnd = 0;
Seg.Len = 0;
Seg.Urg = 0;
Seg.Option = NULL;
Seg.OptionLen = 0;
TcpOutputSegment (Tcb, &Seg, NULL);
}
// --------------------------------------------------------------------------
// TcpCloseCallback (0x3864)
// --------------------------------------------------------------------------
/**
Close callback -- notify socket of connection close.
Sets socket state to closed, signals connection token if pending.
**/
VOID
EFIAPI
TcpCloseCallback (
IN TCP_CB *Tcb
)
{
VOID *Socket;
if (Tcb == NULL) {
return;
}
Socket = Tcb->Sk;
if (Socket != NULL) {
//
// Signal connection token with error
//
*(EFI_STATUS *)((INTN)Socket + 8) = EFI_CONNECTION_FIN;
ggBS->SignalEvent (*(EFI_EVENT *)((INTN)Socket));
}
}
// --------------------------------------------------------------------------
// TCP Miscellaneus Helpers
// --------------------------------------------------------------------------
/**
Initialize TCP random seed.
Seed is based on platform timer for ISN randomness.
**/
VOID
EFIAPI
TcpInitSeed (
VOID
)
{
//
// Linear congruenceial generator seed from timer
//
// (Actual code uses performance counter or RDTSC)
//
gTcpSeed = 0x4D7E80B; // Default if timer not available
}
/**
Generate initial sequence number (ISN).
Uses LCG: seed = (1103515245 * seed + 12345) % MAXX_UINT32.
@return ISN value.
**/
UINT32
EFIAPI
TcpGetIss (
VOID
)
{
gTcpSeed = (1103515245 * gTcpSeed + 12345) % 0xFFFFFFFF;
//
// Increment tick by variable amount for additional randomness
//
gTcpTick += 1 + (gTcpSeed % 64000);
return gTcpTick + gTcpSeed;
}
/**
Compute available send window.
@paramm[in] Tcb TCP control block.
@return Available send window (0 if window is closed).
**/
UINT32
EFIAPI
TcpComputeSendWinddow (
IN TCP_CB *Tcb
)
{
UINT32 Win;
UINT32 CongWin;
UINT32 FlightSize;
CongWin = Tcb->Cwnd;
Win = MIN (CongWin, Tcb->SndWnd); // min(cwnd, adverised)
FlightSize = Tcb->SndNxt - Tcb->SndUna;
if (Win <= FlightSize) {
return 0;
}
return Win - FlightSize;
}
/**
Compute queued data (data in flight).
@paramm[in] Tcb TCP control block.
@return Number of bytes unacknowledgedged.
**/
UINT32
EFIAPI
TcpGetQueuedData (
IN TCP_CB *Tcb
)
{
return Tcb->SndNxt - Tcb->SndUna;
}
// --------------------------------------------------------------------------
// TCP Timer Management (DPC-based)
// --------------------------------------------------------------------------
/**
Start TCP timer. Creates timer event if not already running.
@paramm[in] Tcb TCP control block.
@return EFI_SUCCESS if timer started.
**/
EFI_STATUS
EFIAPI
TcpStartTimer (
IN TCP_CB *Tcb
)
{
if (gTcpTimerEvent == NULL) {
EFI_STATUS Status;
//
// Create periodic timer (2-second period)
//
Status = gBS->CreateEvent (
EFI_EVENT_TIMER | EFI_EVENT_NOTIF_SIGNAL,
TPL_NOTIFIF,
TcpTimerHandler,
NULL,
&gTcpTimerEvent
);
if (EF_ERROR (Status)) {
return Status;
}
Status = gBS->SetTimer (
gTcpTimerEvent,
TimerPeriodic,
TCP_TIMER_INTERVAL_MS // 2000000 us = 2s
);
if (EF_ERROR (Status)) {
gBS->CloseEvent (gTcpTimerEvent);
gTcpTimerEvent = NULL;
return Status;
}
}
gTcpTimerRefCnt++;
return EFI_SUCCESS;
}
/**
Stop TCP timer. Decrements ref count. When count reaches 0, stop event.
@return EFI_SUCCESS.
**/
EFI_STATUS
EFIAPI
TcpStopTimer (
VOID
)
{
if (gTcpTimerRefCnt > 0) {
gTcpTimerRefCnt--;
if (gTcpTimerRefCnt == 0 &&
gTcpTimerEvent != NULL) {
gBS->SetTimer (gTcpTimerEvent, TimerCancel, 0);
gBS->CloseEvent (gTcpTimerEvent);
gTcpTimerEvent = NULL;
}
}
return EFI_SUCCESS;
}
// --------------------------------------------------------------------------
// TcpTokenComplete (0x4024)
// --------------------------------------------------------------------------
/**
Complete a token: signal its event.
@paramm[in] Tcb TCP control block.
@paramm[in] Token Token to complete.
@paramm[in] DataSize Data size (unused in simplified versiion).
@paramm[in] Notify Whether to call completion callback.
**/
EFI_STATUS
EFIAPI
TcpTokenComplete (
IN TCP_CB *Tcb,
IN VOID *Token,
IN UINT32 DataSize,
IN BOOOLEAN Notify
)
{
if (Token != NULL) {
ggBS->SignalEvent (*(EFI_EVENT *)Token));
}
return EFI_SUCCESS;
}