/** @file\r
TCP input process routines.\r
\r
- Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
Tcb->CWnd = Tcb->Ssthresh + 3 * Tcb->SndMss;\r
\r
DEBUG (\r
- (EFI_D_INFO,\r
+ (EFI_D_NET,\r
"TcpFastRecover: enter fast retransmission for TCB %p, recover point is %d\n",\r
Tcb,\r
Tcb->Recover)\r
//\r
Tcb->CWnd += Tcb->SndMss;\r
DEBUG (\r
- (EFI_D_INFO,\r
+ (EFI_D_NET,\r
"TcpFastRecover: received another duplicated ACK (%d) for TCB %p\n",\r
Seg->Ack,\r
Tcb)\r
\r
Tcb->CongestState = TCP_CONGEST_OPEN;\r
DEBUG (\r
- (EFI_D_INFO,\r
+ (EFI_D_NET,\r
"TcpFastRecover: received a full ACK(%d) for TCB %p, exit fast recovery\n",\r
Seg->Ack,\r
Tcb)\r
Tcb->CWnd -= Acked;\r
\r
DEBUG (\r
- (EFI_D_INFO,\r
+ (EFI_D_NET,\r
"TcpFastRecover: received a partial ACK(%d) for TCB %p\n",\r
Seg->Ack,\r
Tcb)\r
Tcb->CongestState = TCP_CONGEST_OPEN;\r
\r
DEBUG (\r
- (EFI_D_INFO,\r
+ (EFI_D_NET,\r
"TcpFastLossRecover: received a full ACK(%d) for TCB %p\n",\r
Seg->Ack,\r
Tcb)\r
//\r
TcpRetransmit (Tcb, Seg->Ack);\r
DEBUG (\r
- (EFI_D_INFO,\r
+ (EFI_D_NET,\r
"TcpFastLossRecover: received a partial ACK(%d) for TCB %p\n",\r
Seg->Ack,\r
Tcb)\r
}\r
\r
DEBUG (\r
- (EFI_D_INFO,\r
+ (EFI_D_NET,\r
"TcpComputeRtt: new RTT for TCB %p computed SRTT: %d RTTVAR: %d RTO: %d\n",\r
Tcb,\r
Tcb->SRtt,\r
@param[in] Left The sequence number of the window's left edge.\r
@param[in] Right The sequence number of the window's right edge.\r
\r
+ @retval 0 The segment is broken.\r
+ @retval 1 The segment is in good shape.\r
+\r
**/\r
-VOID\r
+INTN\r
TcpTrimSegment (\r
IN NET_BUF *Nbuf,\r
IN TCP_SEQNO Left,\r
\r
Seg->Seq = Seg->End;\r
NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_HEAD);\r
- return;\r
+ return 1;\r
}\r
\r
//\r
}\r
}\r
\r
- ASSERT (TcpVerifySegment (Nbuf) != 0);\r
+ return TcpVerifySegment (Nbuf);\r
}\r
\r
/**\r
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
@param[in] Nbuf Pointer to the NET_BUF containing the received tcp segment.\r
\r
+ @retval 0 The segment is broken.\r
+ @retval 1 The segment is in good shape.\r
+\r
**/\r
-VOID\r
+INTN\r
TcpTrimInWnd (\r
IN TCP_CB *Tcb,\r
IN NET_BUF *Nbuf\r
)\r
{\r
- TcpTrimSegment (Nbuf, Tcb->RcvNxt, Tcb->RcvWl2 + Tcb->RcvWnd);\r
+ return TcpTrimSegment (Nbuf, Tcb->RcvNxt, Tcb->RcvWl2 + Tcb->RcvWnd);\r
}\r
\r
/**\r
Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
Seg = TCPSEG_NETBUF (Nbuf);\r
\r
- ASSERT (TcpVerifySegment (Nbuf) != 0);\r
+ if (TcpVerifySegment (Nbuf) == 0) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "TcpToSendData: discard a broken segment for TCB %p\n",\r
+ Tcb)\r
+ );\r
+ NetbufFree (Nbuf);\r
+ return -1;\r
+ }\r
+ \r
ASSERT (Nbuf->Tcp == NULL);\r
\r
if (TCP_SEQ_GT (Seg->Seq, Seq)) {\r
}\r
\r
DEBUG (\r
- (EFI_D_INFO,\r
+ (EFI_D_NET,\r
"TcpDeliverData: processing FIN from peer of TCB %p\n",\r
Tcb)\r
);\r
@param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
@param[in] Nbuf Pointer to the buffer containing the data to be queued.\r
\r
+ @retval 0 An error condition occurred.\r
+ @retval 1 No error occurred to queue data.\r
+\r
**/\r
-VOID\r
+INTN\r
TcpQueueData (\r
IN OUT TCP_CB *Tcb,\r
IN NET_BUF *Nbuf\r
if (IsListEmpty (Head)) {\r
\r
InsertTailList (Head, &Nbuf->List);\r
- return;\r
+ return 1;\r
}\r
\r
//\r
if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->End)) {\r
\r
if (TCP_SEQ_LEQ (Seg->End, TCPSEG_NETBUF (Node)->End)) {\r
-\r
- NetbufFree (Nbuf);\r
- return;\r
+ return 1;\r
}\r
\r
- TcpTrimSegment (Nbuf, TCPSEG_NETBUF (Node)->End, Seg->End);\r
+ if (TcpTrimSegment (Nbuf, TCPSEG_NETBUF (Node)->End, Seg->End) == 0) {\r
+ return 0;\r
+ }\r
}\r
}\r
\r
if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->Seq, Seg->Seq)) {\r
\r
RemoveEntryList (&Nbuf->List);\r
- NetbufFree (Nbuf);\r
- return;\r
+ return 1;\r
}\r
\r
- TcpTrimSegment (Nbuf, Seg->Seq, TCPSEG_NETBUF (Node)->Seq);\r
+ if (TcpTrimSegment (Nbuf, Seg->Seq, TCPSEG_NETBUF (Node)->Seq) == 0) {\r
+ RemoveEntryList (&Nbuf->List);\r
+ return 0;\r
+ }\r
break;\r
}\r
\r
Cur = Cur->ForwardLink;\r
}\r
+\r
+ return 1;\r
}\r
\r
\r
@param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
@param[in] Ack The acknowledge seuqence number of the received segment.\r
\r
+ @retval 0 An error condition occurred.\r
+ @retval 1 No error occurred.\r
+\r
**/\r
-VOID\r
+INTN\r
TcpAdjustSndQue (\r
IN TCP_CB *Tcb,\r
IN TCP_SEQNO Ack\r
continue;\r
}\r
\r
- TcpTrimSegment (Node, Ack, Seg->End);\r
- break;\r
+ return TcpTrimSegment (Node, Ack, Seg->End);\r
}\r
+\r
+ return 1;\r
}\r
\r
/**\r
TCP_SEQNO Right;\r
TCP_SEQNO Urg;\r
UINT16 Checksum;\r
+ INT32 Usable;\r
\r
ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));\r
\r
ASSERT (Head != NULL);\r
\r
if (Nbuf->TotalSize < sizeof (TCP_HEAD)) {\r
- DEBUG ((EFI_D_INFO, "TcpInput: received a malformed packet\n"));\r
+ DEBUG ((EFI_D_NET, "TcpInput: received a malformed packet\n"));\r
goto DISCARD;\r
}\r
\r
\r
if ((Head->HeadLen < 5) || (Len < 0)) {\r
\r
- DEBUG ((EFI_D_INFO, "TcpInput: received a malformed packet\n"));\r
+ DEBUG ((EFI_D_NET, "TcpInput: received a malformed packet\n"));\r
\r
goto DISCARD;\r
}\r
);\r
\r
if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {\r
- DEBUG ((EFI_D_INFO, "TcpInput: send reset because no TCB found\n"));\r
+ DEBUG ((EFI_D_NET, "TcpInput: send reset because no TCB found\n"));\r
\r
Tcb = NULL;\r
goto SEND_RESET;\r
}\r
\r
DEBUG (\r
- (EFI_D_INFO,\r
+ (EFI_D_NET,\r
"TcpInput: create a child for TCB %p in listening\n",\r
Tcb)\r
);\r
\r
TcpSetState (Tcb, TCP_SYN_RCVD);\r
TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
- TcpTrimInWnd (Tcb, Nbuf);\r
+ if (TcpTrimInWnd (Tcb, Nbuf) == 0) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "TcpInput: discard a broken segment for TCB %p\n",\r
+ Tcb)\r
+ );\r
+\r
+ goto DISCARD;\r
+ }\r
\r
goto StepSix;\r
}\r
TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
}\r
\r
- TcpTrimInWnd (Tcb, Nbuf);\r
+ if (TcpTrimInWnd (Tcb, Nbuf) == 0) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "TcpInput: discard a broken segment for TCB %p\n",\r
+ Tcb)\r
+ );\r
+\r
+ goto DISCARD;\r
+ }\r
\r
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
\r
DEBUG (\r
- (EFI_D_INFO,\r
+ (EFI_D_NET,\r
"TcpInput: connection established for TCB %p in SYN_SENT\n",\r
Tcb)\r
);\r
TcpSetState (Tcb, TCP_SYN_RCVD);\r
\r
ASSERT (Tcb->SndNxt == Tcb->Iss + 1);\r
- TcpAdjustSndQue (Tcb, Tcb->SndNxt);\r
\r
- TcpTrimInWnd (Tcb, Nbuf);\r
+ if (TcpAdjustSndQue (Tcb, Tcb->SndNxt) == 0 || TcpTrimInWnd (Tcb, Nbuf) == 0) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "TcpInput: discard a broken segment for TCB %p\n",\r
+ Tcb)\r
+ );\r
+\r
+ goto DISCARD;\r
+ }\r
\r
DEBUG (\r
(EFI_D_WARN,\r
//\r
// Trim the data and flags.\r
//\r
- TcpTrimInWnd (Tcb, Nbuf);\r
+ if (TcpTrimInWnd (Tcb, Nbuf) == 0) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "TcpInput: discard a broken segment for TCB %p\n",\r
+ Tcb)\r
+ );\r
+\r
+ goto DISCARD;\r
+ }\r
\r
//\r
// Third step: Check security and precedence, Ignored\r
TcpDeliverData (Tcb);\r
\r
DEBUG (\r
- (EFI_D_INFO,\r
+ (EFI_D_NET,\r
"TcpInput: connection established for TCB %p in SYN_RCVD\n",\r
Tcb)\r
);\r
\r
if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
\r
- TcpAdjustSndQue (Tcb, Seg->Ack);\r
+ if (TcpAdjustSndQue (Tcb, Seg->Ack) == 0) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "TcpInput: discard a broken segment for TCB %p\n",\r
+ Tcb)\r
+ );\r
+\r
+ goto DISCARD;\r
+ }\r
+ \r
Tcb->SndUna = Seg->Ack;\r
\r
if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&\r
}\r
\r
if (TCP_SEQ_LT (Right, Tcb->SndNxt)) {\r
-\r
- Tcb->SndNxt = Right;\r
-\r
+ //\r
+ // Check for Window Retraction in RFC7923 section 2.4.\r
+ // The lower n bits of the peer's actual receive window is wiped out if TCP\r
+ // window scale is enabled, it will look like the peer is shrinking the window.\r
+ // Check whether the SndNxt is out of the advertised receive window by more than\r
+ // 2^Rcv.Wind.Shift before moving the SndNxt to the left.\r
+ //\r
+ DEBUG (\r
+ (EFI_D_WARN,\r
+ "TcpInput: peer advise negative useable window for connected TCB %p\n",\r
+ Tcb)\r
+ );\r
+ Usable = TCP_SUB_SEQ (Tcb->SndNxt, Right);\r
+ if ((Usable >> Tcb->SndWndScale) > 0) {\r
+ DEBUG (\r
+ (EFI_D_WARN,\r
+ "TcpInput: SndNxt is out of window by more than window scale for TCB %p\n",\r
+ Tcb)\r
+ );\r
+ Tcb->SndNxt = Right;\r
+ }\r
if (Right == Tcb->SndUna) {\r
\r
TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
{\r
\r
DEBUG (\r
- (EFI_D_INFO,\r
+ (EFI_D_NET,\r
"TcpInput: local FIN is ACKed by peer for connected TCB %p\n",\r
Tcb)\r
);\r
if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) && !TCP_FIN_RCVD (Tcb->State)) {\r
\r
DEBUG (\r
- (EFI_D_INFO,\r
+ (EFI_D_NET,\r
"TcpInput: received urgent data from peer for connected TCB %p\n",\r
Tcb)\r
);\r
goto RESET_THEN_DROP;\r
}\r
\r
- TcpQueueData (Tcb, Nbuf);\r
+ if (TcpQueueData (Tcb, Nbuf) == 0) {\r
+ DEBUG (\r
+ (EFI_D_ERROR,\r
+ "TcpInput: discard a broken segment for TCB %p\n",\r
+ Tcb)\r
+ );\r
+\r
+ goto DISCARD;\r
+ }\r
+ \r
if (TcpDeliverData (Tcb) == -1) {\r
goto RESET_THEN_DROP;\r
}\r