/** @file The implementation of a dispatch routine for processing TCP requests. (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #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); FreePool (Tcb); 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; 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; 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 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; }