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