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