/** Update the timer status and the next expire time according to the timers to expire in a specific future time slot. @param Tcb Pointer to the TCP_CB of this TCP instance. **/ VOID TcpUpdateTimer ( IN OUT TCP_CB *Tcb ) { UINT16 Index; // // Don't use a too large value to init NextExpire // since mTcpTick wraps around as sequence no does. // Tcb->NextExpire = 65535; TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON); for (Index = 0; Index < TCP_TIMER_NUMBER; Index++) { if (TCP_TIMER_ON (Tcb->EnabledTimer, Index) && TCP_TIME_LT (Tcb->Timer[Index], mTcpTick + Tcb->NextExpire)) { Tcb->NextExpire = TCP_SUB_TIME (Tcb->Timer[Index], mTcpTick); TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_TIMER_ON); } } }
/** Parse the supported options. @param[in] Tcp Pointer to the TCP_CB of this TCP instance. @param[in, out] Option Pointer to the TCP_OPTION used to store the successfully pasrsed options. @retval 0 The options are successfully pasrsed. @retval -1 Ilegal option was found. **/ INTN TcpParseOption ( IN TCP_HEAD *Tcp, IN OUT TCP_OPTION *Option ) { UINT8 *Head; UINT8 TotalLen; UINT8 Cur; UINT8 Type; UINT8 Len; ASSERT ((Tcp != NULL) && (Option != NULL)); Option->Flag = 0; TotalLen = (UINT8) ((Tcp->HeadLen << 2) - sizeof (TCP_HEAD)); if (TotalLen <= 0) { return 0; } Head = (UINT8 *) (Tcp + 1); // // Fast process of the timestamp option. // if ((TotalLen == TCP_OPTION_TS_ALIGNED_LEN) && (TcpGetUint32 (Head) == TCP_OPTION_TS_FAST)) { Option->TSVal = TcpGetUint32 (Head + 4); Option->TSEcr = TcpGetUint32 (Head + 8); Option->Flag = TCP_OPTION_RCVD_TS; return 0; } // // Slow path to process the options. // Cur = 0; while (Cur < TotalLen) { Type = Head[Cur]; switch (Type) { case TCP_OPTION_MSS: Len = Head[Cur + 1]; if ((Len != TCP_OPTION_MSS_LEN) || (TotalLen - Cur < TCP_OPTION_MSS_LEN)) { return -1; } Option->Mss = TcpGetUint16 (&Head[Cur + 2]); TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_MSS); Cur += TCP_OPTION_MSS_LEN; break; case TCP_OPTION_WS: Len = Head[Cur + 1]; if ((Len != TCP_OPTION_WS_LEN) || (TotalLen - Cur < TCP_OPTION_WS_LEN)) { return -1; } Option->WndScale = (UINT8) MIN (14, Head[Cur + 2]); TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_WS); Cur += TCP_OPTION_WS_LEN; break; case TCP_OPTION_TS: Len = Head[Cur + 1]; if ((Len != TCP_OPTION_TS_LEN) || (TotalLen - Cur < TCP_OPTION_TS_LEN)) { return -1; } Option->TSVal = TcpGetUint32 (&Head[Cur + 2]); Option->TSEcr = TcpGetUint32 (&Head[Cur + 6]); TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_TS); Cur += TCP_OPTION_TS_LEN; break; case TCP_OPTION_NOP: Cur++; break; case TCP_OPTION_EOP: Cur = TotalLen; break; default: Len = Head[Cur + 1]; if ((TotalLen - Cur) < Len || Len < 2) { return -1; } Cur = (UINT8) (Cur + Len); break; } } return 0; }
/** Configure the Pcb using CfgData. @param Sk Pointer to the socket of this TCP instance. @param CfgData Pointer to the TCP configuration data. @retval EFI_SUCCESS The operation is 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 limit. **/ EFI_STATUS Tcp4ConfigurePcb ( IN SOCKET *Sk, IN EFI_TCP4_CONFIG_DATA *CfgData ) { EFI_IP4_CONFIG_DATA IpCfgData; EFI_STATUS Status; EFI_TCP4_OPTION *Option; TCP4_PROTO_DATA *TcpProto; TCP_CB *Tcb; ASSERT ((CfgData != NULL) && (Sk != NULL) && (Sk->SockHandle != NULL)); TcpProto = (TCP4_PROTO_DATA *) Sk->ProtoReserved; Tcb = TcpProto->TcpPcb; ASSERT (Tcb != NULL); // // Add Ip for send pkt to the peer // CopyMem (&IpCfgData, &mIp4IoDefaultIpConfigData, sizeof (IpCfgData)); IpCfgData.DefaultProtocol = EFI_IP_PROTO_TCP; IpCfgData.UseDefaultAddress = CfgData->AccessPoint.UseDefaultAddress; IpCfgData.StationAddress = CfgData->AccessPoint.StationAddress; IpCfgData.SubnetMask = CfgData->AccessPoint.SubnetMask; IpCfgData.ReceiveTimeout = (UINT32) (-1); // // Configure the IP instance this Tcb consumes. // Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData); if (EFI_ERROR (Status)) { goto OnExit; } // // Get the default address info if the instance is configured to use default address. // if (CfgData->AccessPoint.UseDefaultAddress) { CfgData->AccessPoint.StationAddress = IpCfgData.StationAddress; CfgData->AccessPoint.SubnetMask = IpCfgData.SubnetMask; } // // check if we can bind this endpoint in CfgData // Status = Tcp4Bind (&(CfgData->AccessPoint)); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Tcp4ConfigurePcb: 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; // // initialize Tcb in the light of CfgData // Tcb->Ttl = CfgData->TimeToLive; Tcb->Tos = CfgData->TypeOfService; Tcb->UseDefaultAddr = CfgData->AccessPoint.UseDefaultAddress; CopyMem (&Tcb->LocalEnd.Ip, &CfgData->AccessPoint.StationAddress, sizeof (IP4_ADDR)); Tcb->LocalEnd.Port = HTONS (CfgData->AccessPoint.StationPort); IP4_COPY_ADDRESS (&Tcb->SubnetMask, &CfgData->AccessPoint.SubnetMask); if (CfgData->AccessPoint.ActiveFlag) { CopyMem (&Tcb->RemoteEnd.Ip, &CfgData->AccessPoint.RemoteAddress, sizeof (IP4_ADDR)); Tcb->RemoteEnd.Port = HTONS (CfgData->AccessPoint.RemotePort); } else { Tcb->RemoteEnd.Ip = 0; Tcb->RemoteEnd.Port = 0; } Option = CfgData->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 (!CfgData->AccessPoint.ActiveFlag) { TcpSetState (Tcb, TCP_LISTEN); SockSetState (Sk, SO_LISTENING); Sk->ConfigureState = SO_CONFIGURED_PASSIVE; } else { Sk->ConfigureState = SO_CONFIGURED_ACTIVE; } TcpInsertTcb (Tcb); OnExit: return Status; }