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