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