]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Option.c
Import SnpDxe, Tcp4Dxe, Udp4Dxe and MnpDxe.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / Tcp4Option.c
diff --git a/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Option.c b/MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Option.c
new file mode 100644 (file)
index 0000000..d430a2e
--- /dev/null
@@ -0,0 +1,380 @@
+/** @file\r
+\r
+Copyright (c) 2005 - 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  Tcp4Option.c\r
+\r
+Abstract:\r
+\r
+  Routines to process TCP option.\r
+\r
+\r
+**/\r
+\r
+#include "Tcp4Main.h"\r
+\r
+STATIC\r
+UINT16\r
+TcpGetUint16 (\r
+  IN UINT8 *Buf\r
+  )\r
+{\r
+  UINT16  Value;\r
+  NetCopyMem (&Value, Buf, sizeof (UINT16));\r
+  return NTOHS (Value);\r
+}\r
+\r
+STATIC\r
+VOID\r
+TcpPutUint16 (\r
+  IN UINT8  *Buf,\r
+  IN UINT16 Data\r
+  )\r
+{\r
+  Data = HTONS (Data);\r
+  NetCopyMem (Buf, &Data, sizeof (UINT16));\r
+}\r
+\r
+STATIC\r
+UINT32\r
+TcpGetUint32 (\r
+  IN UINT8 *Buf\r
+  )\r
+{\r
+  UINT32  Value;\r
+  NetCopyMem (&Value, Buf, sizeof (UINT32));\r
+  return NTOHL (Value);\r
+}\r
+\r
+STATIC\r
+VOID\r
+TcpPutUint32 (\r
+  IN UINT8  *Buf,\r
+  IN UINT32 Data\r
+  )\r
+{\r
+  Data = HTONL (Data);\r
+  NetCopyMem (Buf, &Data, sizeof (UINT32));\r
+}\r
+\r
+\r
+/**\r
+  Compute the window scale value according to the given\r
+  buffer size.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+\r
+  @retval UINT8   The scale value.\r
+\r
+**/\r
+UINT8\r
+TcpComputeScale (\r
+  IN TCP_CB *Tcb\r
+  )\r
+{\r
+  UINT8   Scale;\r
+  UINT32  BufSize;\r
+\r
+  ASSERT (Tcb && Tcb->Sk);\r
+\r
+  BufSize = GET_RCV_BUFFSIZE (Tcb->Sk);\r
+\r
+  Scale   = 0;\r
+  while ((Scale < TCP_OPTION_MAX_WS) &&\r
+         ((UINT32) (TCP_OPTION_MAX_WIN << Scale) < BufSize)) {\r
+\r
+    Scale++;\r
+  }\r
+\r
+  return Scale;\r
+}\r
+\r
+\r
+/**\r
+  Build the TCP option in three-way handshake.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Nbuf    Pointer to the buffer to store the options.\r
+\r
+  @return The total length of the TCP option field.\r
+\r
+**/\r
+UINT16\r
+TcpSynBuildOption (\r
+  IN TCP_CB  *Tcb,\r
+  IN NET_BUF *Nbuf\r
+  )\r
+{\r
+  char    *Data;\r
+  UINT16  Len;\r
+\r
+  ASSERT (Tcb && Nbuf && !Nbuf->Tcp);\r
+\r
+  Len = 0;\r
+\r
+  //\r
+  // Add timestamp option if not disabled by application\r
+  // and it is the first SYN segment or the peer has sent\r
+  // us its timestamp.\r
+  //\r
+  if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS) &&\r
+      (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||\r
+      TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS))) {\r
+\r
+    Data = NetbufAllocSpace (\r
+            Nbuf,\r
+            TCP_OPTION_TS_ALIGNED_LEN,\r
+            NET_BUF_HEAD\r
+            );\r
+\r
+    ASSERT (Data);\r
+    Len += TCP_OPTION_TS_ALIGNED_LEN;\r
+\r
+    TcpPutUint32 (Data, TCP_OPTION_TS_FAST);\r
+    TcpPutUint32 (Data + 4, mTcpTick);\r
+    TcpPutUint32 (Data + 8, 0);\r
+  }\r
+\r
+  //\r
+  // Build window scale option, only when are configured\r
+  // to send WS option, and either we are doing active\r
+  // open or we have received WS option from peer.\r
+  //\r
+  if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS) &&\r
+      (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||\r
+      TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS))) {\r
+\r
+    Data = NetbufAllocSpace (\r
+            Nbuf,\r
+            TCP_OPTION_WS_ALIGNED_LEN,\r
+            NET_BUF_HEAD\r
+            );\r
+\r
+    ASSERT (Data);\r
+\r
+    Len += TCP_OPTION_WS_ALIGNED_LEN;\r
+    TcpPutUint32 (Data, TCP_OPTION_WS_FAST | TcpComputeScale (Tcb));\r
+  }\r
+\r
+  //\r
+  // Build MSS option\r
+  //\r
+  Data = NetbufAllocSpace (Nbuf, TCP_OPTION_MSS_LEN, 1);\r
+  ASSERT (Data);\r
+\r
+  Len += TCP_OPTION_MSS_LEN;\r
+  TcpPutUint32 (Data, TCP_OPTION_MSS_FAST | Tcb->RcvMss);\r
+\r
+  return Len;\r
+}\r
+\r
+\r
+/**\r
+  Build the TCP option in synchronized states.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Nbuf    Pointer to the buffer to store the options.\r
+\r
+  @return The total length of the TCP option field.\r
+\r
+**/\r
+UINT16\r
+TcpBuildOption (\r
+  IN TCP_CB  *Tcb,\r
+  IN NET_BUF *Nbuf\r
+  )\r
+{\r
+  char    *Data;\r
+  UINT16  Len;\r
+\r
+  ASSERT (Tcb && Nbuf && !Nbuf->Tcp);\r
+  Len = 0;\r
+\r
+  //\r
+  // Build Timestamp option\r
+  //\r
+  if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_TS) &&\r
+      !TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_RST)) {\r
+\r
+    Data = NetbufAllocSpace (\r
+            Nbuf,\r
+            TCP_OPTION_TS_ALIGNED_LEN,\r
+            NET_BUF_HEAD\r
+            );\r
+\r
+    ASSERT (Data);\r
+    Len += TCP_OPTION_TS_ALIGNED_LEN;\r
+\r
+    TcpPutUint32 (Data, TCP_OPTION_TS_FAST);\r
+    TcpPutUint32 (Data + 4, mTcpTick);\r
+    TcpPutUint32 (Data + 8, Tcb->TsRecent);\r
+  }\r
+\r
+  return Len;\r
+}\r
+\r
+\r
+/**\r
+  Parse the supported options.\r
+\r
+  @param  Tcp     Pointer to the TCP_CB of this TCP instance.\r
+  @param  Option  Pointer to the TCP_OPTION used to store the successfully pasrsed\r
+                  options.\r
+\r
+  @retval 0       The options are successfully pasrsed.\r
+  @retval -1      Ilegal option was found.\r
+\r
+**/\r
+INTN\r
+TcpParseOption (\r
+  IN TCP_HEAD   *Tcp,\r
+  IN TCP_OPTION *Option\r
+  )\r
+{\r
+  UINT8 *Head;\r
+  UINT8 TotalLen;\r
+  UINT8 Cur;\r
+  UINT8 Type;\r
+  UINT8 Len;\r
+\r
+  ASSERT (Tcp && Option);\r
+\r
+  Option->Flag  = 0;\r
+\r
+  TotalLen      = (Tcp->HeadLen << 2) - sizeof (TCP_HEAD);\r
+  if (TotalLen <= 0) {\r
+    return 0;\r
+  }\r
+\r
+  Head = (UINT8 *) (Tcp + 1);\r
+\r
+  //\r
+  // Fast process of timestamp option\r
+  //\r
+  if ((TotalLen == TCP_OPTION_TS_ALIGNED_LEN) &&\r
+      (TcpGetUint32 (Head) == TCP_OPTION_TS_FAST)) {\r
+\r
+    Option->TSVal = TcpGetUint32 (Head + 4);\r
+    Option->TSEcr = TcpGetUint32 (Head + 8);\r
+    Option->Flag  = TCP_OPTION_RCVD_TS;\r
+\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Slow path to process the options.\r
+  //\r
+  Cur = 0;\r
+\r
+  while (Cur < TotalLen) {\r
+    Type = Head[Cur];\r
+\r
+    switch (Type) {\r
+    case TCP_OPTION_MSS:\r
+      Len = Head[Cur + 1];\r
+\r
+      if ((Len != TCP_OPTION_MSS_LEN) ||\r
+          (TotalLen - Cur < TCP_OPTION_MSS_LEN)) {\r
+\r
+        return -1;\r
+      }\r
+\r
+      Option->Mss = TcpGetUint16 (&Head[Cur + 2]);\r
+      TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_MSS);\r
+\r
+      Cur += TCP_OPTION_MSS_LEN;\r
+      break;\r
+\r
+    case TCP_OPTION_WS:\r
+      Len = Head[Cur + 1];\r
+\r
+      if ((Len != TCP_OPTION_WS_LEN) ||\r
+          (TotalLen - Cur < TCP_OPTION_WS_LEN)) {\r
+\r
+        return -1;\r
+      }\r
+\r
+      Option->WndScale = NET_MIN (14, Head[Cur + 2]);\r
+      TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_WS);\r
+\r
+      Cur += TCP_OPTION_WS_LEN;\r
+      break;\r
+\r
+    case TCP_OPTION_TS:\r
+      Len = Head[Cur + 1];\r
+\r
+      if ((Len != TCP_OPTION_TS_LEN) ||\r
+          (TotalLen - Cur < TCP_OPTION_TS_LEN)) {\r
+\r
+        return -1;\r
+      }\r
+\r
+      Option->TSVal = TcpGetUint32 (&Head[Cur + 2]);\r
+      Option->TSEcr = TcpGetUint32 (&Head[Cur + 6]);\r
+      TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_TS);\r
+\r
+      Cur += TCP_OPTION_TS_LEN;\r
+      break;\r
+\r
+    case TCP_OPTION_NOP:\r
+      Cur++;\r
+      break;\r
+\r
+    case TCP_OPTION_EOP:\r
+      Cur = TotalLen;\r
+      break;\r
+\r
+    default:\r
+      Len = Head[Cur + 1];\r
+\r
+      if (TotalLen - Cur < Len || Len < 2) {\r
+        return -1;\r
+      }\r
+\r
+      Cur = Cur + Len;\r
+      break;\r
+    }\r
+\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+\r
+/**\r
+  Check the segment against PAWS.\r
+\r
+  @param  Tcb     Pointer to the TCP_CB of this TCP instance.\r
+  @param  TSVal   The timestamp value.\r
+\r
+  @retval 1       The segment passed the PAWS check.\r
+  @retval 0       The segment failed to pass the PAWS check.\r
+\r
+**/\r
+UINT32\r
+TcpPawsOK (\r
+  IN TCP_CB *Tcb,\r
+  IN UINT32 TSVal\r
+  )\r
+{\r
+  //\r
+  // PAWS as defined in RFC1323, buggy...\r
+  //\r
+  if (TCP_TIME_LT (TSVal, Tcb->TsRecent) &&\r
+      TCP_TIME_LT (Tcb->TsRecentAge + TCP_PAWS_24DAY, mTcpTick)) {\r
+\r
+    return 0;\r
+\r
+  }\r
+\r
+  return 1;\r
+}\r