• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
TcpGetUint16(IN UINT8 * Buf)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
TcpGetUint32(IN UINT8 * Buf)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
TcpPutUint32(OUT UINT8 * Buf,IN UINT32 Data)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
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) && ((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
TcpSynBuildOption(IN TCP_CB * Tcb,IN NET_BUF * Nbuf)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
TcpBuildOption(IN TCP_CB * Tcb,IN NET_BUF * Nbuf)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
TcpParseOption(IN TCP_HEAD * Tcp,IN OUT TCP_OPTION * Option)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
TcpPawsOK(IN TCP_CB * Tcb,IN UINT32 TSVal)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 }
375