a28656c9c6f42ec2331c7d780faa5bbc7ba5a8bf
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Option.c
1 /** @file\r
2 \r
3 Copyright (c) 2005 - 2006, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 Module Name:\r
13 \r
14   Ip4Option.c\r
15 \r
16 Abstract:\r
17 \r
18   IP4 option support functions\r
19 \r
20 \r
21 **/\r
22 \r
23 #include "Ip4Impl.h"\r
24 \r
25 \r
26 /**\r
27   Validate the IP4 option format for both the packets we received\r
28   and will transmit. It will compute the ICMP error message fields\r
29   if the option is mal-formated. But this information isn't used.\r
30 \r
31   @param  Option                The first byte of the option\r
32   @param  OptionLen             The length of the whole option\r
33   @param  Rcvd                  The option is from the packet we received if TRUE,\r
34                                 otherwise the option we wants to transmit.\r
35 \r
36   @return TRUE:  The option is properly formated\r
37   @return FALSE: The option is mal-formated\r
38 \r
39 **/\r
40 BOOLEAN\r
41 Ip4OptionIsValid (\r
42   IN UINT8                  *Option,\r
43   IN UINT32                 OptionLen,\r
44   IN BOOLEAN                Rcvd\r
45   )\r
46 {\r
47   UINT32                    Cur;\r
48   UINT32                    Len;\r
49   UINT32                    Point;\r
50   volatile UINT8            IcmpType;\r
51   volatile UINT8            IcmpCode;\r
52   volatile UINT32           IcmpPoint;\r
53 \r
54   IcmpType  = ICMP_PARAMETER_PROBLEM;\r
55   IcmpCode  = 0;\r
56   IcmpPoint = 0;\r
57 \r
58   Cur       = 0;\r
59 \r
60   while (Cur < OptionLen) {\r
61     switch (Option[Cur]) {\r
62     case IP4_OPTION_NOP:\r
63       Cur++;\r
64       break;\r
65 \r
66     case IP4_OPTION_EOP:\r
67       Cur = OptionLen;\r
68       break;\r
69 \r
70     case IP4_OPTION_LSRR:\r
71     case IP4_OPTION_SSRR:\r
72     case IP4_OPTION_RR:\r
73       Len   = Option[Cur + 1];\r
74       Point = Option[Cur + 2];\r
75 \r
76       //\r
77       // SRR/RR options are formated as |Type|Len|Point|Ip1|Ip2|...\r
78       //\r
79       if ((OptionLen - Cur < Len) || (Len < 3) || ((Len - 3) % 4 != 0)) {\r
80         IcmpPoint = Cur + 1;\r
81         return FALSE;\r
82       }\r
83 \r
84       if ((Point > Len + 1) || (Point % 4 != 0)) {\r
85         IcmpPoint = Cur + 2;\r
86         return FALSE;\r
87       }\r
88 \r
89       //\r
90       // The Point must point pass the last entry if the packet is received\r
91       // by us. It must point to 4 if the packet is to be sent by us for\r
92       // source route option.\r
93       //\r
94       if ((Option[Cur] != IP4_OPTION_RR) &&\r
95           ((Rcvd && (Point != Len + 1)) || (!Rcvd && (Point != 4)))) {\r
96 \r
97         IcmpType  = ICMP_DEST_UNREACHABLE;\r
98         IcmpCode  = ICMP_SOURCEROUTE_FAILED;\r
99         return FALSE;\r
100       }\r
101 \r
102       Cur += Len;\r
103       break;\r
104 \r
105     default:\r
106       Len = Option[Cur + 1];\r
107 \r
108       if ((OptionLen - Cur < Len) || (Len < 2)) {\r
109         IcmpPoint = Cur + 1;\r
110         return FALSE;\r
111       }\r
112 \r
113       Cur = Cur + Len;\r
114       break;\r
115     }\r
116 \r
117   }\r
118 \r
119   return TRUE;\r
120 }\r
121 \r
122 \r
123 /**\r
124   Copy the option from the original option to buffer. It\r
125   handles the details such as:\r
126   1. whether copy the single IP4 option to the first/non-first\r
127   fragments.\r
128   2. Pad the options copied over to aligened to 4 bytes.\r
129 \r
130   @param  Option                The original option to copy from\r
131   @param  OptionLen             The length of the original option\r
132   @param  FirstFragment         Whether it is the first fragment\r
133   @param  Buf                   The buffer to copy options to\r
134   @param  BufLen                The length of the buffer\r
135 \r
136   @retval EFI_SUCCESS           The options are copied over\r
137   @retval EFI_BUFFER_TOO_SMALL  The buffer caller provided is too small.\r
138 \r
139 **/\r
140 EFI_STATUS\r
141 Ip4CopyOption (\r
142   IN UINT8                  *Option,\r
143   IN UINT32                 OptionLen,\r
144   IN BOOLEAN                FirstFragment,\r
145   IN UINT8                  *Buf,           OPTIONAL\r
146   IN OUT UINT32             *BufLen\r
147   )\r
148 {\r
149   UINT8                     OptBuf[40];\r
150   UINT32                    Cur;\r
151   UINT32                    Next;\r
152   UINT8                     Type;\r
153   UINT32                    Len;\r
154 \r
155   ASSERT ((BufLen != NULL) && (OptionLen <= 40));\r
156 \r
157   Cur   = 0;\r
158   Next  = 0;\r
159 \r
160   while (Cur < OptionLen) {\r
161     Type  = Option[Cur];\r
162     Len   = Option[Cur + 1];\r
163 \r
164     if (Type == IP4_OPTION_NOP) {\r
165       //\r
166       // Keep the padding, in case that the sender wants to align\r
167       // the option, say, to 4 bytes\r
168       //\r
169       OptBuf[Next] = IP4_OPTION_NOP;\r
170       Next++;\r
171       Cur++;\r
172 \r
173     } else if (Type == IP4_OPTION_EOP) {\r
174       //\r
175       // Don't append the EOP to avoid including only a EOP option\r
176       //\r
177       break;\r
178 \r
179     } else {\r
180       //\r
181       // don't copy options that is only valid for the first fragment\r
182       //\r
183       if (FirstFragment || (Type & IP4_OPTION_COPY_MASK) != 0) {\r
184         CopyMem (OptBuf + Next, Option + Cur, Len);\r
185         Next += Len;\r
186       }\r
187 \r
188       Cur += Len;\r
189     }\r
190   }\r
191 \r
192   //\r
193   // Don't append an EOP only option.\r
194   //\r
195   if (Next == 0) {\r
196     *BufLen = 0;\r
197     return EFI_SUCCESS;\r
198   }\r
199 \r
200   //\r
201   // Append an EOP if the end of option doesn't coincide with the\r
202   // end of the IP header, that is, isn't aligned to 4 bytes..\r
203   //\r
204   if ((Next % 4) != 0) {\r
205     OptBuf[Next] = IP4_OPTION_EOP;\r
206     Next++;\r
207   }\r
208 \r
209   //\r
210   // Head length is in the unit of 4 bytes. Now, Len is the\r
211   // acutal option length to appear in the IP header.\r
212   //\r
213   Len = ((Next + 3) &~0x03);\r
214 \r
215   //\r
216   // If the buffer is too small, set the BufLen then return\r
217   //\r
218   if ((Buf == NULL) || (*BufLen < Len)) {\r
219     *BufLen = Len;\r
220     return EFI_BUFFER_TOO_SMALL;\r
221   }\r
222 \r
223   //\r
224   // Copy the option to the Buf, zero the buffer first to pad\r
225   // the options with NOP to align to 4 bytes.\r
226   //\r
227   ZeroMem (Buf, Len);\r
228   CopyMem (Buf, OptBuf, Next);\r
229   *BufLen = Len;\r
230   return EFI_SUCCESS;\r
231 }\r