3 Copyright (c) 2005 - 2006, Intel Corporation
\r
4 All rights reserved. This program and the accompanying materials
\r
5 are licensed and made available under the terms and conditions of the BSD License
\r
6 which accompanies this distribution. The full text of the license may be found at
\r
7 http://opensource.org/licenses/bsd-license.php
\r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
\r
21 #include "Tcp4Main.h"
\r
23 #define TCP_COMP_VAL(Min, Max, Default, Val) \
\r
24 ((((Val) <= (Max)) && ((Val) >= (Min))) ? (Val) : (Default))
\r
30 IN TCP4_ROUTE_INFO *RouteInfo
\r
34 Routine Description:
\r
36 Add or remove a route entry in the IP route table associated
\r
37 with this TCP instance.
\r
41 Tcb - Pointer to the TCP_CB of this TCP instance.
\r
42 RouteInfo - Pointer to the route info to be processed.
\r
46 EFI_SUCCESS - The operation completed successfully.
\r
47 EFI_NOT_STARTED - The driver instance has not been started.
\r
48 EFI_NO_MAPPING - When using the default address, configuration(DHCP,
\r
49 BOOTP, RARP, etc.) is not finished yet.
\r
50 EFI_OUT_OF_RESOURCES - Could not add the entry to the routing table.
\r
51 EFI_NOT_FOUND - This route is not in the routing table
\r
52 (when RouteInfo->DeleteRoute is TRUE).
\r
53 EFI_ACCESS_DENIED - The route is already defined in the routing table
\r
54 (when RouteInfo->DeleteRoute is FALSE).
\r
58 EFI_IP4_PROTOCOL *Ip;
\r
60 Ip = Tcb->IpInfo->Ip;
\r
66 RouteInfo->DeleteRoute,
\r
67 RouteInfo->SubnetAddress,
\r
68 RouteInfo->SubnetMask,
\r
69 RouteInfo->GatewayAddress
\r
76 Get the operational settings of this TCP instance.
\r
78 @param Tcb Pointer to the TCP_CB of this TCP instance.
\r
79 @param Mode Pointer to the buffer to store the operational
\r
82 @retval EFI_SUCCESS The mode data is read.
\r
83 @retval EFI_NOT_STARTED No configuration data is available because this
\r
84 instance hasn't been started.
\r
91 IN TCP4_MODE_DATA *Mode
\r
95 EFI_TCP4_CONFIG_DATA *ConfigData;
\r
96 EFI_TCP4_ACCESS_POINT *AccessPoint;
\r
97 EFI_TCP4_OPTION *Option;
\r
98 EFI_IP4_PROTOCOL *Ip;
\r
102 if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp4ConfigData != NULL)) {
\r
103 return EFI_NOT_STARTED;
\r
106 if (Mode->Tcp4State) {
\r
107 *(Mode->Tcp4State) = (EFI_TCP4_CONNECTION_STATE) Tcb->State;
\r
110 if (Mode->Tcp4ConfigData) {
\r
112 ConfigData = Mode->Tcp4ConfigData;
\r
113 AccessPoint = &(ConfigData->AccessPoint);
\r
114 Option = ConfigData->ControlOption;
\r
116 ConfigData->TypeOfService = Tcb->TOS;
\r
117 ConfigData->TimeToLive = Tcb->TTL;
\r
119 AccessPoint->UseDefaultAddress = Tcb->UseDefaultAddr;
\r
121 NetCopyMem (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
\r
122 AccessPoint->SubnetMask = Tcb->SubnetMask;
\r
123 AccessPoint->StationPort = NTOHS (Tcb->LocalEnd.Port);
\r
125 NetCopyMem (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));
\r
126 AccessPoint->RemotePort = NTOHS (Tcb->RemoteEnd.Port);
\r
127 AccessPoint->ActiveFlag = (BOOLEAN) (Tcb->State != TCP_LISTEN);
\r
129 if (Option != NULL) {
\r
130 Option->ReceiveBufferSize = GET_RCV_BUFFSIZE (Tcb->Sk);
\r
131 Option->SendBufferSize = GET_SND_BUFFSIZE (Tcb->Sk);
\r
132 Option->MaxSynBackLog = GET_BACKLOG (Tcb->Sk);
\r
134 Option->ConnectionTimeout = Tcb->ConnectTimeout / TCP_TICK_HZ;
\r
135 Option->DataRetries = Tcb->MaxRexmit;
\r
136 Option->FinTimeout = Tcb->FinWait2Timeout / TCP_TICK_HZ;
\r
137 Option->TimeWaitTimeout = Tcb->TimeWaitTimeout / TCP_TICK_HZ;
\r
138 Option->KeepAliveProbes = Tcb->MaxKeepAlive;
\r
139 Option->KeepAliveTime = Tcb->KeepAliveIdle / TCP_TICK_HZ;
\r
140 Option->KeepAliveInterval = Tcb->KeepAlivePeriod / TCP_TICK_HZ;
\r
142 Option->EnableNagle = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE));
\r
143 Option->EnableTimeStamp = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS));
\r
144 Option->EnableWindowScaling = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS))
\r
147 Option->EnableSelectiveAck = FALSE;
\r
148 Option->EnablePathMtuDiscovery = FALSE;
\r
152 Ip = Tcb->IpInfo->Ip;
\r
155 return Ip->GetModeData (Ip, Mode->Ip4ModeData, Mode->MnpConfigData, Mode->SnpModeData);
\r
160 If AP->StationPort isn't zero, check whether the access point
\r
161 is registered, else generate a random station port for this
\r
164 @param AP Pointer to the access point.
\r
166 @retval EFI_SUCCESS The check is passed or the port is assigned.
\r
167 @retval EFI_INVALID_PARAMETER The non-zero station port is already used.
\r
168 @retval EFI_OUT_OF_RESOURCES No port can be allocated.
\r
174 IN EFI_TCP4_ACCESS_POINT *AP
\r
179 if (0 != AP->StationPort) {
\r
181 // check if a same endpoint is bound
\r
183 if (TcpFindTcbByPeer (&AP->StationAddress, AP->StationPort)) {
\r
185 return EFI_INVALID_PARAMETER;
\r
189 // generate a random port
\r
193 if (TCP4_PORT_USER_RESERVED == mTcp4RandomPort) {
\r
194 mTcp4RandomPort = TCP4_PORT_KNOWN;
\r
199 while (TcpFindTcbByPeer (&AP->StationAddress, mTcp4RandomPort)) {
\r
203 if (mTcp4RandomPort <= TCP4_PORT_KNOWN) {
\r
206 TCP4_DEBUG_ERROR (("Tcp4Bind: no port can be allocated "
\r
207 "for this pcb\n"));
\r
209 return EFI_OUT_OF_RESOURCES;
\r
212 mTcp4RandomPort = TCP4_PORT_KNOWN + 1;
\r
219 AP->StationPort = mTcp4RandomPort;
\r
222 return EFI_SUCCESS;
\r
227 Flush the Tcb add its associated protocols..
\r
229 @param Tcb Pointer to the TCP_CB to be flushed.
\r
231 @retval EFI_SUCCESS The operation is completed successfully.
\r
241 TCP4_PROTO_DATA *TcpProto;
\r
243 IpIoConfigIp (Tcb->IpInfo, NULL);
\r
246 TcpProto = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
\r
248 if (SOCK_IS_CONFIGURED (Sock)) {
\r
249 NetListRemoveEntry (&Tcb->List);
\r
251 TcpSetVariableData (TcpProto->TcpService);
\r
254 NetbufFreeList (&Tcb->SndQue);
\r
255 NetbufFreeList (&Tcb->RcvQue);
\r
265 TCP4_PROTO_DATA *ProtoData;
\r
268 Tcb = NetAllocateZeroPool (sizeof (TCP_CB));
\r
272 TCP4_DEBUG_ERROR (("Tcp4ConfigurePcb: failed to allocate a TCB\n"));
\r
274 return EFI_OUT_OF_RESOURCES;
\r
277 ProtoData = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
\r
278 IpIo = ProtoData->TcpService->IpIo;
\r
281 // Create an IpInfo for this Tcb.
\r
283 Tcb->IpInfo = IpIoAddIp (IpIo);
\r
284 if (Tcb->IpInfo == NULL) {
\r
287 return EFI_OUT_OF_RESOURCES;
\r
290 NetListInit (&Tcb->List);
\r
291 NetListInit (&Tcb->SndQue);
\r
292 NetListInit (&Tcb->RcvQue);
\r
294 Tcb->State = TCP_CLOSED;
\r
296 ProtoData->TcpPcb = Tcb;
\r
298 return EFI_SUCCESS;
\r
307 TCP4_PROTO_DATA *ProtoData;
\r
310 ProtoData = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
\r
311 Tcb = ProtoData->TcpPcb;
\r
313 ASSERT (Tcb != NULL);
\r
315 Tcp4FlushPcb (Tcb);
\r
317 IpIoRemoveIp (ProtoData->TcpService->IpIo, Tcb->IpInfo);
\r
321 ProtoData->TcpPcb = NULL;
\r
326 Configure the Tcb using CfgData.
\r
328 @param Sk Pointer to the socket of this TCP instance.
\r
329 @param SkTcb Pointer to the TCP_CB of this TCP instance.
\r
330 @param CfgData Pointer to the TCP configuration data.
\r
332 @retval EFI_SUCCESS The operation is completed successfully.
\r
333 @retval EFI_INVALID_PARAMETER A same access point has been configured in
\r
334 another TCP instance.
\r
335 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
\r
342 IN EFI_TCP4_CONFIG_DATA *CfgData
\r
345 EFI_IP4_CONFIG_DATA IpCfgData;
\r
347 EFI_TCP4_OPTION *Option;
\r
348 TCP4_PROTO_DATA *TcpProto;
\r
351 ASSERT (CfgData && Sk && Sk->SockHandle);
\r
353 TcpProto = (TCP4_PROTO_DATA *) Sk->ProtoReserved;
\r
354 Tcb = TcpProto->TcpPcb;
\r
356 ASSERT (Tcb != NULL);
\r
359 // Add Ip for send pkt to the peer
\r
361 CopyMem (&IpCfgData, &mIpIoDefaultIpConfigData, sizeof (IpCfgData));
\r
362 IpCfgData.DefaultProtocol = EFI_IP_PROTO_TCP;
\r
363 IpCfgData.UseDefaultAddress = CfgData->AccessPoint.UseDefaultAddress;
\r
364 IpCfgData.StationAddress = CfgData->AccessPoint.StationAddress;
\r
365 IpCfgData.SubnetMask = CfgData->AccessPoint.SubnetMask;
\r
366 IpCfgData.ReceiveTimeout = (UINT32) (-1);
\r
369 // Configure the IP instance this Tcb consumes.
\r
371 Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData);
\r
372 if (EFI_ERROR (Status)) {
\r
377 // Get the default address info if the instance is configured to use default address.
\r
379 if (CfgData->AccessPoint.UseDefaultAddress) {
\r
380 CfgData->AccessPoint.StationAddress = IpCfgData.StationAddress;
\r
381 CfgData->AccessPoint.SubnetMask = IpCfgData.SubnetMask;
\r
385 // check if we can bind this endpoint in CfgData
\r
387 Status = Tcp4Bind (&(CfgData->AccessPoint));
\r
389 if (EFI_ERROR (Status)) {
\r
390 TCP4_DEBUG_ERROR (("Tcp4ConfigurePcb: Bind endpoint failed "
\r
391 "with %r\n", Status));
\r
397 // Initalize the operating information in this Tcb
\r
399 ASSERT (Tcb->State == TCP_CLOSED &&
\r
400 NetListIsEmpty (&Tcb->SndQue) &&
\r
401 NetListIsEmpty (&Tcb->RcvQue));
\r
403 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
\r
404 Tcb->State = TCP_CLOSED;
\r
407 Tcb->RcvMss = TcpGetRcvMss (Sk);
\r
410 Tcb->Rto = 3 * TCP_TICK_HZ;
\r
412 Tcb->CWnd = Tcb->SndMss;
\r
413 Tcb->Ssthresh = 0xffffffff;
\r
415 Tcb->CongestState = TCP_CONGEST_OPEN;
\r
417 Tcb->KeepAliveIdle = TCP_KEEPALIVE_IDLE_MIN;
\r
418 Tcb->KeepAlivePeriod = TCP_KEEPALIVE_PERIOD;
\r
419 Tcb->MaxKeepAlive = TCP_MAX_KEEPALIVE;
\r
420 Tcb->MaxRexmit = TCP_MAX_LOSS;
\r
421 Tcb->FinWait2Timeout = TCP_FIN_WAIT2_TIME;
\r
422 Tcb->TimeWaitTimeout = TCP_TIME_WAIT_TIME;
\r
423 Tcb->ConnectTimeout = TCP_CONNECT_TIME;
\r
426 // initialize Tcb in the light of CfgData
\r
428 Tcb->TTL = CfgData->TimeToLive;
\r
429 Tcb->TOS = CfgData->TypeOfService;
\r
431 NetCopyMem (&Tcb->LocalEnd.Ip, &CfgData->AccessPoint.StationAddress, sizeof (IP4_ADDR));
\r
432 Tcb->LocalEnd.Port = HTONS (CfgData->AccessPoint.StationPort);
\r
433 Tcb->SubnetMask = CfgData->AccessPoint.SubnetMask;
\r
435 NetCopyMem (&Tcb->RemoteEnd.Ip, &CfgData->AccessPoint.RemoteAddress, sizeof (IP4_ADDR));
\r
436 Tcb->RemoteEnd.Port = HTONS (CfgData->AccessPoint.RemotePort);
\r
438 Option = CfgData->ControlOption;
\r
440 if (Option != NULL) {
\r
443 (UINT32) (TCP_COMP_VAL (
\r
444 TCP_RCV_BUF_SIZE_MIN,
\r
447 Option->ReceiveBufferSize
\r
453 (UINT32) (TCP_COMP_VAL (
\r
454 TCP_SND_BUF_SIZE_MIN,
\r
457 Option->SendBufferSize
\r
464 (UINT32) (TCP_COMP_VAL (
\r
468 Option->MaxSynBackLog
\r
473 Tcb->MaxRexmit = (UINT16) TCP_COMP_VAL (
\r
477 Option->DataRetries
\r
479 Tcb->FinWait2Timeout = TCP_COMP_VAL (
\r
480 TCP_FIN_WAIT2_TIME,
\r
481 TCP_FIN_WAIT2_TIME_MAX,
\r
482 TCP_FIN_WAIT2_TIME,
\r
483 (UINT32) (Option->FinTimeout * TCP_TICK_HZ)
\r
486 if (Option->TimeWaitTimeout != 0) {
\r
487 Tcb->TimeWaitTimeout = TCP_COMP_VAL (
\r
488 TCP_TIME_WAIT_TIME,
\r
489 TCP_TIME_WAIT_TIME_MAX,
\r
490 TCP_TIME_WAIT_TIME,
\r
491 (UINT32) (Option->TimeWaitTimeout * TCP_TICK_HZ)
\r
494 Tcb->TimeWaitTimeout = 0;
\r
497 if (Option->KeepAliveProbes != 0) {
\r
498 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE);
\r
500 Tcb->MaxKeepAlive = (UINT8) TCP_COMP_VAL (
\r
501 TCP_MAX_KEEPALIVE_MIN,
\r
504 Option->KeepAliveProbes
\r
506 Tcb->KeepAliveIdle = TCP_COMP_VAL (
\r
507 TCP_KEEPALIVE_IDLE_MIN,
\r
508 TCP_KEEPALIVE_IDLE_MAX,
\r
509 TCP_KEEPALIVE_IDLE_MIN,
\r
510 (UINT32) (Option->KeepAliveTime * TCP_TICK_HZ)
\r
512 Tcb->KeepAlivePeriod = TCP_COMP_VAL (
\r
513 TCP_KEEPALIVE_PERIOD_MIN,
\r
514 TCP_KEEPALIVE_PERIOD,
\r
515 TCP_KEEPALIVE_PERIOD,
\r
516 (UINT32) (Option->KeepAliveInterval * TCP_TICK_HZ)
\r
520 Tcb->ConnectTimeout = TCP_COMP_VAL (
\r
521 TCP_CONNECT_TIME_MIN,
\r
524 (UINT32) (Option->ConnectionTimeout * TCP_TICK_HZ)
\r
527 if (Option->EnableNagle == FALSE) {
\r
528 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE);
\r
531 if (Option->EnableTimeStamp == FALSE) {
\r
532 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_TS);
\r
535 if (Option->EnableWindowScaling == FALSE) {
\r
536 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_WS);
\r
541 // update state of Tcb and socket
\r
543 if (CfgData->AccessPoint.ActiveFlag == FALSE) {
\r
545 TcpSetState (Tcb, TCP_LISTEN);
\r
546 SockSetState (Sk, SO_LISTENING);
\r
548 Sk->ConfigureState = SO_CONFIGURED_PASSIVE;
\r
551 Sk->ConfigureState = SO_CONFIGURED_ACTIVE;
\r
554 TcpInsertTcb (Tcb);
\r
563 The procotol handler provided to the socket layer, used to
\r
564 dispatch the socket level requests by calling the corresponding
\r
565 TCP layer functions.
\r
567 @param Sock Pointer to the socket of this TCP instance.
\r
568 @param Request The code of this operation request.
\r
569 @param Data Pointer to the operation specific data passed in
\r
570 together with the operation request.
\r
572 @retval EFI_SUCCESS The socket request is completed successfully.
\r
573 @retval other The error status returned by the corresponding TCP
\r
580 IN SOCK_REQUEST Request,
\r
581 IN VOID *Data OPTIONAL
\r
585 TCP4_PROTO_DATA *ProtoData;
\r
586 EFI_IP4_PROTOCOL *Ip;
\r
588 ProtoData = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
\r
589 Tcb = ProtoData->TcpPcb;
\r
593 Ip = ProtoData->TcpService->IpIo->Ip;
\r
597 case SOCK_CONSUMED:
\r
599 // After user received data from socket buffer, socket will
\r
600 // notify TCP using this message to give it a chance to send out
\r
601 // window update information
\r
604 TcpOnAppConsume (Tcb);
\r
610 TcpOnAppSend (Tcb);
\r
615 TcpOnAppClose (Tcb);
\r
621 TcpOnAppAbort (Tcb);
\r
626 Tcb->SndPsh = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk);
\r
627 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);
\r
632 Tcb->SndUp = TcpGetMaxSndNxt (Tcb) + GET_SND_DATASIZE (Tcb->Sk) - 1;
\r
633 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
\r
639 TcpOnAppConnect (Tcb);
\r
645 return Tcp4AttachPcb (Sock);
\r
651 Tcp4FlushPcb (Tcb);
\r
657 Tcp4DetachPcb (Sock);
\r
661 case SOCK_CONFIGURE:
\r
663 return Tcp4ConfigurePcb (
\r
665 (EFI_TCP4_CONFIG_DATA *) Data
\r
672 ASSERT (Data && Tcb);
\r
674 return Tcp4GetMode (Tcb, (TCP4_MODE_DATA *) Data);
\r
680 ASSERT (Data && Tcb);
\r
682 return Tcp4Route (Tcb, (TCP4_ROUTE_INFO *) Data);
\r
685 return EFI_UNSUPPORTED;
\r
688 return EFI_SUCCESS;
\r