/** @file\r
TCP input process routines.\r
\r
- Copyright (c) 2009 - 2010, 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
IN TCP_SEG *Seg\r
)\r
{\r
- return (TCP_SEQ_LEQ (Tcb->RcvWl2, Seg->End) &&\r
+ return (TCP_SEQ_LEQ (Tcb->RcvNxt, Seg->End) &&\r
TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2 + Tcb->RcvWnd));\r
}\r
\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
}\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
Urgent = 0;\r
\r
if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&\r
- TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvUp)\r
- ) {\r
+ TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvUp))\r
+ {\r
\r
if (TCP_SEQ_LEQ (Seg->End, Tcb->RcvUp)) {\r
Urgent = Nbuf->TotalSize;\r
//\r
for (Prev = Head, Cur = Head->ForwardLink;\r
Cur != Head;\r
- Prev = Cur, Cur = Cur->ForwardLink\r
- ) {\r
+ Prev = Cur, Cur = Cur->ForwardLink) {\r
\r
Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\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
\r
Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
ASSERT (Head != NULL);\r
+ \r
+ if (Nbuf->TotalSize < sizeof (TCP_HEAD)) {\r
+ DEBUG ((EFI_D_NET, "TcpInput: received a malformed packet\n"));\r
+ goto DISCARD;\r
+ }\r
+ \r
Len = Nbuf->TotalSize - (Head->HeadLen << 2);\r
\r
if ((Head->HeadLen < 5) || (Len < 0)) {\r
\r
- DEBUG ((EFI_D_INFO, "TcpInput: received an mal-formated packet\n"));\r
+ DEBUG ((EFI_D_NET, "TcpInput: received a malformed packet\n"));\r
+ \r
goto DISCARD;\r
}\r
\r
);\r
\r
if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {\r
- DEBUG ((EFI_D_INFO, "TcpInput: send reset because no TCB find\n"));\r
+ DEBUG ((EFI_D_NET, "TcpInput: send reset because no TCB found\n"));\r
\r
Tcb = NULL;\r
goto SEND_RESET;\r
if (TcpParseOption (Nbuf->Tcp, &Option) == -1) {\r
DEBUG (\r
(EFI_D_ERROR,\r
- "TcpInput: reset the peer because of mal-format option for Tcb %p\n",\r
+ "TcpInput: reset the peer because of malformed option for TCB %p\n",\r
Tcb)\r
);\r
\r
if (Tcb == NULL) {\r
DEBUG (\r
(EFI_D_ERROR,\r
- "TcpInput: discard a segment because failed to clone a child for TCB%p\n",\r
+ "TcpInput: discard a segment because failed to clone a child for TCB %p\n",\r
Tcb)\r
);\r
\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
\r
//\r
- // Fourth step: Check SYN. Pay attention to sitimulatous open\r
+ // Fourth step: Check SYN. Pay attention to simultaneous open\r
//\r
if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
\r
TcpDeliverData (Tcb);\r
\r
if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&\r
- TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)\r
- ) {\r
+ TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON))\r
+ {\r
\r
TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\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
\r
DEBUG (\r
(EFI_D_WARN,\r
- "TcpInput: simultanous open for TCB %p in SYN_SENT\n",\r
+ "TcpInput: simultaneous open for TCB %p in SYN_SENT\n",\r
Tcb)\r
);\r
\r
\r
if ((TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2)) &&\r
(Tcb->RcvWl2 == Seg->End) &&\r
- !TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN)\r
- ) {\r
+ !TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN))\r
+ {\r
\r
TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
}\r
// if it comes from a LISTEN TCB.\r
//\r
} else if ((Tcb->State == TCP_ESTABLISHED) ||\r
- (Tcb->State == TCP_FIN_WAIT_1) ||\r
- (Tcb->State == TCP_FIN_WAIT_2) ||\r
- (Tcb->State == TCP_CLOSE_WAIT)\r
- ) {\r
+ (Tcb->State == TCP_FIN_WAIT_1) ||\r
+ (Tcb->State == TCP_FIN_WAIT_2) ||\r
+ (Tcb->State == TCP_CLOSE_WAIT))\r
+ {\r
\r
SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
\r
\r
if (Tcb->State == TCP_SYN_RCVD) {\r
\r
- if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) && TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt)) {\r
+ if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) &&\r
+ TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt))\r
+ {\r
\r
Tcb->SndWnd = Seg->Wnd;\r
Tcb->SndWndMax = MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
TcpDeliverData (Tcb);\r
\r
DEBUG (\r
- (EFI_D_INFO,\r
- "TcpInput: connection established for TCB %p in SYN_RCVD\n",\r
+ (EFI_D_NET,\r
+ "TcpInput: connection established for TCB %p in SYN_RCVD\n",\r
Tcb)\r
);\r
\r
// RcvWl2 equals to the variable "LastAckSent"\r
// defined there.\r
//\r
- if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) && TCP_SEQ_LT (Tcb->RcvWl2, Seg->End)) {\r
+ if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) &&\r
+ TCP_SEQ_LT (Tcb->RcvWl2, Seg->End))\r
+ {\r
\r
Tcb->TsRecent = Option.TSVal;\r
Tcb->TsRecentAge = mTcpTick;\r
if ((Seg->Ack == Tcb->SndUna) &&\r
(Tcb->SndUna != Tcb->SndNxt) &&\r
(Seg->Wnd == Tcb->SndWnd) &&\r
- (0 == Len)\r
- ) {\r
+ (0 == Len))\r
+ {\r
\r
Tcb->DupAck++;\r
} else {\r
// Congestion avoidance, fast recovery and fast retransmission.\r
//\r
if (((Tcb->CongestState == TCP_CONGEST_OPEN) && (Tcb->DupAck < 3)) ||\r
- (Tcb->CongestState == TCP_CONGEST_LOSS)\r
- ) {\r
+ (Tcb->CongestState == TCP_CONGEST_LOSS))\r
+ {\r
\r
if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
\r
Tcb->SndUna = Seg->Ack;\r
\r
if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&\r
- TCP_SEQ_LT (Tcb->SndUp, Seg->Ack)\r
- ) {\r
+ TCP_SEQ_LT (Tcb->SndUp, Seg->Ack))\r
+ {\r
\r
TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);\r
}\r
// Update window info\r
//\r
if (TCP_SEQ_LT (Tcb->SndWl1, Seg->Seq) ||\r
- ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack))\r
- ) {\r
+ ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack)))\r
+ {\r
\r
Right = Seg->Ack + Seg->Wnd;\r
\r
\r
if ((Tcb->SndWl1 == Seg->Seq) &&\r
(Tcb->SndWl2 == Seg->Ack) &&\r
- (Len == 0)\r
- ) {\r
+ (Len == 0))\r
+ {\r
\r
goto NO_UPDATE;\r
}\r
Tcb)\r
);\r
\r
- if ((Tcb->CongestState == TCP_CONGEST_RECOVER) && (TCP_SEQ_LT (Right, Tcb->Recover))) {\r
+ if ((Tcb->CongestState == TCP_CONGEST_RECOVER) &&\r
+ (TCP_SEQ_LT (Right, Tcb->Recover)))\r
+ {\r
\r
Tcb->Recover = Right;\r
}\r
\r
- if ((Tcb->CongestState == TCP_CONGEST_LOSS) && (TCP_SEQ_LT (Right, Tcb->LossRecover))) {\r
+ if ((Tcb->CongestState == TCP_CONGEST_LOSS) &&\r
+ (TCP_SEQ_LT (Right, Tcb->LossRecover)))\r
+ {\r
\r
Tcb->LossRecover = Right;\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
NO_UPDATE:\r
\r
- if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) && (Tcb->SndUna == Tcb->SndNxt)) {\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) &&\r
+ (Tcb->SndUna == Tcb->SndNxt))\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
\r
Urg = Seg->Seq + Seg->Urg;\r
\r
- if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) && TCP_SEQ_GT (Urg, Tcb->RcvUp)) {\r
+ if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&\r
+ TCP_SEQ_GT (Urg, Tcb->RcvUp))\r
+ {\r
\r
Tcb->RcvUp = Urg;\r
} else {\r
\r
if ((Tcb->State != TCP_CLOSED) &&\r
(TcpToSendData (Tcb, 0) == 0) &&\r
- (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || (Nbuf->TotalSize != 0))\r
- ) {\r
+ (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || (Nbuf->TotalSize != 0)))\r
+ {\r
\r
TcpToSendAck (Tcb);\r
}\r
BOOLEAN IcmpErrIsHard;\r
BOOLEAN IcmpErrNotify;\r
\r
+ if (Nbuf->TotalSize < sizeof (TCP_HEAD)) {\r
+ goto CLEAN_EXIT;\r
+ }\r
+ \r
Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
ASSERT (Head != NULL);\r
\r
goto CLEAN_EXIT;\r
}\r
\r
- IcmpErrStatus = IpIoGetIcmpErrStatus (IcmpErr, Tcb->Sk->IpVersion, &IcmpErrIsHard, &IcmpErrNotify);\r
+ IcmpErrStatus = IpIoGetIcmpErrStatus (\r
+ IcmpErr,\r
+ Tcb->Sk->IpVersion,\r
+ &IcmpErrIsHard,\r
+ &IcmpErrNotify\r
+ );\r
\r
if (IcmpErrNotify) {\r
\r