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