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