]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/TcpDxe/TcpOption.c
Fix a bug about the iSCSI DHCP dependency issue.
[mirror_edk2.git] / NetworkPkg / TcpDxe / TcpOption.c
1 /** @file
2 Routines to process TCP option.
3
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "TcpMain.h"
17
18 /**
19 Get a UINT16 value from buffer.
20
21 @param[in] Buf Pointer to input buffer.
22
23 @return The UINT16 value obtained from the buffer.
24
25 **/
26 UINT16
27 TcpGetUint16 (
28 IN UINT8 *Buf
29 )
30 {
31 UINT16 Value;
32 CopyMem (&Value, Buf, sizeof (UINT16));
33 return NTOHS (Value);
34 }
35
36 /**
37 Get a UINT32 value from buffer.
38
39 @param[in] Buf Pointer to input buffer.
40
41 @return The UINT32 value obtained from the buffer.
42
43 **/
44 UINT32
45 TcpGetUint32 (
46 IN UINT8 *Buf
47 )
48 {
49 UINT32 Value;
50 CopyMem (&Value, Buf, sizeof (UINT32));
51 return NTOHL (Value);
52 }
53
54 /**
55 Put a UINT32 value in buffer.
56
57 @param[out] Buf Pointer to the buffer.
58 @param[in] Data The UINT32 Date to put in the buffer.
59
60 **/
61 VOID
62 TcpPutUint32 (
63 OUT UINT8 *Buf,
64 IN UINT32 Data
65 )
66 {
67 Data = HTONL (Data);
68 CopyMem (Buf, &Data, sizeof (UINT32));
69 }
70
71 /**
72 Compute the window scale value according to the given buffer size.
73
74 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
75
76 @return The scale value.
77
78 **/
79 UINT8
80 TcpComputeScale (
81 IN TCP_CB *Tcb
82 )
83 {
84 UINT8 Scale;
85 UINT32 BufSize;
86
87 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));
88
89 BufSize = GET_RCV_BUFFSIZE (Tcb->Sk);
90
91 Scale = 0;
92 while ((Scale < TCP_OPTION_MAX_WS) && ((UINT32) (TCP_OPTION_MAX_WIN << Scale) < BufSize)) {
93
94 Scale++;
95 }
96
97 return Scale;
98 }
99
100 /**
101 Build the TCP option in three-way handshake.
102
103 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
104 @param[in] Nbuf Pointer to the buffer to store the options.
105
106 @return The total length of the TCP option field.
107
108 **/
109 UINT16
110 TcpSynBuildOption (
111 IN TCP_CB *Tcb,
112 IN NET_BUF *Nbuf
113 )
114 {
115 UINT8 *Data;
116 UINT16 Len;
117
118 ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));
119
120 Len = 0;
121
122 //
123 // Add a timestamp option if not disabled by the application
124 // and it is the first SYN segment, or the peer has sent
125 // us its timestamp.
126 //
127 if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS) &&
128 (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||
129 TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS))
130 ) {
131
132 Data = NetbufAllocSpace (
133 Nbuf,
134 TCP_OPTION_TS_ALIGNED_LEN,
135 NET_BUF_HEAD
136 );
137
138 ASSERT (Data != NULL);
139 Len += TCP_OPTION_TS_ALIGNED_LEN;
140
141 TcpPutUint32 (Data, TCP_OPTION_TS_FAST);
142 TcpPutUint32 (Data + 4, mTcpTick);
143 TcpPutUint32 (Data + 8, 0);
144 }
145
146 //
147 // Build window scale option, only when configured
148 // to send WS option, and either we are doing active
149 // open or we have received WS option from peer.
150 //
151 if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS) &&
152 (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||
153 TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS))
154 ) {
155
156 Data = NetbufAllocSpace (
157 Nbuf,
158 TCP_OPTION_WS_ALIGNED_LEN,
159 NET_BUF_HEAD
160 );
161
162 ASSERT (Data != NULL);
163
164 Len += TCP_OPTION_WS_ALIGNED_LEN;
165 TcpPutUint32 (Data, TCP_OPTION_WS_FAST | TcpComputeScale (Tcb));
166 }
167
168 //
169 // Build the MSS option.
170 //
171 Data = NetbufAllocSpace (Nbuf, TCP_OPTION_MSS_LEN, 1);
172 ASSERT (Data != NULL);
173
174 Len += TCP_OPTION_MSS_LEN;
175 TcpPutUint32 (Data, TCP_OPTION_MSS_FAST | Tcb->RcvMss);
176
177 return Len;
178 }
179
180 /**
181 Build the TCP option in synchronized states.
182
183 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
184 @param[in] Nbuf Pointer to the buffer to store the options.
185
186 @return The total length of the TCP option field.
187
188 **/
189 UINT16
190 TcpBuildOption (
191 IN TCP_CB *Tcb,
192 IN NET_BUF *Nbuf
193 )
194 {
195 UINT8 *Data;
196 UINT16 Len;
197
198 ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));
199 Len = 0;
200
201 //
202 // Build the Timestamp option.
203 //
204 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_TS) &&
205 !TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_RST)
206 ) {
207
208 Data = NetbufAllocSpace (
209 Nbuf,
210 TCP_OPTION_TS_ALIGNED_LEN,
211 NET_BUF_HEAD
212 );
213
214 ASSERT (Data != NULL);
215 Len += TCP_OPTION_TS_ALIGNED_LEN;
216
217 TcpPutUint32 (Data, TCP_OPTION_TS_FAST);
218 TcpPutUint32 (Data + 4, mTcpTick);
219 TcpPutUint32 (Data + 8, Tcb->TsRecent);
220 }
221
222 return Len;
223 }
224
225 /**
226 Parse the supported options.
227
228 @param[in] Tcp Pointer to the TCP_CB of this TCP instance.
229 @param[in, out] Option Pointer to the TCP_OPTION used to store the
230 successfully pasrsed options.
231
232 @retval 0 The options are successfully pasrsed.
233 @retval -1 Ilegal option was found.
234
235 **/
236 INTN
237 TcpParseOption (
238 IN TCP_HEAD *Tcp,
239 IN OUT TCP_OPTION *Option
240 )
241 {
242 UINT8 *Head;
243 UINT8 TotalLen;
244 UINT8 Cur;
245 UINT8 Type;
246 UINT8 Len;
247
248 ASSERT ((Tcp != NULL) && (Option != NULL));
249
250 Option->Flag = 0;
251
252 TotalLen = (UINT8) ((Tcp->HeadLen << 2) - sizeof (TCP_HEAD));
253 if (TotalLen <= 0) {
254 return 0;
255 }
256
257 Head = (UINT8 *) (Tcp + 1);
258
259 //
260 // Fast process of the timestamp option.
261 //
262 if ((TotalLen == TCP_OPTION_TS_ALIGNED_LEN) && (TcpGetUint32 (Head) == TCP_OPTION_TS_FAST)) {
263
264 Option->TSVal = TcpGetUint32 (Head + 4);
265 Option->TSEcr = TcpGetUint32 (Head + 8);
266 Option->Flag = TCP_OPTION_RCVD_TS;
267
268 return 0;
269 }
270 //
271 // Slow path to process the options.
272 //
273 Cur = 0;
274
275 while (Cur < TotalLen) {
276 Type = Head[Cur];
277
278 switch (Type) {
279 case TCP_OPTION_MSS:
280 Len = Head[Cur + 1];
281
282 if ((Len != TCP_OPTION_MSS_LEN) || (TotalLen - Cur < TCP_OPTION_MSS_LEN)) {
283
284 return -1;
285 }
286
287 Option->Mss = TcpGetUint16 (&Head[Cur + 2]);
288 TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_MSS);
289
290 Cur += TCP_OPTION_MSS_LEN;
291 break;
292
293 case TCP_OPTION_WS:
294 Len = Head[Cur + 1];
295
296 if ((Len != TCP_OPTION_WS_LEN) || (TotalLen - Cur < TCP_OPTION_WS_LEN)) {
297
298 return -1;
299 }
300
301 Option->WndScale = (UINT8) MIN (14, Head[Cur + 2]);
302 TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_WS);
303
304 Cur += TCP_OPTION_WS_LEN;
305 break;
306
307 case TCP_OPTION_TS:
308 Len = Head[Cur + 1];
309
310 if ((Len != TCP_OPTION_TS_LEN) || (TotalLen - Cur < TCP_OPTION_TS_LEN)) {
311
312 return -1;
313 }
314
315 Option->TSVal = TcpGetUint32 (&Head[Cur + 2]);
316 Option->TSEcr = TcpGetUint32 (&Head[Cur + 6]);
317 TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_TS);
318
319 Cur += TCP_OPTION_TS_LEN;
320 break;
321
322 case TCP_OPTION_NOP:
323 Cur++;
324 break;
325
326 case TCP_OPTION_EOP:
327 Cur = TotalLen;
328 break;
329
330 default:
331 Len = Head[Cur + 1];
332
333 if ((TotalLen - Cur) < Len || Len < 2) {
334 return -1;
335 }
336
337 Cur = (UINT8) (Cur + Len);
338 break;
339 }
340
341 }
342
343 return 0;
344 }
345
346 /**
347 Check the segment against PAWS.
348
349 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
350 @param[in] TSVal The timestamp value.
351
352 @retval 1 The segment passed the PAWS check.
353 @retval 0 The segment failed to pass the PAWS check.
354
355 **/
356 UINT32
357 TcpPawsOK (
358 IN TCP_CB *Tcb,
359 IN UINT32 TSVal
360 )
361 {
362 //
363 // PAWS as defined in RFC1323, buggy...
364 //
365 if (TCP_TIME_LT (TSVal, Tcb->TsRecent) &&
366 TCP_TIME_LT (Tcb->TsRecentAge + TCP_PAWS_24DAY, mTcpTick)
367 ) {
368
369 return 0;
370
371 }
372
373 return 1;
374 }