Ip4Option.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /** @file
  2. IP4 option support functions.
  3. Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "Ip4Impl.h"
  7. /**
  8. Validate the IP4 option format for both the packets we received
  9. and will transmit.
  10. @param[in] Option The first byte of the option
  11. @param[in] OptionLen The length of the whole option
  12. @param[in] Rcvd The option is from the packet we received if TRUE,
  13. otherwise the option we wants to transmit.
  14. @retval TRUE The option is properly formatted
  15. @retval FALSE The option is malformatted
  16. **/
  17. BOOLEAN
  18. Ip4OptionIsValid (
  19. IN UINT8 *Option,
  20. IN UINT32 OptionLen,
  21. IN BOOLEAN Rcvd
  22. )
  23. {
  24. UINT32 Cur;
  25. UINT32 Len;
  26. UINT32 Point;
  27. Cur = 0;
  28. while (Cur < OptionLen) {
  29. switch (Option[Cur]) {
  30. case IP4_OPTION_NOP:
  31. Cur++;
  32. break;
  33. case IP4_OPTION_EOP:
  34. Cur = OptionLen;
  35. break;
  36. case IP4_OPTION_LSRR:
  37. case IP4_OPTION_SSRR:
  38. case IP4_OPTION_RR:
  39. Len = Option[Cur + 1];
  40. Point = Option[Cur + 2];
  41. //
  42. // SRR/RR options are formatted as |Type|Len|Point|Ip1|Ip2|...
  43. //
  44. if ((OptionLen - Cur < Len) || (Len < 3) || ((Len - 3) % 4 != 0)) {
  45. return FALSE;
  46. }
  47. if ((Point > Len + 1) || (Point % 4 != 0)) {
  48. return FALSE;
  49. }
  50. //
  51. // The Point must point pass the last entry if the packet is received
  52. // by us. It must point to 4 if the packet is to be sent by us for
  53. // source route option.
  54. //
  55. if ((Option[Cur] != IP4_OPTION_RR) &&
  56. ((Rcvd && (Point != Len + 1)) || (!Rcvd && (Point != 4))))
  57. {
  58. return FALSE;
  59. }
  60. Cur += Len;
  61. break;
  62. default:
  63. Len = Option[Cur + 1];
  64. if ((OptionLen - Cur < Len) || (Len < 2)) {
  65. return FALSE;
  66. }
  67. Cur = Cur + Len;
  68. break;
  69. }
  70. }
  71. return TRUE;
  72. }
  73. /**
  74. Copy the option from the original option to buffer. It
  75. handles the details such as:
  76. 1. whether copy the single IP4 option to the first/non-first
  77. fragments.
  78. 2. Pad the options copied over to aligned to 4 bytes.
  79. @param[in] Option The original option to copy from
  80. @param[in] OptionLen The length of the original option
  81. @param[in] FirstFragment Whether it is the first fragment
  82. @param[in, out] Buf The buffer to copy options to. NULL
  83. @param[in, out] BufLen The length of the buffer
  84. @retval EFI_SUCCESS The options are copied over
  85. @retval EFI_BUFFER_TOO_SMALL Buf is NULL or BufLen provided is too small.
  86. **/
  87. EFI_STATUS
  88. Ip4CopyOption (
  89. IN UINT8 *Option,
  90. IN UINT32 OptionLen,
  91. IN BOOLEAN FirstFragment,
  92. IN OUT UINT8 *Buf OPTIONAL,
  93. IN OUT UINT32 *BufLen
  94. )
  95. {
  96. UINT8 OptBuf[40];
  97. UINT32 Cur;
  98. UINT32 Next;
  99. UINT8 Type;
  100. UINT32 Len;
  101. ASSERT ((BufLen != NULL) && (OptionLen <= 40));
  102. Cur = 0;
  103. Next = 0;
  104. while (Cur < OptionLen) {
  105. Type = Option[Cur];
  106. Len = Option[Cur + 1];
  107. if (Type == IP4_OPTION_NOP) {
  108. //
  109. // Keep the padding, in case that the sender wants to align
  110. // the option, say, to 4 bytes
  111. //
  112. OptBuf[Next] = IP4_OPTION_NOP;
  113. Next++;
  114. Cur++;
  115. } else if (Type == IP4_OPTION_EOP) {
  116. //
  117. // Don't append the EOP to avoid including only a EOP option
  118. //
  119. break;
  120. } else {
  121. //
  122. // don't copy options that is only valid for the first fragment
  123. //
  124. if (FirstFragment || ((Type & IP4_OPTION_COPY_MASK) != 0)) {
  125. CopyMem (OptBuf + Next, Option + Cur, Len);
  126. Next += Len;
  127. }
  128. Cur += Len;
  129. }
  130. }
  131. //
  132. // Don't append an EOP only option.
  133. //
  134. if (Next == 0) {
  135. *BufLen = 0;
  136. return EFI_SUCCESS;
  137. }
  138. //
  139. // Append an EOP if the end of option doesn't coincide with the
  140. // end of the IP header, that is, isn't aligned to 4 bytes..
  141. //
  142. if ((Next % 4) != 0) {
  143. OptBuf[Next] = IP4_OPTION_EOP;
  144. Next++;
  145. }
  146. //
  147. // Head length is in the unit of 4 bytes. Now, Len is the
  148. // actual option length to appear in the IP header.
  149. //
  150. Len = ((Next + 3) &~0x03);
  151. //
  152. // If the buffer is too small, set the BufLen then return
  153. //
  154. if ((Buf == NULL) || (*BufLen < Len)) {
  155. *BufLen = Len;
  156. return EFI_BUFFER_TOO_SMALL;
  157. }
  158. //
  159. // Copy the option to the Buf, zero the buffer first to pad
  160. // the options with NOP to align to 4 bytes.
  161. //
  162. ZeroMem (Buf, Len);
  163. CopyMem (Buf, OptBuf, Next);
  164. *BufLen = Len;
  165. return EFI_SUCCESS;
  166. }