2 Tcp request dispatcher implementation.
4 Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php<BR>
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #define TCP_COMP_VAL(Min, Max, Default, Val) \
18 ((((Val) <= (Max)) && ((Val) >= (Min))) ? (Val) : (Default))
21 Add or remove a route entry in the IP route table associated with this TCP instance.
23 @param Tcb Pointer to the TCP_CB of this TCP instance.
24 @param RouteInfo Pointer to the route info to be processed.
26 @retval EFI_SUCCESS The operation completed successfully.
27 @retval EFI_NOT_STARTED The driver instance has not been started.
28 @retval EFI_NO_MAPPING When using the default address, configuration(DHCP,
29 BOOTP, RARP, etc.) is not finished yet.
30 @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table.
31 @retval EFI_NOT_FOUND This route is not in the routing table
32 (when RouteInfo->DeleteRoute is TRUE).
33 @retval EFI_ACCESS_DENIED The route is already defined in the routing table
34 (when RouteInfo->DeleteRoute is FALSE).
39 IN TCP4_ROUTE_INFO
*RouteInfo
42 EFI_IP4_PROTOCOL
*Ip4
;
44 Ip4
= Tcb
->IpInfo
->Ip
.Ip4
;
50 RouteInfo
->DeleteRoute
,
51 RouteInfo
->SubnetAddress
,
52 RouteInfo
->SubnetMask
,
53 RouteInfo
->GatewayAddress
60 Get the operational settings of this TCP instance.
62 @param Tcb Pointer to the TCP_CB of this TCP instance.
63 @param Mode Pointer to the buffer to store the operational
66 @retval EFI_SUCCESS The mode data is read.
67 @retval EFI_NOT_STARTED No configuration data is available because this
68 instance hasn't been started.
74 IN OUT TCP4_MODE_DATA
*Mode
78 EFI_TCP4_CONFIG_DATA
*ConfigData
;
79 EFI_TCP4_ACCESS_POINT
*AccessPoint
;
80 EFI_TCP4_OPTION
*Option
;
85 if (!SOCK_IS_CONFIGURED (Sock
) && (Mode
->Tcp4ConfigData
!= NULL
)) {
86 return EFI_NOT_STARTED
;
89 if (Mode
->Tcp4State
!= NULL
) {
90 *(Mode
->Tcp4State
) = (EFI_TCP4_CONNECTION_STATE
) Tcb
->State
;
93 if (Mode
->Tcp4ConfigData
!= NULL
) {
95 ConfigData
= Mode
->Tcp4ConfigData
;
96 AccessPoint
= &(ConfigData
->AccessPoint
);
97 Option
= ConfigData
->ControlOption
;
99 ConfigData
->TypeOfService
= Tcb
->Tos
;
100 ConfigData
->TimeToLive
= Tcb
->Ttl
;
102 AccessPoint
->UseDefaultAddress
= Tcb
->UseDefaultAddr
;
104 CopyMem (&AccessPoint
->StationAddress
, &Tcb
->LocalEnd
.Ip
, sizeof (EFI_IPv4_ADDRESS
));
105 AccessPoint
->SubnetMask
= Tcb
->SubnetMask
;
106 AccessPoint
->StationPort
= NTOHS (Tcb
->LocalEnd
.Port
);
108 CopyMem (&AccessPoint
->RemoteAddress
, &Tcb
->RemoteEnd
.Ip
, sizeof (EFI_IPv4_ADDRESS
));
109 AccessPoint
->RemotePort
= NTOHS (Tcb
->RemoteEnd
.Port
);
110 AccessPoint
->ActiveFlag
= (BOOLEAN
) (Tcb
->State
!= TCP_LISTEN
);
112 if (Option
!= NULL
) {
113 Option
->ReceiveBufferSize
= GET_RCV_BUFFSIZE (Tcb
->Sk
);
114 Option
->SendBufferSize
= GET_SND_BUFFSIZE (Tcb
->Sk
);
115 Option
->MaxSynBackLog
= GET_BACKLOG (Tcb
->Sk
);
117 Option
->ConnectionTimeout
= Tcb
->ConnectTimeout
/ TCP_TICK_HZ
;
118 Option
->DataRetries
= Tcb
->MaxRexmit
;
119 Option
->FinTimeout
= Tcb
->FinWait2Timeout
/ TCP_TICK_HZ
;
120 Option
->TimeWaitTimeout
= Tcb
->TimeWaitTimeout
/ TCP_TICK_HZ
;
121 Option
->KeepAliveProbes
= Tcb
->MaxKeepAlive
;
122 Option
->KeepAliveTime
= Tcb
->KeepAliveIdle
/ TCP_TICK_HZ
;
123 Option
->KeepAliveInterval
= Tcb
->KeepAlivePeriod
/ TCP_TICK_HZ
;
125 Option
->EnableNagle
= (BOOLEAN
) (!TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_NO_NAGLE
));
126 Option
->EnableTimeStamp
= (BOOLEAN
) (!TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_NO_TS
));
127 Option
->EnableWindowScaling
= (BOOLEAN
) (!TCP_FLG_ON (Tcb
->CtrlFlag
, TCP_CTRL_NO_WS
));
129 Option
->EnableSelectiveAck
= FALSE
;
130 Option
->EnablePathMtuDiscovery
= FALSE
;
134 Ip
= Tcb
->IpInfo
->Ip
.Ip4
;
137 return Ip
->GetModeData (Ip
, Mode
->Ip4ModeData
, Mode
->MnpConfigData
, Mode
->SnpModeData
);
142 If AP->StationPort isn't zero, check whether the access point
143 is registered, else generate a random station port for this
146 @param AP Pointer to the access point.
148 @retval EFI_SUCCESS The check is passed or the port is assigned.
149 @retval EFI_INVALID_PARAMETER The non-zero station port is already used.
150 @retval EFI_OUT_OF_RESOURCES No port can be allocated.
155 IN EFI_TCP4_ACCESS_POINT
*AP
160 if (0 != AP
->StationPort
) {
162 // check if a same endpoint is bound
164 if (TcpFindTcbByPeer (&AP
->StationAddress
, AP
->StationPort
)) {
166 return EFI_INVALID_PARAMETER
;
170 // generate a random port
174 if (TCP4_PORT_USER_RESERVED
== mTcp4RandomPort
) {
175 mTcp4RandomPort
= TCP4_PORT_KNOWN
;
180 while (TcpFindTcbByPeer (&AP
->StationAddress
, mTcp4RandomPort
)) {
184 if (mTcp4RandomPort
<= TCP4_PORT_KNOWN
) {
187 DEBUG ((EFI_D_ERROR
, "Tcp4Bind: no port can be allocated "
190 return EFI_OUT_OF_RESOURCES
;
193 mTcp4RandomPort
= TCP4_PORT_KNOWN
+ 1;
200 AP
->StationPort
= mTcp4RandomPort
;
208 Flush the Tcb add its associated protocols.
210 @param Tcb Pointer to the TCP_CB to be flushed.
219 TCP4_PROTO_DATA
*TcpProto
;
221 IpIoConfigIp (Tcb
->IpInfo
, NULL
);
224 TcpProto
= (TCP4_PROTO_DATA
*) Sock
->ProtoReserved
;
226 if (SOCK_IS_CONFIGURED (Sock
)) {
227 RemoveEntryList (&Tcb
->List
);
230 // Uninstall the device path protocol.
232 if (Sock
->DevicePath
!= NULL
) {
233 gBS
->UninstallProtocolInterface (
235 &gEfiDevicePathProtocolGuid
,
238 FreePool (Sock
->DevicePath
);
242 NetbufFreeList (&Tcb
->SndQue
);
243 NetbufFreeList (&Tcb
->RcvQue
);
244 Tcb
->State
= TCP_CLOSED
;
248 Attach a Pcb to the socket.
250 @param Sk Pointer to the socket of this TCP instance.
252 @retval EFI_SUCCESS The operation is completed successfully.
253 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
262 TCP4_PROTO_DATA
*ProtoData
;
267 Tcb
= AllocateZeroPool (sizeof (TCP_CB
));
271 DEBUG ((EFI_D_ERROR
, "Tcp4ConfigurePcb: failed to allocate a TCB\n"));
273 return EFI_OUT_OF_RESOURCES
;
276 ProtoData
= (TCP4_PROTO_DATA
*) Sk
->ProtoReserved
;
277 IpIo
= ProtoData
->TcpService
->IpIo
;
280 // Create an IpInfo for this Tcb.
282 Tcb
->IpInfo
= IpIoAddIp (IpIo
);
283 if (Tcb
->IpInfo
== NULL
) {
286 return EFI_OUT_OF_RESOURCES
;
290 // Open the new created IP instance BY_CHILD.
292 Status
= gBS
->OpenProtocol (
293 Tcb
->IpInfo
->ChildHandle
,
294 &gEfiIp4ProtocolGuid
,
298 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
300 if (EFI_ERROR (Status
)) {
301 IpIoRemoveIp (IpIo
, Tcb
->IpInfo
);
305 InitializeListHead (&Tcb
->List
);
306 InitializeListHead (&Tcb
->SndQue
);
307 InitializeListHead (&Tcb
->RcvQue
);
309 Tcb
->State
= TCP_CLOSED
;
311 ProtoData
->TcpPcb
= Tcb
;
317 Detach the Pcb of the socket.
319 @param Sk Pointer to the socket of this TCP instance.
327 TCP4_PROTO_DATA
*ProtoData
;
330 ProtoData
= (TCP4_PROTO_DATA
*) Sk
->ProtoReserved
;
331 Tcb
= ProtoData
->TcpPcb
;
333 ASSERT (Tcb
!= NULL
);
338 // Close the IP protocol.
341 Tcb
->IpInfo
->ChildHandle
,
342 &gEfiIp4ProtocolGuid
,
343 ProtoData
->TcpService
->IpIo
->Image
,
347 IpIoRemoveIp (ProtoData
->TcpService
->IpIo
, Tcb
->IpInfo
);
351 ProtoData
->TcpPcb
= NULL
;
356 Configure the Pcb using CfgData.
358 @param Sk Pointer to the socket of this TCP instance.
359 @param CfgData Pointer to the TCP configuration data.
361 @retval EFI_SUCCESS The operation is completed successfully.
362 @retval EFI_INVALID_PARAMETER A same access point has been configured in
363 another TCP instance.
364 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
370 IN EFI_TCP4_CONFIG_DATA
*CfgData
373 EFI_IP4_CONFIG_DATA IpCfgData
;
375 EFI_TCP4_OPTION
*Option
;
376 TCP4_PROTO_DATA
*TcpProto
;
379 ASSERT ((CfgData
!= NULL
) && (Sk
!= NULL
) && (Sk
->SockHandle
!= NULL
));
381 TcpProto
= (TCP4_PROTO_DATA
*) Sk
->ProtoReserved
;
382 Tcb
= TcpProto
->TcpPcb
;
384 ASSERT (Tcb
!= NULL
);
387 // Add Ip for send pkt to the peer
389 CopyMem (&IpCfgData
, &mIp4IoDefaultIpConfigData
, sizeof (IpCfgData
));
390 IpCfgData
.DefaultProtocol
= EFI_IP_PROTO_TCP
;
391 IpCfgData
.UseDefaultAddress
= CfgData
->AccessPoint
.UseDefaultAddress
;
392 IpCfgData
.StationAddress
= CfgData
->AccessPoint
.StationAddress
;
393 IpCfgData
.SubnetMask
= CfgData
->AccessPoint
.SubnetMask
;
394 IpCfgData
.ReceiveTimeout
= (UINT32
) (-1);
397 // Configure the IP instance this Tcb consumes.
399 Status
= IpIoConfigIp (Tcb
->IpInfo
, &IpCfgData
);
400 if (EFI_ERROR (Status
)) {
405 // Get the default address info if the instance is configured to use default address.
407 if (CfgData
->AccessPoint
.UseDefaultAddress
) {
408 CfgData
->AccessPoint
.StationAddress
= IpCfgData
.StationAddress
;
409 CfgData
->AccessPoint
.SubnetMask
= IpCfgData
.SubnetMask
;
413 // check if we can bind this endpoint in CfgData
415 Status
= Tcp4Bind (&(CfgData
->AccessPoint
));
417 if (EFI_ERROR (Status
)) {
418 DEBUG ((EFI_D_ERROR
, "Tcp4ConfigurePcb: Bind endpoint failed "
419 "with %r\n", Status
));
425 // Initalize the operating information in this Tcb
427 ASSERT (Tcb
->State
== TCP_CLOSED
&&
428 IsListEmpty (&Tcb
->SndQue
) &&
429 IsListEmpty (&Tcb
->RcvQue
));
431 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_NO_KEEPALIVE
);
432 Tcb
->State
= TCP_CLOSED
;
435 Tcb
->RcvMss
= TcpGetRcvMss (Sk
);
438 Tcb
->Rto
= 3 * TCP_TICK_HZ
;
440 Tcb
->CWnd
= Tcb
->SndMss
;
441 Tcb
->Ssthresh
= 0xffffffff;
443 Tcb
->CongestState
= TCP_CONGEST_OPEN
;
445 Tcb
->KeepAliveIdle
= TCP_KEEPALIVE_IDLE_MIN
;
446 Tcb
->KeepAlivePeriod
= TCP_KEEPALIVE_PERIOD
;
447 Tcb
->MaxKeepAlive
= TCP_MAX_KEEPALIVE
;
448 Tcb
->MaxRexmit
= TCP_MAX_LOSS
;
449 Tcb
->FinWait2Timeout
= TCP_FIN_WAIT2_TIME
;
450 Tcb
->TimeWaitTimeout
= TCP_TIME_WAIT_TIME
;
451 Tcb
->ConnectTimeout
= TCP_CONNECT_TIME
;
454 // initialize Tcb in the light of CfgData
456 Tcb
->Ttl
= CfgData
->TimeToLive
;
457 Tcb
->Tos
= CfgData
->TypeOfService
;
459 Tcb
->UseDefaultAddr
= CfgData
->AccessPoint
.UseDefaultAddress
;
461 CopyMem (&Tcb
->LocalEnd
.Ip
, &CfgData
->AccessPoint
.StationAddress
, sizeof (IP4_ADDR
));
462 Tcb
->LocalEnd
.Port
= HTONS (CfgData
->AccessPoint
.StationPort
);
463 Tcb
->SubnetMask
= CfgData
->AccessPoint
.SubnetMask
;
465 if (CfgData
->AccessPoint
.ActiveFlag
) {
466 CopyMem (&Tcb
->RemoteEnd
.Ip
, &CfgData
->AccessPoint
.RemoteAddress
, sizeof (IP4_ADDR
));
467 Tcb
->RemoteEnd
.Port
= HTONS (CfgData
->AccessPoint
.RemotePort
);
469 Tcb
->RemoteEnd
.Ip
= 0;
470 Tcb
->RemoteEnd
.Port
= 0;
473 Option
= CfgData
->ControlOption
;
475 if (Option
!= NULL
) {
478 (UINT32
) (TCP_COMP_VAL (
479 TCP_RCV_BUF_SIZE_MIN
,
482 Option
->ReceiveBufferSize
488 (UINT32
) (TCP_COMP_VAL (
489 TCP_SND_BUF_SIZE_MIN
,
492 Option
->SendBufferSize
499 (UINT32
) (TCP_COMP_VAL (
503 Option
->MaxSynBackLog
508 Tcb
->MaxRexmit
= (UINT16
) TCP_COMP_VAL (
514 Tcb
->FinWait2Timeout
= TCP_COMP_VAL (
516 TCP_FIN_WAIT2_TIME_MAX
,
518 (UINT32
) (Option
->FinTimeout
* TCP_TICK_HZ
)
521 if (Option
->TimeWaitTimeout
!= 0) {
522 Tcb
->TimeWaitTimeout
= TCP_COMP_VAL (
524 TCP_TIME_WAIT_TIME_MAX
,
526 (UINT32
) (Option
->TimeWaitTimeout
* TCP_TICK_HZ
)
529 Tcb
->TimeWaitTimeout
= 0;
532 if (Option
->KeepAliveProbes
!= 0) {
533 TCP_CLEAR_FLG (Tcb
->CtrlFlag
, TCP_CTRL_NO_KEEPALIVE
);
535 Tcb
->MaxKeepAlive
= (UINT8
) TCP_COMP_VAL (
536 TCP_MAX_KEEPALIVE_MIN
,
539 Option
->KeepAliveProbes
541 Tcb
->KeepAliveIdle
= TCP_COMP_VAL (
542 TCP_KEEPALIVE_IDLE_MIN
,
543 TCP_KEEPALIVE_IDLE_MAX
,
544 TCP_KEEPALIVE_IDLE_MIN
,
545 (UINT32
) (Option
->KeepAliveTime
* TCP_TICK_HZ
)
547 Tcb
->KeepAlivePeriod
= TCP_COMP_VAL (
548 TCP_KEEPALIVE_PERIOD_MIN
,
549 TCP_KEEPALIVE_PERIOD
,
550 TCP_KEEPALIVE_PERIOD
,
551 (UINT32
) (Option
->KeepAliveInterval
* TCP_TICK_HZ
)
555 Tcb
->ConnectTimeout
= TCP_COMP_VAL (
556 TCP_CONNECT_TIME_MIN
,
559 (UINT32
) (Option
->ConnectionTimeout
* TCP_TICK_HZ
)
562 if (!Option
->EnableNagle
) {
563 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_NO_NAGLE
);
566 if (!Option
->EnableTimeStamp
) {
567 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_NO_TS
);
570 if (!Option
->EnableWindowScaling
) {
571 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_NO_WS
);
576 // The socket is bound, the <SrcIp, SrcPort, DstIp, DstPort> is
577 // determined, construct the IP device path and install it.
579 Status
= TcpInstallDevicePath (Sk
);
580 if (EFI_ERROR (Status
)) {
585 // update state of Tcb and socket
587 if (!CfgData
->AccessPoint
.ActiveFlag
) {
589 TcpSetState (Tcb
, TCP_LISTEN
);
590 SockSetState (Sk
, SO_LISTENING
);
592 Sk
->ConfigureState
= SO_CONFIGURED_PASSIVE
;
595 Sk
->ConfigureState
= SO_CONFIGURED_ACTIVE
;
607 The procotol handler provided to the socket layer, used to
608 dispatch the socket level requests by calling the corresponding
611 @param Sock Pointer to the socket of this TCP instance.
612 @param Request The code of this operation request.
613 @param Data Pointer to the operation specific data passed in
614 together with the operation request.
616 @retval EFI_SUCCESS The socket request is completed successfully.
617 @retval other The error status returned by the corresponding TCP
625 IN VOID
*Data OPTIONAL
629 TCP4_PROTO_DATA
*ProtoData
;
630 EFI_IP4_PROTOCOL
*Ip
;
632 ProtoData
= (TCP4_PROTO_DATA
*) Sock
->ProtoReserved
;
633 Tcb
= ProtoData
->TcpPcb
;
637 Ip
= ProtoData
->TcpService
->IpIo
->Ip
.Ip4
;
643 // After user received data from socket buffer, socket will
644 // notify TCP using this message to give it a chance to send out
645 // window update information
647 ASSERT (Tcb
!= NULL
);
648 TcpOnAppConsume (Tcb
);
653 ASSERT (Tcb
!= NULL
);
670 Tcb
->SndPsh
= TcpGetMaxSndNxt (Tcb
) + GET_SND_DATASIZE (Tcb
->Sk
);
671 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_PSH
);
676 Tcb
->SndUp
= TcpGetMaxSndNxt (Tcb
) + GET_SND_DATASIZE (Tcb
->Sk
) - 1;
677 TCP_SET_FLG (Tcb
->CtrlFlag
, TCP_CTRL_SND_URG
);
683 TcpOnAppConnect (Tcb
);
689 return Tcp4AttachPcb (Sock
);
699 Tcp4DetachPcb (Sock
);
705 return Tcp4ConfigurePcb (
707 (EFI_TCP4_CONFIG_DATA
*) Data
712 ASSERT ((Data
!= NULL
) && (Tcb
!= NULL
));
714 return Tcp4GetMode (Tcb
, (TCP4_MODE_DATA
*) Data
);
718 ASSERT ((Data
!= NULL
) && (Tcb
!= NULL
));
720 return Tcp4Route (Tcb
, (TCP4_ROUTE_INFO
*) Data
);
723 return EFI_UNSUPPORTED
;