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