1 /** @file
2 Routines to process TCP option.
3
4 Copyright (c) 2005 - 2006, 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<BR>
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 "Tcp4Main.h"
16
17 /**
18 Get a UINT16 value from buffer.
19
20 @param Buf Pointer to input buffer.
21
22 @return The UINT16 value get from buffer.
23
24 **/
25 UINT16
TcpGetUint16(IN UINT8 * Buf)26 TcpGetUint16 (
27 IN UINT8 *Buf
28 )
29 {
30 UINT16 Value;
31 CopyMem (&Value, Buf, sizeof (UINT16));
32 return NTOHS (Value);
33 }
34
35 /**
36 Get a UINT32 value from buffer.
37
38 @param Buf Pointer to input buffer.
39
40 @return The UINT32 value get from buffer.
41
42 **/
43 UINT32
TcpGetUint32(IN UINT8 * Buf)44 TcpGetUint32 (
45 IN UINT8 *Buf
46 )
47 {
48 UINT32 Value;
49 CopyMem (&Value, Buf, sizeof (UINT32));
50 return NTOHL (Value);
51 }
52
53 /**
54 Put a UINT32 value in buffer.
55
56 @param Buf Pointer to the buffer.
57 @param Data The UINT32 Date to put in buffer
58
59 **/
60 VOID
TcpPutUint32(OUT UINT8 * Buf,IN UINT32 Data)61 TcpPutUint32 (
62 OUT UINT8 *Buf,
63 IN UINT32 Data
64 )
65 {
66 Data = HTONL (Data);
67 CopyMem (Buf, &Data, sizeof (UINT32));
68 }
69
70
71 /**
72 Compute the window scale value according to the given buffer size.
73
74 @param Tcb Pointer to the TCP_CB of this TCP instance.
75
76 @return The scale value.
77
78 **/
79 UINT8
TcpComputeScale(IN TCP_CB * Tcb)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) &&
93 ((UINT32) (TCP_OPTION_MAX_WIN << Scale) < BufSize)) {
94
95 Scale++;
96 }
97
98 return Scale;
99 }
100
101
102 /**
103 Build the TCP option in three-way handshake.
104
105 @param Tcb Pointer to the TCP_CB of this TCP instance.
106 @param Nbuf Pointer to the buffer to store the options.
107
108 @return The total length of the TCP option field.
109
110 **/
111 UINT16
TcpSynBuildOption(IN TCP_CB * Tcb,IN NET_BUF * Nbuf)112 TcpSynBuildOption (
113 IN TCP_CB *Tcb,
114 IN NET_BUF *Nbuf
115 )
116 {
117 UINT8 *Data;
118 UINT16 Len;
119
120 ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));
121
122 Len = 0;
123
124 //
125 // Add timestamp option if not disabled by application
126 // and it is the first SYN segment or the peer has sent
127 // us its timestamp.
128 //
129 if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS) &&
130 (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||
131 TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS))) {
132
133 Data = NetbufAllocSpace (
134 Nbuf,
135 TCP_OPTION_TS_ALIGNED_LEN,
136 NET_BUF_HEAD
137 );
138
139 ASSERT (Data != NULL);
140 Len += TCP_OPTION_TS_ALIGNED_LEN;
141
142 TcpPutUint32 (Data, TCP_OPTION_TS_FAST);
143 TcpPutUint32 (Data + 4, mTcpTick);
144 TcpPutUint32 (Data + 8, 0);
145 }
146
147 //
148 // Build window scale option, only when are configured
149 // to send WS option, and either we are doing active
150 // open or we have received WS option from peer.
151 //
152 if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS) &&
153 (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||
154 TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS))) {
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 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 /**
182 Build the TCP option in synchronized states.
183
184 @param Tcb Pointer to the TCP_CB of this TCP instance.
185 @param Nbuf Pointer to the buffer to store the options.
186
187 @return The total length of the TCP option field.
188
189 **/
190 UINT16
TcpBuildOption(IN TCP_CB * Tcb,IN NET_BUF * Nbuf)191 TcpBuildOption (
192 IN TCP_CB *Tcb,
193 IN NET_BUF *Nbuf
194 )
195 {
196 UINT8 *Data;
197 UINT16 Len;
198
199 ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));
200 Len = 0;
201
202 //
203 // Build Timestamp option
204 //
205 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_TS) &&
206 !TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_RST)) {
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 /**
227 Parse the supported options.
228
229 @param Tcp Pointer to the TCP_CB of this TCP instance.
230 @param Option Pointer to the TCP_OPTION used to store the successfully pasrsed
231 options.
232
233 @retval 0 The options are successfully pasrsed.
234 @retval -1 Ilegal option was found.
235
236 **/
237 INTN
TcpParseOption(IN TCP_HEAD * Tcp,IN OUT TCP_OPTION * Option)238 TcpParseOption (
239 IN TCP_HEAD *Tcp,
240 IN OUT TCP_OPTION *Option
241 )
242 {
243 UINT8 *Head;
244 UINT8 TotalLen;
245 UINT8 Cur;
246 UINT8 Type;
247 UINT8 Len;
248
249 ASSERT ((Tcp != NULL) && (Option != NULL));
250
251 Option->Flag = 0;
252
253 TotalLen = (UINT8) ((Tcp->HeadLen << 2) - sizeof (TCP_HEAD));
254 if (TotalLen <= 0) {
255 return 0;
256 }
257
258 Head = (UINT8 *) (Tcp + 1);
259
260 //
261 // Fast process of timestamp option
262 //
263 if ((TotalLen == TCP_OPTION_TS_ALIGNED_LEN) &&
264 (TcpGetUint32 (Head) == TCP_OPTION_TS_FAST)) {
265
266 Option->TSVal = TcpGetUint32 (Head + 4);
267 Option->TSEcr = TcpGetUint32 (Head + 8);
268 Option->Flag = TCP_OPTION_RCVD_TS;
269
270 return 0;
271 }
272
273 //
274 // Slow path to process the options.
275 //
276 Cur = 0;
277
278 while (Cur < TotalLen) {
279 Type = Head[Cur];
280
281 switch (Type) {
282 case TCP_OPTION_MSS:
283 Len = Head[Cur + 1];
284
285 if ((Len != TCP_OPTION_MSS_LEN) ||
286 (TotalLen - Cur < TCP_OPTION_MSS_LEN)) {
287
288 return -1;
289 }
290
291 Option->Mss = TcpGetUint16 (&Head[Cur + 2]);
292 TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_MSS);
293
294 Cur += TCP_OPTION_MSS_LEN;
295 break;
296
297 case TCP_OPTION_WS:
298 Len = Head[Cur + 1];
299
300 if ((Len != TCP_OPTION_WS_LEN) ||
301 (TotalLen - Cur < TCP_OPTION_WS_LEN)) {
302
303 return -1;
304 }
305
306 Option->WndScale = (UINT8) MIN (14, Head[Cur + 2]);
307 TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_WS);
308
309 Cur += TCP_OPTION_WS_LEN;
310 break;
311
312 case TCP_OPTION_TS:
313 Len = Head[Cur + 1];
314
315 if ((Len != TCP_OPTION_TS_LEN) ||
316 (TotalLen - Cur < TCP_OPTION_TS_LEN)) {
317
318 return -1;
319 }
320
321 Option->TSVal = TcpGetUint32 (&Head[Cur + 2]);
322 Option->TSEcr = TcpGetUint32 (&Head[Cur + 6]);
323 TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_TS);
324
325 Cur += TCP_OPTION_TS_LEN;
326 break;
327
328 case TCP_OPTION_NOP:
329 Cur++;
330 break;
331
332 case TCP_OPTION_EOP:
333 Cur = TotalLen;
334 break;
335
336 default:
337 Len = Head[Cur + 1];
338
339 if ((TotalLen - Cur) < Len || Len < 2) {
340 return -1;
341 }
342
343 Cur = (UINT8) (Cur + Len);
344 break;
345 }
346
347 }
348
349 return 0;
350 }
351
352
353 /**
354 Check the segment against PAWS.
355
356 @param Tcb Pointer to the TCP_CB of this TCP instance.
357 @param TSVal The timestamp value.
358
359 @retval 1 The segment passed the PAWS check.
360 @retval 0 The segment failed to pass the PAWS check.
361
362 **/
363 UINT32
TcpPawsOK(IN TCP_CB * Tcb,IN UINT32 TSVal)364 TcpPawsOK (
365 IN TCP_CB *Tcb,
366 IN UINT32 TSVal
367 )
368 {
369 //
370 // PAWS as defined in RFC1323, buggy...
371 //
372 if (TCP_TIME_LT (TSVal, Tcb->TsRecent) &&
373 TCP_TIME_LT (Tcb->TsRecentAge + TCP_PAWS_24DAY, mTcpTick)) {
374
375 return 0;
376
377 }
378
379 return 1;
380 }
381