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