]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/TcpDxe/TcpOption.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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
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
39UINT32\r
40TcpGetUint32 (\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
57VOID\r
58TcpPutUint32 (\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
75UINT8\r
76TcpComputeScale (\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
104UINT16\r
105TcpSynBuildOption (\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
184UINT16\r
185TcpBuildOption (\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
231INTN\r
232TcpParseOption (\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