]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Option.c
Import ArpDxe, Dhcp4Dxe, Ip4Dxe, Mtftp4Dxe, PxeBcDxe and PxeDhcp4Dxe.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Option.c
diff --git a/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Option.c b/MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Option.c
new file mode 100644 (file)
index 0000000..e1f059e
--- /dev/null
@@ -0,0 +1,231 @@
+/** @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
+  Ip4Option.c\r
+\r
+Abstract:\r
+\r
+  IP4 option support functions\r
+\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+\r
+/**\r
+  Validate the IP4 option format for both the packets we received\r
+  and will transmit. It will compute the ICMP error message fields\r
+  if the option is mal-formated. But this information isn't used.\r
+\r
+  @param  Option                The first byte of the option\r
+  @param  OptionLen             The length of the whole option\r
+  @param  Rcvd                  The option is from the packet we received if TRUE,\r
+                                otherwise the option we wants to transmit.\r
+\r
+  @return TRUE:  The option is properly formated\r
+  @return FALSE: The option is mal-formated\r
+\r
+**/\r
+BOOLEAN\r
+Ip4OptionIsValid (\r
+  IN UINT8                  *Option,\r
+  IN UINT32                 OptionLen,\r
+  IN BOOLEAN                Rcvd\r
+  )\r
+{\r
+  UINT32                    Cur;\r
+  UINT32                    Len;\r
+  UINT32                    Point;\r
+  UINT8                     IcmpType;\r
+  UINT8                     IcmpCode;\r
+  UINT32                    IcmpPoint;\r
+\r
+  IcmpType  = ICMP_PARAMETER_PROBLEM;\r
+  IcmpCode  = 0;\r
+  IcmpPoint = 0;\r
+\r
+  Cur       = 0;\r
+\r
+  while (Cur < OptionLen) {\r
+    switch (Option[Cur]) {\r
+    case IP4_OPTION_NOP:\r
+      Cur++;\r
+      break;\r
+\r
+    case IP4_OPTION_EOP:\r
+      Cur = OptionLen;\r
+      break;\r
+\r
+    case IP4_OPTION_LSRR:\r
+    case IP4_OPTION_SSRR:\r
+    case IP4_OPTION_RR:\r
+      Len   = Option[Cur + 1];\r
+      Point = Option[Cur + 2];\r
+\r
+      //\r
+      // SRR/RR options are formated as |Type|Len|Point|Ip1|Ip2|...\r
+      //\r
+      if ((OptionLen - Cur < Len) || (Len < 3) || ((Len - 3) % 4 != 0)) {\r
+        IcmpPoint = Cur + 1;\r
+        return FALSE;\r
+      }\r
+\r
+      if ((Point > Len + 1) || (Point % 4 != 0)) {\r
+        IcmpPoint = Cur + 2;\r
+        return FALSE;\r
+      }\r
+\r
+      //\r
+      // The Point must point pass the last entry if the packet is received\r
+      // by us. It must point to 4 if the packet is to be sent by us for\r
+      // source route option.\r
+      //\r
+      if ((Option[Cur] != IP4_OPTION_RR) &&\r
+          ((Rcvd && (Point != Len + 1)) || (!Rcvd && (Point != 4)))) {\r
+\r
+        IcmpType  = ICMP_DEST_UNREACHABLE;\r
+        IcmpCode  = ICMP_SOURCEROUTE_FAILED;\r
+        return FALSE;\r
+      }\r
+\r
+      Cur += Len;\r
+      break;\r
+\r
+    default:\r
+      Len = Option[Cur + 1];\r
+\r
+      if ((OptionLen - Cur < Len) || (Len < 2)) {\r
+        IcmpPoint = Cur + 1;\r
+        return FALSE;\r
+      }\r
+\r
+      Cur = Cur + Len;\r
+      break;\r
+    }\r
+\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Copy the option from the original option to buffer. It\r
+  handles the details such as:\r
+  1. whether copy the single IP4 option to the first/non-first\r
+  fragments.\r
+  2. Pad the options copied over to aligened to 4 bytes.\r
+\r
+  @param  Option                The original option to copy from\r
+  @param  OptionLen             The length of the original option\r
+  @param  FirstFragment         Whether it is the first fragment\r
+  @param  Buf                   The buffer to copy options to\r
+  @param  BufLen                The length of the buffer\r
+\r
+  @retval EFI_SUCCESS           The options are copied over\r
+  @retval EFI_BUFFER_TOO_SMALL  The buffer caller provided is too small.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4CopyOption (\r
+  IN UINT8                  *Option,\r
+  IN UINT32                 OptionLen,\r
+  IN BOOLEAN                FirstFragment,\r
+  IN UINT8                  *Buf,           OPTIONAL\r
+  IN OUT UINT32             *BufLen\r
+  )\r
+{\r
+  UINT8                     OptBuf[40];\r
+  UINT32                    Cur;\r
+  UINT32                    Next;\r
+  UINT8                     Type;\r
+  UINT32                    Len;\r
+\r
+  ASSERT ((BufLen != NULL) && (OptionLen <= 40));\r
+\r
+  Cur   = 0;\r
+  Next  = 0;\r
+\r
+  while (Cur < OptionLen) {\r
+    Type  = Option[Cur];\r
+    Len   = Option[Cur + 1];\r
+\r
+    if (Type == IP4_OPTION_NOP) {\r
+      //\r
+      // Keep the padding, in case that the sender wants to align\r
+      // the option, say, to 4 bytes\r
+      //\r
+      OptBuf[Next] = IP4_OPTION_NOP;\r
+      Next++;\r
+      Cur++;\r
+\r
+    } else if (Type == IP4_OPTION_EOP) {\r
+      //\r
+      // Don't append the EOP to avoid including only a EOP option\r
+      //\r
+      break;\r
+\r
+    } else {\r
+      //\r
+      // don't copy options that is only valid for the first fragment\r
+      //\r
+      if (FirstFragment || (Type & IP4_OPTION_COPY_MASK)) {\r
+        NetCopyMem (OptBuf + Next, Option + Cur, Len);\r
+        Next += Len;\r
+      }\r
+\r
+      Cur += Len;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Don't append an EOP only option.\r
+  //\r
+  if (Next == 0) {\r
+    *BufLen = 0;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Append an EOP if the end of option doesn't coincide with the\r
+  // end of the IP header, that is, isn't aligned to 4 bytes..\r
+  //\r
+  if ((Next % 4) != 0) {\r
+    OptBuf[Next] = IP4_OPTION_EOP;\r
+    Next++;\r
+  }\r
+\r
+  //\r
+  // Head length is in the unit of 4 bytes. Now, Len is the\r
+  // acutal option length to appear in the IP header.\r
+  //\r
+  Len = ((Next + 3) &~0x03);\r
+\r
+  //\r
+  // If the buffer is too small, set the BufLen then return\r
+  //\r
+  if ((Buf == NULL) || (*BufLen < Len)) {\r
+    *BufLen = Len;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  //\r
+  // Copy the option to the Buf, zero the buffer first to pad\r
+  // the options with NOP to align to 4 bytes.\r
+  //\r
+  NetZeroMem (Buf, Len);\r
+  NetCopyMem (Buf, OptBuf, Next);\r
+  *BufLen = Len;\r
+  return EFI_SUCCESS;\r
+}\r