--- /dev/null
+/** @file\r
+ IP4 option support functions.\r
+\r
+Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\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.\r
+\r
+ @param[in] Option The first byte of the option\r
+ @param[in] OptionLen The length of the whole option\r
+ @param[in] Rcvd The option is from the packet we received if TRUE,\r
+ otherwise the option we wants to transmit.\r
+\r
+ @retval TRUE The option is properly formatted\r
+ @retval 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
+\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 formatted as |Type|Len|Point|Ip1|Ip2|...\r
+ //\r
+ if ((OptionLen - Cur < Len) || (Len < 3) || ((Len - 3) % 4 != 0)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if ((Point > Len + 1) || (Point % 4 != 0)) {\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
+ 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
+ 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 aligned to 4 bytes.\r
+\r
+ @param[in] Option The original option to copy from\r
+ @param[in] OptionLen The length of the original option\r
+ @param[in] FirstFragment Whether it is the first fragment\r
+ @param[in, out] Buf The buffer to copy options to. NULL\r
+ @param[in, out] BufLen The length of the buffer\r
+\r
+ @retval EFI_SUCCESS The options are copied over\r
+ @retval EFI_BUFFER_TOO_SMALL Buf is NULL or BufLen 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 OUT 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) != 0) {\r
+ CopyMem (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
+ ZeroMem (Buf, Len);\r
+ CopyMem (Buf, OptBuf, Next);\r
+ *BufLen = Len;\r
+ return EFI_SUCCESS;\r
+}\r