]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/TcpDxe/TcpInput.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / TcpDxe / TcpInput.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 TCP input process routines.\r
3\r
f75a7f56 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 Check whether the sequence number of the incoming segment is acceptable.\r
14\r
15 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
16 @param[in] Seg Pointer to the incoming segment.\r
17\r
18 @retval 1 The sequence number is acceptable.\r
19 @retval 0 The sequence number is not acceptable.\r
20\r
21**/\r
22INTN\r
23TcpSeqAcceptable (\r
d1050b9d
MK
24 IN TCP_CB *Tcb,\r
25 IN TCP_SEG *Seg\r
a3bcde70
HT
26 )\r
27{\r
09c25d1f 28 return (TCP_SEQ_LEQ (Tcb->RcvNxt, Seg->End) &&\r
a3bcde70
HT
29 TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2 + Tcb->RcvWnd));\r
30}\r
31\r
32/**\r
33 NewReno fast recovery defined in RFC3782.\r
34\r
35 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
36 @param[in] Seg Segment that triggers the fast recovery.\r
37\r
38**/\r
39VOID\r
40TcpFastRecover (\r
d1050b9d
MK
41 IN OUT TCP_CB *Tcb,\r
42 IN TCP_SEG *Seg\r
a3bcde70
HT
43 )\r
44{\r
45 UINT32 FlightSize;\r
46 UINT32 Acked;\r
47\r
48 //\r
49 // Step 1: Three duplicate ACKs and not in fast recovery\r
50 //\r
51 if (Tcb->CongestState != TCP_CONGEST_RECOVER) {\r
a3bcde70
HT
52 //\r
53 // Step 1A: Invoking fast retransmission.\r
54 //\r
d1050b9d 55 FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);\r
a3bcde70 56\r
d1050b9d
MK
57 Tcb->Ssthresh = MAX (FlightSize >> 1, (UINT32)(2 * Tcb->SndMss));\r
58 Tcb->Recover = Tcb->SndNxt;\r
a3bcde70
HT
59\r
60 Tcb->CongestState = TCP_CONGEST_RECOVER;\r
61 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
62\r
63 //\r
64 // Step 2: Entering fast retransmission\r
65 //\r
66 TcpRetransmit (Tcb, Tcb->SndUna);\r
67 Tcb->CWnd = Tcb->Ssthresh + 3 * Tcb->SndMss;\r
68\r
69 DEBUG (\r
c49ca4a2 70 (DEBUG_NET,\r
d1050b9d
MK
71 "TcpFastRecover: enter fast retransmission for TCB %p, recover point is %d\n",\r
72 Tcb,\r
73 Tcb->Recover)\r
a3bcde70
HT
74 );\r
75 return;\r
76 }\r
77\r
78 //\r
79 // During fast recovery, execute Step 3, 4, 5 of RFC3782\r
80 //\r
81 if (Seg->Ack == Tcb->SndUna) {\r
a3bcde70
HT
82 //\r
83 // Step 3: Fast Recovery,\r
84 // If this is a duplicated ACK, increse Cwnd by SMSS.\r
85 //\r
86\r
87 // Step 4 is skipped here only to be executed later\r
88 // by TcpToSendData\r
89 //\r
90 Tcb->CWnd += Tcb->SndMss;\r
91 DEBUG (\r
c49ca4a2 92 (DEBUG_NET,\r
d1050b9d
MK
93 "TcpFastRecover: received another duplicated ACK (%d) for TCB %p\n",\r
94 Seg->Ack,\r
95 Tcb)\r
a3bcde70 96 );\r
a3bcde70 97 } else {\r
a3bcde70
HT
98 //\r
99 // New data is ACKed, check whether it is a\r
100 // full ACK or partial ACK\r
101 //\r
102 if (TCP_SEQ_GEQ (Seg->Ack, Tcb->Recover)) {\r
a3bcde70
HT
103 //\r
104 // Step 5 - Full ACK:\r
105 // deflate the congestion window, and exit fast recovery\r
106 //\r
d1050b9d 107 FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);\r
a3bcde70 108\r
d1050b9d 109 Tcb->CWnd = MIN (Tcb->Ssthresh, FlightSize + Tcb->SndMss);\r
a3bcde70
HT
110\r
111 Tcb->CongestState = TCP_CONGEST_OPEN;\r
112 DEBUG (\r
c49ca4a2 113 (DEBUG_NET,\r
d1050b9d
MK
114 "TcpFastRecover: received a full ACK(%d) for TCB %p, exit fast recovery\n",\r
115 Seg->Ack,\r
116 Tcb)\r
a3bcde70 117 );\r
a3bcde70 118 } else {\r
a3bcde70
HT
119 //\r
120 // Step 5 - Partial ACK:\r
121 // fast retransmit the first unacknowledge field\r
122 // , then deflate the CWnd\r
123 //\r
124 TcpRetransmit (Tcb, Seg->Ack);\r
125 Acked = TCP_SUB_SEQ (Seg->Ack, Tcb->SndUna);\r
126\r
127 //\r
128 // Deflate the CWnd by the amount of new data\r
129 // ACKed by SEG.ACK. If more than one SMSS data\r
130 // is ACKed, add back SMSS byte to CWnd after\r
131 //\r
132 if (Acked >= Tcb->SndMss) {\r
133 Acked -= Tcb->SndMss;\r
a3bcde70
HT
134 }\r
135\r
136 Tcb->CWnd -= Acked;\r
137\r
138 DEBUG (\r
c49ca4a2 139 (DEBUG_NET,\r
d1050b9d
MK
140 "TcpFastRecover: received a partial ACK(%d) for TCB %p\n",\r
141 Seg->Ack,\r
142 Tcb)\r
a3bcde70 143 );\r
a3bcde70
HT
144 }\r
145 }\r
146}\r
147\r
148/**\r
149 NewReno fast loss recovery defined in RFC3792.\r
150\r
151 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
152 @param[in] Seg Segment that triggers the fast loss recovery.\r
153\r
154**/\r
155VOID\r
156TcpFastLossRecover (\r
d1050b9d
MK
157 IN OUT TCP_CB *Tcb,\r
158 IN TCP_SEG *Seg\r
a3bcde70
HT
159 )\r
160{\r
161 if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
a3bcde70
HT
162 //\r
163 // New data is ACKed, check whether it is a\r
164 // full ACK or partial ACK\r
165 //\r
166 if (TCP_SEQ_GEQ (Seg->Ack, Tcb->LossRecover)) {\r
a3bcde70
HT
167 //\r
168 // Full ACK: exit the loss recovery.\r
169 //\r
170 Tcb->LossTimes = 0;\r
171 Tcb->CongestState = TCP_CONGEST_OPEN;\r
172\r
173 DEBUG (\r
c49ca4a2 174 (DEBUG_NET,\r
d1050b9d
MK
175 "TcpFastLossRecover: received a full ACK(%d) for TCB %p\n",\r
176 Seg->Ack,\r
177 Tcb)\r
a3bcde70 178 );\r
a3bcde70 179 } else {\r
a3bcde70
HT
180 //\r
181 // Partial ACK:\r
182 // fast retransmit the first unacknowledge field.\r
183 //\r
184 TcpRetransmit (Tcb, Seg->Ack);\r
185 DEBUG (\r
c49ca4a2 186 (DEBUG_NET,\r
d1050b9d
MK
187 "TcpFastLossRecover: received a partial ACK(%d) for TCB %p\n",\r
188 Seg->Ack,\r
189 Tcb)\r
a3bcde70
HT
190 );\r
191 }\r
192 }\r
193}\r
194\r
195/**\r
196 Compute the RTT as specified in RFC2988.\r
197\r
198 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
199 @param[in] Measure Currently measured RTT in heartbeats.\r
200\r
201**/\r
202VOID\r
203TcpComputeRtt (\r
d1050b9d
MK
204 IN OUT TCP_CB *Tcb,\r
205 IN UINT32 Measure\r
a3bcde70
HT
206 )\r
207{\r
d1050b9d 208 INT32 Var;\r
a3bcde70
HT
209\r
210 //\r
211 // Step 2.3: Compute the RTO for subsequent RTT measurement.\r
212 //\r
213 if (Tcb->SRtt != 0) {\r
a3bcde70
HT
214 Var = Tcb->SRtt - (Measure << TCP_RTT_SHIFT);\r
215\r
216 if (Var < 0) {\r
217 Var = -Var;\r
218 }\r
219\r
220 Tcb->RttVar = (3 * Tcb->RttVar + Var) >> 2;\r
221 Tcb->SRtt = 7 * (Tcb->SRtt >> 3) + Measure;\r
a3bcde70
HT
222 } else {\r
223 //\r
224 // Step 2.2: compute the first RTT measure\r
225 //\r
226 Tcb->SRtt = Measure << TCP_RTT_SHIFT;\r
227 Tcb->RttVar = Measure << (TCP_RTT_SHIFT - 1);\r
228 }\r
229\r
230 Tcb->Rto = (Tcb->SRtt + MAX (8, 4 * Tcb->RttVar)) >> TCP_RTT_SHIFT;\r
231\r
232 //\r
233 // Step 2.4: Limit the RTO to at least 1 second\r
81c6f176 234 // Step 2.5: Limit the RTO to a maximum value that\r
a3bcde70
HT
235 // is at least 60 second\r
236 //\r
237 if (Tcb->Rto < TCP_RTO_MIN) {\r
238 Tcb->Rto = TCP_RTO_MIN;\r
a3bcde70
HT
239 } else if (Tcb->Rto > TCP_RTO_MAX) {\r
240 Tcb->Rto = TCP_RTO_MAX;\r
a3bcde70
HT
241 }\r
242\r
243 DEBUG (\r
c49ca4a2 244 (DEBUG_NET,\r
d1050b9d
MK
245 "TcpComputeRtt: new RTT for TCB %p computed SRTT: %d RTTVAR: %d RTO: %d\n",\r
246 Tcb,\r
247 Tcb->SRtt,\r
248 Tcb->RttVar,\r
249 Tcb->Rto)\r
a3bcde70 250 );\r
a3bcde70
HT
251}\r
252\r
253/**\r
254 Trim the data; SYN and FIN to fit into the window defined by Left and Right.\r
255\r
256 @param[in] Nbuf The buffer that contains a received TCP segment without an IP header.\r
257 @param[in] Left The sequence number of the window's left edge.\r
258 @param[in] Right The sequence number of the window's right edge.\r
259\r
786a4d19
JW
260 @retval 0 The segment is broken.\r
261 @retval 1 The segment is in good shape.\r
262\r
a3bcde70 263**/\r
786a4d19 264INTN\r
a3bcde70 265TcpTrimSegment (\r
d1050b9d
MK
266 IN NET_BUF *Nbuf,\r
267 IN TCP_SEQNO Left,\r
268 IN TCP_SEQNO Right\r
a3bcde70
HT
269 )\r
270{\r
d1050b9d
MK
271 TCP_SEG *Seg;\r
272 TCP_SEQNO Urg;\r
273 UINT32 Drop;\r
a3bcde70
HT
274\r
275 Seg = TCPSEG_NETBUF (Nbuf);\r
276\r
277 //\r
278 // If the segment is completely out of window,\r
279 // truncate every thing, include SYN and FIN.\r
280 //\r
281 if (TCP_SEQ_LEQ (Seg->End, Left) || TCP_SEQ_LEQ (Right, Seg->Seq)) {\r
a3bcde70
HT
282 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);\r
283 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);\r
284\r
285 Seg->Seq = Seg->End;\r
286 NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_HEAD);\r
786a4d19 287 return 1;\r
a3bcde70
HT
288 }\r
289\r
290 //\r
291 // Adjust the buffer header\r
292 //\r
293 if (TCP_SEQ_LT (Seg->Seq, Left)) {\r
d1050b9d
MK
294 Drop = TCP_SUB_SEQ (Left, Seg->Seq);\r
295 Urg = Seg->Seq + Seg->Urg;\r
296 Seg->Seq = Left;\r
a3bcde70
HT
297\r
298 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
299 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);\r
300 Drop--;\r
301 }\r
302\r
303 //\r
304 // Adjust the urgent point\r
305 //\r
306 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG)) {\r
a3bcde70 307 if (TCP_SEQ_LT (Urg, Seg->Seq)) {\r
a3bcde70
HT
308 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG);\r
309 } else {\r
d1050b9d 310 Seg->Urg = (UINT16)TCP_SUB_SEQ (Urg, Seg->Seq);\r
a3bcde70
HT
311 }\r
312 }\r
313\r
314 if (Drop != 0) {\r
315 NetbufTrim (Nbuf, Drop, NET_BUF_HEAD);\r
316 }\r
317 }\r
318\r
319 //\r
320 // Adjust the buffer tail\r
321 //\r
322 if (TCP_SEQ_GT (Seg->End, Right)) {\r
d1050b9d
MK
323 Drop = TCP_SUB_SEQ (Seg->End, Right);\r
324 Seg->End = Right;\r
a3bcde70
HT
325\r
326 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
327 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);\r
328 Drop--;\r
329 }\r
330\r
331 if (Drop != 0) {\r
332 NetbufTrim (Nbuf, Drop, NET_BUF_TAIL);\r
333 }\r
334 }\r
335\r
786a4d19 336 return TcpVerifySegment (Nbuf);\r
a3bcde70
HT
337}\r
338\r
339/**\r
340 Trim off the data outside the tcb's receive window.\r
341\r
342 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
343 @param[in] Nbuf Pointer to the NET_BUF containing the received tcp segment.\r
344\r
786a4d19
JW
345 @retval 0 The segment is broken.\r
346 @retval 1 The segment is in good shape.\r
347\r
a3bcde70 348**/\r
786a4d19 349INTN\r
a3bcde70 350TcpTrimInWnd (\r
d1050b9d
MK
351 IN TCP_CB *Tcb,\r
352 IN NET_BUF *Nbuf\r
a3bcde70
HT
353 )\r
354{\r
786a4d19 355 return TcpTrimSegment (Nbuf, Tcb->RcvNxt, Tcb->RcvWl2 + Tcb->RcvWnd);\r
a3bcde70
HT
356}\r
357\r
358/**\r
359 Process the data and FIN flag, and check whether to deliver\r
360 data to the socket layer.\r
361\r
362 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
363\r
364 @retval 0 No error occurred to deliver data.\r
365 @retval -1 An error condition occurred. The proper response is to reset the\r
366 connection.\r
367\r
368**/\r
369INTN\r
370TcpDeliverData (\r
d1050b9d 371 IN OUT TCP_CB *Tcb\r
a3bcde70
HT
372 )\r
373{\r
d1050b9d
MK
374 LIST_ENTRY *Entry;\r
375 NET_BUF *Nbuf;\r
376 TCP_SEQNO Seq;\r
377 TCP_SEG *Seg;\r
378 UINT32 Urgent;\r
a3bcde70
HT
379\r
380 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));\r
381\r
382 //\r
383 // make sure there is some data queued,\r
384 // and TCP is in a proper state\r
385 //\r
386 if (IsListEmpty (&Tcb->RcvQue) || !TCP_CONNECTED (Tcb->State)) {\r
a3bcde70
HT
387 return 0;\r
388 }\r
389\r
390 //\r
391 // Deliver data to the socket layer\r
392 //\r
393 Entry = Tcb->RcvQue.ForwardLink;\r
394 Seq = Tcb->RcvNxt;\r
395\r
396 while (Entry != &Tcb->RcvQue) {\r
d1050b9d
MK
397 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
398 Seg = TCPSEG_NETBUF (Nbuf);\r
a3bcde70 399\r
786a4d19
JW
400 if (TcpVerifySegment (Nbuf) == 0) {\r
401 DEBUG (\r
c49ca4a2 402 (DEBUG_ERROR,\r
d1050b9d
MK
403 "TcpToSendData: discard a broken segment for TCB %p\n",\r
404 Tcb)\r
786a4d19
JW
405 );\r
406 NetbufFree (Nbuf);\r
407 return -1;\r
408 }\r
f75a7f56 409\r
a3bcde70
HT
410 ASSERT (Nbuf->Tcp == NULL);\r
411\r
412 if (TCP_SEQ_GT (Seg->Seq, Seq)) {\r
413 break;\r
414 }\r
415\r
416 Entry = Entry->ForwardLink;\r
417 Seq = Seg->End;\r
418 Tcb->RcvNxt = Seq;\r
419\r
420 RemoveEntryList (&Nbuf->List);\r
421\r
422 //\r
423 // RFC793 Eighth step: process FIN in sequence\r
424 //\r
425 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
a3bcde70
HT
426 //\r
427 // The peer sends to us junky data after FIN,\r
428 // reset the connection.\r
429 //\r
430 if (!IsListEmpty (&Tcb->RcvQue)) {\r
431 DEBUG (\r
c49ca4a2 432 (DEBUG_ERROR,\r
d1050b9d
MK
433 "TcpDeliverData: data received after FIN from peer of TCB %p, reset connection\n",\r
434 Tcb)\r
a3bcde70
HT
435 );\r
436\r
437 NetbufFree (Nbuf);\r
438 return -1;\r
439 }\r
440\r
441 DEBUG (\r
c49ca4a2 442 (DEBUG_NET,\r
d1050b9d
MK
443 "TcpDeliverData: processing FIN from peer of TCB %p\n",\r
444 Tcb)\r
a3bcde70
HT
445 );\r
446\r
447 switch (Tcb->State) {\r
d1050b9d
MK
448 case TCP_SYN_RCVD:\r
449 case TCP_ESTABLISHED:\r
a3bcde70 450\r
d1050b9d 451 TcpSetState (Tcb, TCP_CLOSE_WAIT);\r
a3bcde70 452 break;\r
a3bcde70 453\r
d1050b9d 454 case TCP_FIN_WAIT_1:\r
a3bcde70 455\r
d1050b9d
MK
456 if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
457 TcpSetState (Tcb, TCP_CLOSING);\r
458 break;\r
459 }\r
a3bcde70 460\r
d1050b9d
MK
461 //\r
462 // fall through\r
463 //\r
464 case TCP_FIN_WAIT_2:\r
a3bcde70 465\r
d1050b9d
MK
466 TcpSetState (Tcb, TCP_TIME_WAIT);\r
467 TcpClearAllTimer (Tcb);\r
a3bcde70 468\r
d1050b9d
MK
469 if (Tcb->TimeWaitTimeout != 0) {\r
470 TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
471 } else {\r
472 DEBUG (\r
473 (DEBUG_WARN,\r
474 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",\r
475 Tcb)\r
476 );\r
a3bcde70 477\r
d1050b9d
MK
478 TcpSendAck (Tcb);\r
479 TcpClose (Tcb);\r
480 }\r
a3bcde70 481\r
d1050b9d
MK
482 break;\r
483\r
484 case TCP_CLOSE_WAIT:\r
485 case TCP_CLOSING:\r
486 case TCP_LAST_ACK:\r
487 case TCP_TIME_WAIT:\r
488 //\r
489 // The peer sends to us junk FIN byte. Discard\r
490 // the buffer then reset the connection\r
491 //\r
492 NetbufFree (Nbuf);\r
493 return -1;\r
494 break;\r
495 default:\r
496 break;\r
a3bcde70
HT
497 }\r
498\r
499 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
500\r
501 Seg->End--;\r
502 }\r
503\r
504 //\r
505 // Don't delay the ack if PUSH flag is on.\r
506 //\r
507 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_PSH)) {\r
a3bcde70
HT
508 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
509 }\r
510\r
511 if (Nbuf->TotalSize != 0) {\r
512 Urgent = 0;\r
513\r
514 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&\r
49789216
BZ
515 TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvUp))\r
516 {\r
a3bcde70
HT
517 if (TCP_SEQ_LEQ (Seg->End, Tcb->RcvUp)) {\r
518 Urgent = Nbuf->TotalSize;\r
519 } else {\r
520 Urgent = TCP_SUB_SEQ (Tcb->RcvUp, Seg->Seq) + 1;\r
521 }\r
522 }\r
523\r
524 SockDataRcvd (Tcb->Sk, Nbuf, Urgent);\r
525 }\r
526\r
527 if (TCP_FIN_RCVD (Tcb->State)) {\r
a3bcde70
HT
528 SockNoMoreData (Tcb->Sk);\r
529 }\r
530\r
531 NetbufFree (Nbuf);\r
532 }\r
533\r
534 return 0;\r
535}\r
536\r
537/**\r
538 Store the data into the reassemble queue.\r
539\r
540 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
541 @param[in] Nbuf Pointer to the buffer containing the data to be queued.\r
542\r
786a4d19
JW
543 @retval 0 An error condition occurred.\r
544 @retval 1 No error occurred to queue data.\r
545\r
a3bcde70 546**/\r
786a4d19 547INTN\r
a3bcde70 548TcpQueueData (\r
d1050b9d
MK
549 IN OUT TCP_CB *Tcb,\r
550 IN NET_BUF *Nbuf\r
a3bcde70
HT
551 )\r
552{\r
d1050b9d
MK
553 TCP_SEG *Seg;\r
554 LIST_ENTRY *Head;\r
555 LIST_ENTRY *Prev;\r
556 LIST_ENTRY *Cur;\r
557 NET_BUF *Node;\r
a3bcde70
HT
558\r
559 ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));\r
560\r
561 NET_GET_REF (Nbuf);\r
562\r
d1050b9d
MK
563 Seg = TCPSEG_NETBUF (Nbuf);\r
564 Head = &Tcb->RcvQue;\r
a3bcde70
HT
565\r
566 //\r
567 // Fast path to process normal case. That is,\r
568 // no out-of-order segments are received.\r
569 //\r
570 if (IsListEmpty (Head)) {\r
a3bcde70 571 InsertTailList (Head, &Nbuf->List);\r
786a4d19 572 return 1;\r
a3bcde70
HT
573 }\r
574\r
575 //\r
576 // Find the point to insert the buffer\r
577 //\r
578 for (Prev = Head, Cur = Head->ForwardLink;\r
579 Cur != Head;\r
d1050b9d
MK
580 Prev = Cur, Cur = Cur->ForwardLink)\r
581 {\r
a3bcde70
HT
582 Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
583\r
584 if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->Seq)) {\r
585 break;\r
586 }\r
587 }\r
588\r
589 //\r
590 // Check whether the current segment overlaps with the\r
591 // previous segment.\r
592 //\r
593 if (Prev != Head) {\r
594 Node = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);\r
595\r
596 if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->End)) {\r
a3bcde70 597 if (TCP_SEQ_LEQ (Seg->End, TCPSEG_NETBUF (Node)->End)) {\r
786a4d19 598 return 1;\r
a3bcde70
HT
599 }\r
600\r
786a4d19
JW
601 if (TcpTrimSegment (Nbuf, TCPSEG_NETBUF (Node)->End, Seg->End) == 0) {\r
602 return 0;\r
603 }\r
a3bcde70
HT
604 }\r
605 }\r
606\r
607 InsertHeadList (Prev, &Nbuf->List);\r
608\r
609 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
610\r
611 //\r
612 // Check the segments after the insert point.\r
613 //\r
614 while (Cur != Head) {\r
615 Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
616\r
617 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->End, Seg->End)) {\r
a3bcde70
HT
618 Cur = Cur->ForwardLink;\r
619\r
620 RemoveEntryList (&Node->List);\r
621 NetbufFree (Node);\r
622 continue;\r
623 }\r
624\r
625 if (TCP_SEQ_LT (TCPSEG_NETBUF (Node)->Seq, Seg->End)) {\r
a3bcde70 626 if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->Seq, Seg->Seq)) {\r
a3bcde70 627 RemoveEntryList (&Nbuf->List);\r
786a4d19 628 return 1;\r
a3bcde70
HT
629 }\r
630\r
786a4d19
JW
631 if (TcpTrimSegment (Nbuf, Seg->Seq, TCPSEG_NETBUF (Node)->Seq) == 0) {\r
632 RemoveEntryList (&Nbuf->List);\r
633 return 0;\r
634 }\r
d1050b9d 635\r
a3bcde70
HT
636 break;\r
637 }\r
638\r
639 Cur = Cur->ForwardLink;\r
640 }\r
786a4d19
JW
641\r
642 return 1;\r
a3bcde70
HT
643}\r
644\r
a3bcde70
HT
645/**\r
646 Adjust the send queue or the retransmit queue.\r
647\r
648 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
81c6f176 649 @param[in] Ack The acknowledge sequence number of the received segment.\r
a3bcde70 650\r
786a4d19
JW
651 @retval 0 An error condition occurred.\r
652 @retval 1 No error occurred.\r
653\r
a3bcde70 654**/\r
786a4d19 655INTN\r
a3bcde70 656TcpAdjustSndQue (\r
d1050b9d
MK
657 IN TCP_CB *Tcb,\r
658 IN TCP_SEQNO Ack\r
a3bcde70
HT
659 )\r
660{\r
d1050b9d
MK
661 LIST_ENTRY *Head;\r
662 LIST_ENTRY *Cur;\r
663 NET_BUF *Node;\r
664 TCP_SEG *Seg;\r
a3bcde70 665\r
d1050b9d
MK
666 Head = &Tcb->SndQue;\r
667 Cur = Head->ForwardLink;\r
a3bcde70
HT
668\r
669 while (Cur != Head) {\r
d1050b9d
MK
670 Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
671 Seg = TCPSEG_NETBUF (Node);\r
a3bcde70
HT
672\r
673 if (TCP_SEQ_GEQ (Seg->Seq, Ack)) {\r
674 break;\r
675 }\r
676\r
677 //\r
678 // Remove completely ACKed segments\r
679 //\r
680 if (TCP_SEQ_LEQ (Seg->End, Ack)) {\r
681 Cur = Cur->ForwardLink;\r
682\r
683 RemoveEntryList (&Node->List);\r
684 NetbufFree (Node);\r
685 continue;\r
686 }\r
687\r
786a4d19 688 return TcpTrimSegment (Node, Ack, Seg->End);\r
a3bcde70 689 }\r
786a4d19
JW
690\r
691 return 1;\r
a3bcde70
HT
692}\r
693\r
694/**\r
695 Process the received TCP segments.\r
696\r
697 @param[in] Nbuf Buffer that contains received a TCP segment without an IP header.\r
698 @param[in] Src Source address of the segment, or the peer's IP address.\r
699 @param[in] Dst Destination address of the segment, or the local end's IP\r
700 address.\r
701 @param[in] Version IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates\r
702 IP6 stack.\r
703\r
704 @retval 0 Segment processed successfully. It is either accepted or\r
705 discarded. However, no connection is reset by the segment.\r
706 @retval -1 A connection is reset by the segment.\r
707\r
708**/\r
709INTN\r
710TcpInput (\r
711 IN NET_BUF *Nbuf,\r
712 IN EFI_IP_ADDRESS *Src,\r
713 IN EFI_IP_ADDRESS *Dst,\r
714 IN UINT8 Version\r
715 )\r
716{\r
717 TCP_CB *Tcb;\r
718 TCP_CB *Parent;\r
719 TCP_OPTION Option;\r
720 TCP_HEAD *Head;\r
721 INT32 Len;\r
722 TCP_SEG *Seg;\r
723 TCP_SEQNO Right;\r
724 TCP_SEQNO Urg;\r
725 UINT16 Checksum;\r
2d5afbda 726 INT32 Usable;\r
a3bcde70
HT
727\r
728 ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));\r
729\r
730 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
731\r
d1050b9d
MK
732 Parent = NULL;\r
733 Tcb = NULL;\r
a3bcde70 734\r
d1050b9d 735 Head = (TCP_HEAD *)NetbufGetByte (Nbuf, 0, NULL);\r
a3bcde70 736 ASSERT (Head != NULL);\r
f75a7f56 737\r
37b68011 738 if (Nbuf->TotalSize < sizeof (TCP_HEAD)) {\r
c49ca4a2 739 DEBUG ((DEBUG_NET, "TcpInput: received a malformed packet\n"));\r
37b68011
FS
740 goto DISCARD;\r
741 }\r
f75a7f56 742\r
d1050b9d 743 Len = Nbuf->TotalSize - (Head->HeadLen << 2);\r
a3bcde70
HT
744\r
745 if ((Head->HeadLen < 5) || (Len < 0)) {\r
c49ca4a2 746 DEBUG ((DEBUG_NET, "TcpInput: received a malformed packet\n"));\r
f75a7f56 747\r
a3bcde70
HT
748 goto DISCARD;\r
749 }\r
750\r
751 if (Version == IP_VERSION_4) {\r
752 Checksum = NetPseudoHeadChecksum (Src->Addr[0], Dst->Addr[0], 6, 0);\r
753 } else {\r
754 Checksum = NetIp6PseudoHeadChecksum (&Src->v6, &Dst->v6, 6, 0);\r
755 }\r
756\r
757 Checksum = TcpChecksum (Nbuf, Checksum);\r
758\r
759 if (Checksum != 0) {\r
c49ca4a2 760 DEBUG ((DEBUG_ERROR, "TcpInput: received a checksum error packet\n"));\r
a3bcde70
HT
761 goto DISCARD;\r
762 }\r
763\r
764 if (TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)) {\r
765 Len++;\r
766 }\r
767\r
768 if (TCP_FLG_ON (Head->Flag, TCP_FLG_FIN)) {\r
769 Len++;\r
770 }\r
771\r
772 Tcb = TcpLocateTcb (\r
773 Head->DstPort,\r
774 Dst,\r
775 Head->SrcPort,\r
776 Src,\r
777 Version,\r
d1050b9d 778 (BOOLEAN)TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)\r
a3bcde70
HT
779 );\r
780\r
781 if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {\r
c49ca4a2 782 DEBUG ((DEBUG_NET, "TcpInput: send reset because no TCB found\n"));\r
a3bcde70
HT
783\r
784 Tcb = NULL;\r
785 goto SEND_RESET;\r
786 }\r
787\r
788 Seg = TcpFormatNetbuf (Tcb, Nbuf);\r
789\r
790 //\r
791 // RFC1122 recommended reaction to illegal option\r
792 // (in fact, an illegal option length) is reset.\r
793 //\r
794 if (TcpParseOption (Nbuf->Tcp, &Option) == -1) {\r
795 DEBUG (\r
c49ca4a2 796 (DEBUG_ERROR,\r
d1050b9d
MK
797 "TcpInput: reset the peer because of malformed option for TCB %p\n",\r
798 Tcb)\r
a3bcde70
HT
799 );\r
800\r
801 goto SEND_RESET;\r
802 }\r
803\r
804 //\r
805 // From now on, the segment is headless\r
806 //\r
807 NetbufTrim (Nbuf, (Head->HeadLen << 2), NET_BUF_HEAD);\r
808 Nbuf->Tcp = NULL;\r
809\r
810 //\r
811 // Process the segment in LISTEN state.\r
812 //\r
813 if (Tcb->State == TCP_LISTEN) {\r
814 //\r
815 // First step: Check RST\r
816 //\r
817 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
818 DEBUG (\r
c49ca4a2 819 (DEBUG_WARN,\r
d1050b9d
MK
820 "TcpInput: discard a reset segment for TCB %p in listening\n",\r
821 Tcb)\r
a3bcde70
HT
822 );\r
823\r
824 goto DISCARD;\r
825 }\r
826\r
827 //\r
828 // Second step: Check ACK.\r
829 // Any ACK sent to TCP in LISTEN is reseted.\r
830 //\r
831 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
832 DEBUG (\r
c49ca4a2 833 (DEBUG_WARN,\r
d1050b9d
MK
834 "TcpInput: send reset because of segment with ACK for TCB %p in listening\n",\r
835 Tcb)\r
a3bcde70
HT
836 );\r
837\r
838 goto SEND_RESET;\r
839 }\r
840\r
841 //\r
842 // Third step: Check SYN\r
843 //\r
844 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
845 //\r
846 // create a child TCB to handle the data\r
847 //\r
d1050b9d 848 Parent = Tcb;\r
a3bcde70 849\r
d1050b9d 850 Tcb = TcpCloneTcb (Parent);\r
a3bcde70
HT
851 if (Tcb == NULL) {\r
852 DEBUG (\r
c49ca4a2 853 (DEBUG_ERROR,\r
d1050b9d
MK
854 "TcpInput: discard a segment because failed to clone a child for TCB %p\n",\r
855 Tcb)\r
a3bcde70
HT
856 );\r
857\r
858 goto DISCARD;\r
859 }\r
860\r
861 DEBUG (\r
c49ca4a2 862 (DEBUG_NET,\r
d1050b9d
MK
863 "TcpInput: create a child for TCB %p in listening\n",\r
864 Tcb)\r
a3bcde70
HT
865 );\r
866\r
867 //\r
868 // init the TCB structure\r
869 //\r
870 IP6_COPY_ADDRESS (&Tcb->LocalEnd.Ip, Dst);\r
871 IP6_COPY_ADDRESS (&Tcb->RemoteEnd.Ip, Src);\r
872 Tcb->LocalEnd.Port = Head->DstPort;\r
873 Tcb->RemoteEnd.Port = Head->SrcPort;\r
874\r
875 TcpInitTcbLocal (Tcb);\r
876 TcpInitTcbPeer (Tcb, Seg, &Option);\r
877\r
878 TcpSetState (Tcb, TCP_SYN_RCVD);\r
879 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
786a4d19
JW
880 if (TcpTrimInWnd (Tcb, Nbuf) == 0) {\r
881 DEBUG (\r
c49ca4a2 882 (DEBUG_ERROR,\r
d1050b9d
MK
883 "TcpInput: discard a broken segment for TCB %p\n",\r
884 Tcb)\r
786a4d19
JW
885 );\r
886\r
887 goto DISCARD;\r
888 }\r
a3bcde70
HT
889\r
890 goto StepSix;\r
891 }\r
892\r
893 goto DISCARD;\r
a3bcde70
HT
894 } else if (Tcb->State == TCP_SYN_SENT) {\r
895 //\r
896 // First step: Check ACK bit\r
897 //\r
898 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK) && (Seg->Ack != Tcb->Iss + 1)) {\r
a3bcde70 899 DEBUG (\r
c49ca4a2 900 (DEBUG_WARN,\r
d1050b9d
MK
901 "TcpInput: send reset because of wrong ACK received for TCB %p in SYN_SENT\n",\r
902 Tcb)\r
a3bcde70
HT
903 );\r
904\r
905 goto SEND_RESET;\r
906 }\r
907\r
908 //\r
909 // Second step: Check RST bit\r
910 //\r
911 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
a3bcde70 912 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
a3bcde70 913 DEBUG (\r
c49ca4a2 914 (DEBUG_WARN,\r
d1050b9d
MK
915 "TcpInput: connection reset by peer for TCB %p in SYN_SENT\n",\r
916 Tcb)\r
a3bcde70
HT
917 );\r
918\r
919 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
920 goto DROP_CONNECTION;\r
921 } else {\r
a3bcde70 922 DEBUG (\r
c49ca4a2 923 (DEBUG_WARN,\r
d1050b9d
MK
924 "TcpInput: discard a reset segment because of no ACK for TCB %p in SYN_SENT\n",\r
925 Tcb)\r
a3bcde70
HT
926 );\r
927\r
928 goto DISCARD;\r
929 }\r
930 }\r
931\r
932 //\r
933 // Third step: Check security and precedence. Skipped\r
934 //\r
935\r
936 //\r
49789216 937 // Fourth step: Check SYN. Pay attention to simultaneous open\r
a3bcde70
HT
938 //\r
939 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
a3bcde70
HT
940 TcpInitTcbPeer (Tcb, Seg, &Option);\r
941\r
942 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
a3bcde70
HT
943 Tcb->SndUna = Seg->Ack;\r
944 }\r
945\r
946 TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
947\r
948 if (TCP_SEQ_GT (Tcb->SndUna, Tcb->Iss)) {\r
a3bcde70
HT
949 TcpSetState (Tcb, TCP_ESTABLISHED);\r
950\r
951 TcpClearTimer (Tcb, TCP_TIMER_CONNECT);\r
952 TcpDeliverData (Tcb);\r
953\r
954 if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&\r
49789216
BZ
955 TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON))\r
956 {\r
a3bcde70
HT
957 TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
958 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
959 }\r
960\r
786a4d19
JW
961 if (TcpTrimInWnd (Tcb, Nbuf) == 0) {\r
962 DEBUG (\r
c49ca4a2 963 (DEBUG_ERROR,\r
d1050b9d
MK
964 "TcpInput: discard a broken segment for TCB %p\n",\r
965 Tcb)\r
786a4d19
JW
966 );\r
967\r
968 goto DISCARD;\r
969 }\r
a3bcde70
HT
970\r
971 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
972\r
973 DEBUG (\r
c49ca4a2 974 (DEBUG_NET,\r
d1050b9d
MK
975 "TcpInput: connection established for TCB %p in SYN_SENT\n",\r
976 Tcb)\r
a3bcde70
HT
977 );\r
978\r
979 goto StepSix;\r
980 } else {\r
981 //\r
81c6f176 982 // Received a SYN segment without ACK, simultaneous open.\r
a3bcde70
HT
983 //\r
984 TcpSetState (Tcb, TCP_SYN_RCVD);\r
985\r
986 ASSERT (Tcb->SndNxt == Tcb->Iss + 1);\r
a3bcde70 987\r
d1050b9d 988 if ((TcpAdjustSndQue (Tcb, Tcb->SndNxt) == 0) || (TcpTrimInWnd (Tcb, Nbuf) == 0)) {\r
786a4d19 989 DEBUG (\r
c49ca4a2 990 (DEBUG_ERROR,\r
d1050b9d
MK
991 "TcpInput: discard a broken segment for TCB %p\n",\r
992 Tcb)\r
786a4d19
JW
993 );\r
994\r
995 goto DISCARD;\r
996 }\r
a3bcde70
HT
997\r
998 DEBUG (\r
c49ca4a2 999 (DEBUG_WARN,\r
d1050b9d
MK
1000 "TcpInput: simultaneous open for TCB %p in SYN_SENT\n",\r
1001 Tcb)\r
a3bcde70
HT
1002 );\r
1003\r
1004 goto StepSix;\r
1005 }\r
1006 }\r
1007\r
1008 goto DISCARD;\r
1009 }\r
1010\r
1011 //\r
1012 // Process segment in SYN_RCVD or TCP_CONNECTED states\r
1013 //\r
1014\r
1015 //\r
1016 // Clear probe timer since the RecvWindow is opened.\r
1017 //\r
1018 if (Tcb->ProbeTimerOn && (Seg->Wnd != 0)) {\r
1019 TcpClearTimer (Tcb, TCP_TIMER_PROBE);\r
1020 Tcb->ProbeTimerOn = FALSE;\r
1021 }\r
1022\r
1023 //\r
1024 // First step: Check whether SEG.SEQ is acceptable\r
1025 //\r
1026 if (TcpSeqAcceptable (Tcb, Seg) == 0) {\r
1027 DEBUG (\r
c49ca4a2 1028 (DEBUG_WARN,\r
d1050b9d
MK
1029 "TcpInput: sequence acceptance test failed for segment of TCB %p\n",\r
1030 Tcb)\r
a3bcde70
HT
1031 );\r
1032\r
1033 if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
1034 TcpSendAck (Tcb);\r
1035 }\r
1036\r
1037 goto DISCARD;\r
1038 }\r
1039\r
1040 if ((TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2)) &&\r
1041 (Tcb->RcvWl2 == Seg->End) &&\r
49789216
BZ
1042 !TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN))\r
1043 {\r
a3bcde70
HT
1044 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
1045 }\r
1046\r
1047 //\r
1048 // Second step: Check the RST\r
1049 //\r
1050 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
c49ca4a2 1051 DEBUG ((DEBUG_WARN, "TcpInput: connection reset for TCB %p\n", Tcb));\r
a3bcde70
HT
1052\r
1053 if (Tcb->State == TCP_SYN_RCVD) {\r
a3bcde70
HT
1054 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_REFUSED);\r
1055\r
1056 //\r
1057 // This TCB comes from either a LISTEN TCB,\r
81c6f176 1058 // or active open TCB with simultaneous open.\r
a3bcde70
HT
1059 // Do NOT signal user CONNECTION refused\r
1060 // if it comes from a LISTEN TCB.\r
1061 //\r
1062 } else if ((Tcb->State == TCP_ESTABLISHED) ||\r
49789216
BZ
1063 (Tcb->State == TCP_FIN_WAIT_1) ||\r
1064 (Tcb->State == TCP_FIN_WAIT_2) ||\r
1065 (Tcb->State == TCP_CLOSE_WAIT))\r
1066 {\r
a3bcde70 1067 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
a3bcde70
HT
1068 } else {\r
1069 }\r
1070\r
1071 goto DROP_CONNECTION;\r
1072 }\r
1073\r
1074 //\r
1075 // Trim the data and flags.\r
1076 //\r
786a4d19
JW
1077 if (TcpTrimInWnd (Tcb, Nbuf) == 0) {\r
1078 DEBUG (\r
c49ca4a2 1079 (DEBUG_ERROR,\r
d1050b9d
MK
1080 "TcpInput: discard a broken segment for TCB %p\n",\r
1081 Tcb)\r
786a4d19
JW
1082 );\r
1083\r
1084 goto DISCARD;\r
1085 }\r
a3bcde70
HT
1086\r
1087 //\r
1088 // Third step: Check security and precedence, Ignored\r
1089 //\r
1090\r
1091 //\r
1092 // Fourth step: Check the SYN bit.\r
1093 //\r
1094 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
a3bcde70 1095 DEBUG (\r
c49ca4a2 1096 (DEBUG_WARN,\r
d1050b9d
MK
1097 "TcpInput: connection reset because received extra SYN for TCB %p\n",\r
1098 Tcb)\r
a3bcde70
HT
1099 );\r
1100\r
1101 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
1102 goto RESET_THEN_DROP;\r
1103 }\r
d1050b9d 1104\r
a3bcde70
HT
1105 //\r
1106 // Fifth step: Check the ACK\r
1107 //\r
1108 if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
1109 DEBUG (\r
c49ca4a2 1110 (DEBUG_WARN,\r
d1050b9d
MK
1111 "TcpInput: segment discard because of no ACK for connected TCB %p\n",\r
1112 Tcb)\r
a3bcde70
HT
1113 );\r
1114\r
1115 goto DISCARD;\r
1116 } else {\r
d1050b9d 1117 if ((Tcb->IpInfo->IpVersion == IP_VERSION_6) && (Tcb->Tick == 0)) {\r
a3bcde70
HT
1118 Tcp6RefreshNeighbor (Tcb, Src, TCP6_KEEP_NEIGHBOR_TIME * TICKS_PER_SECOND);\r
1119 Tcb->Tick = TCP6_REFRESH_NEIGHBOR_TICK;\r
1120 }\r
1121 }\r
1122\r
1123 if (Tcb->State == TCP_SYN_RCVD) {\r
49789216
BZ
1124 if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) &&\r
1125 TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt))\r
1126 {\r
d1050b9d
MK
1127 Tcb->SndWnd = Seg->Wnd;\r
1128 Tcb->SndWndMax = MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
1129 Tcb->SndWl1 = Seg->Seq;\r
1130 Tcb->SndWl2 = Seg->Ack;\r
a3bcde70
HT
1131 TcpSetState (Tcb, TCP_ESTABLISHED);\r
1132\r
1133 TcpClearTimer (Tcb, TCP_TIMER_CONNECT);\r
1134 TcpDeliverData (Tcb);\r
1135\r
1136 DEBUG (\r
c49ca4a2 1137 (DEBUG_NET,\r
d1050b9d
MK
1138 "TcpInput: connection established for TCB %p in SYN_RCVD\n",\r
1139 Tcb)\r
a3bcde70
HT
1140 );\r
1141\r
1142 //\r
1143 // Continue the process as ESTABLISHED state\r
1144 //\r
1145 } else {\r
1146 DEBUG (\r
c49ca4a2 1147 (DEBUG_WARN,\r
d1050b9d
MK
1148 "TcpInput: send reset because of wrong ACK for TCB %p in SYN_RCVD\n",\r
1149 Tcb)\r
a3bcde70
HT
1150 );\r
1151\r
1152 goto SEND_RESET;\r
1153 }\r
1154 }\r
1155\r
1156 if (TCP_SEQ_LT (Seg->Ack, Tcb->SndUna)) {\r
a3bcde70 1157 DEBUG (\r
c49ca4a2 1158 (DEBUG_WARN,\r
d1050b9d
MK
1159 "TcpInput: ignore the out-of-data ACK for connected TCB %p\n",\r
1160 Tcb)\r
a3bcde70
HT
1161 );\r
1162\r
1163 goto StepSix;\r
a3bcde70 1164 } else if (TCP_SEQ_GT (Seg->Ack, Tcb->SndNxt)) {\r
a3bcde70 1165 DEBUG (\r
c49ca4a2 1166 (DEBUG_WARN,\r
d1050b9d
MK
1167 "TcpInput: discard segment for future ACK for connected TCB %p\n",\r
1168 Tcb)\r
a3bcde70
HT
1169 );\r
1170\r
1171 TcpSendAck (Tcb);\r
1172 goto DISCARD;\r
1173 }\r
1174\r
1175 //\r
1176 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.\r
1177 //\r
1178 if (TCP_FLG_ON (Option.Flag, TCP_OPTION_RCVD_TS)) {\r
1179 //\r
1180 // update TsRecent as specified in page 16 RFC1323.\r
1181 // RcvWl2 equals to the variable "LastAckSent"\r
1182 // defined there.\r
1183 //\r
49789216
BZ
1184 if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) &&\r
1185 TCP_SEQ_LT (Tcb->RcvWl2, Seg->End))\r
1186 {\r
d1050b9d
MK
1187 Tcb->TsRecent = Option.TSVal;\r
1188 Tcb->TsRecentAge = mTcpTick;\r
a3bcde70
HT
1189 }\r
1190\r
1191 TcpComputeRtt (Tcb, TCP_SUB_TIME (mTcpTick, Option.TSEcr));\r
a3bcde70 1192 } else if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
a3bcde70
HT
1193 ASSERT (Tcb->CongestState == TCP_CONGEST_OPEN);\r
1194\r
1195 TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
1196 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
1197 }\r
1198\r
1199 if (Seg->Ack == Tcb->SndNxt) {\r
a3bcde70
HT
1200 TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
1201 } else {\r
a3bcde70
HT
1202 TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);\r
1203 }\r
1204\r
1205 //\r
1206 // Count duplicate acks.\r
1207 //\r
1208 if ((Seg->Ack == Tcb->SndUna) &&\r
1209 (Tcb->SndUna != Tcb->SndNxt) &&\r
1210 (Seg->Wnd == Tcb->SndWnd) &&\r
49789216
BZ
1211 (0 == Len))\r
1212 {\r
a3bcde70
HT
1213 Tcb->DupAck++;\r
1214 } else {\r
a3bcde70
HT
1215 Tcb->DupAck = 0;\r
1216 }\r
1217\r
1218 //\r
1219 // Congestion avoidance, fast recovery and fast retransmission.\r
1220 //\r
1221 if (((Tcb->CongestState == TCP_CONGEST_OPEN) && (Tcb->DupAck < 3)) ||\r
49789216
BZ
1222 (Tcb->CongestState == TCP_CONGEST_LOSS))\r
1223 {\r
a3bcde70 1224 if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
a3bcde70 1225 if (Tcb->CWnd < Tcb->Ssthresh) {\r
a3bcde70
HT
1226 Tcb->CWnd += Tcb->SndMss;\r
1227 } else {\r
a3bcde70
HT
1228 Tcb->CWnd += MAX (Tcb->SndMss * Tcb->SndMss / Tcb->CWnd, 1);\r
1229 }\r
1230\r
1231 Tcb->CWnd = MIN (Tcb->CWnd, TCP_MAX_WIN << Tcb->SndWndScale);\r
1232 }\r
1233\r
1234 if (Tcb->CongestState == TCP_CONGEST_LOSS) {\r
1235 TcpFastLossRecover (Tcb, Seg);\r
1236 }\r
1237 } else {\r
a3bcde70
HT
1238 TcpFastRecover (Tcb, Seg);\r
1239 }\r
1240\r
1241 if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
786a4d19
JW
1242 if (TcpAdjustSndQue (Tcb, Seg->Ack) == 0) {\r
1243 DEBUG (\r
c49ca4a2 1244 (DEBUG_ERROR,\r
d1050b9d
MK
1245 "TcpInput: discard a broken segment for TCB %p\n",\r
1246 Tcb)\r
786a4d19
JW
1247 );\r
1248\r
1249 goto DISCARD;\r
1250 }\r
f75a7f56 1251\r
a3bcde70
HT
1252 Tcb->SndUna = Seg->Ack;\r
1253\r
1254 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&\r
49789216
BZ
1255 TCP_SEQ_LT (Tcb->SndUp, Seg->Ack))\r
1256 {\r
a3bcde70
HT
1257 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);\r
1258 }\r
1259 }\r
1260\r
1261 //\r
1262 // Update window info\r
1263 //\r
1264 if (TCP_SEQ_LT (Tcb->SndWl1, Seg->Seq) ||\r
49789216
BZ
1265 ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack)))\r
1266 {\r
a3bcde70
HT
1267 Right = Seg->Ack + Seg->Wnd;\r
1268\r
1269 if (TCP_SEQ_LT (Right, Tcb->SndWl2 + Tcb->SndWnd)) {\r
a3bcde70
HT
1270 if ((Tcb->SndWl1 == Seg->Seq) &&\r
1271 (Tcb->SndWl2 == Seg->Ack) &&\r
49789216
BZ
1272 (Len == 0))\r
1273 {\r
a3bcde70
HT
1274 goto NO_UPDATE;\r
1275 }\r
1276\r
1277 DEBUG (\r
c49ca4a2 1278 (DEBUG_WARN,\r
d1050b9d
MK
1279 "TcpInput: peer shrinks the window for connected TCB %p\n",\r
1280 Tcb)\r
a3bcde70
HT
1281 );\r
1282\r
49789216
BZ
1283 if ((Tcb->CongestState == TCP_CONGEST_RECOVER) &&\r
1284 (TCP_SEQ_LT (Right, Tcb->Recover)))\r
1285 {\r
a3bcde70
HT
1286 Tcb->Recover = Right;\r
1287 }\r
1288\r
49789216
BZ
1289 if ((Tcb->CongestState == TCP_CONGEST_LOSS) &&\r
1290 (TCP_SEQ_LT (Right, Tcb->LossRecover)))\r
1291 {\r
a3bcde70
HT
1292 Tcb->LossRecover = Right;\r
1293 }\r
1294\r
1295 if (TCP_SEQ_LT (Right, Tcb->SndNxt)) {\r
2d5afbda
FS
1296 //\r
1297 // Check for Window Retraction in RFC7923 section 2.4.\r
1298 // The lower n bits of the peer's actual receive window is wiped out if TCP\r
1299 // window scale is enabled, it will look like the peer is shrinking the window.\r
1300 // Check whether the SndNxt is out of the advertised receive window by more than\r
1301 // 2^Rcv.Wind.Shift before moving the SndNxt to the left.\r
1302 //\r
1303 DEBUG (\r
c49ca4a2 1304 (DEBUG_WARN,\r
d1050b9d
MK
1305 "TcpInput: peer advise negative useable window for connected TCB %p\n",\r
1306 Tcb)\r
2d5afbda
FS
1307 );\r
1308 Usable = TCP_SUB_SEQ (Tcb->SndNxt, Right);\r
1309 if ((Usable >> Tcb->SndWndScale) > 0) {\r
1310 DEBUG (\r
c49ca4a2 1311 (DEBUG_WARN,\r
d1050b9d
MK
1312 "TcpInput: SndNxt is out of window by more than window scale for TCB %p\n",\r
1313 Tcb)\r
2d5afbda
FS
1314 );\r
1315 Tcb->SndNxt = Right;\r
1316 }\r
a3bcde70 1317\r
d1050b9d 1318 if (Right == Tcb->SndUna) {\r
a3bcde70
HT
1319 TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
1320 TcpSetProbeTimer (Tcb);\r
1321 }\r
1322 }\r
1323 }\r
1324\r
d1050b9d
MK
1325 Tcb->SndWnd = Seg->Wnd;\r
1326 Tcb->SndWndMax = MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
1327 Tcb->SndWl1 = Seg->Seq;\r
1328 Tcb->SndWl2 = Seg->Ack;\r
a3bcde70
HT
1329 }\r
1330\r
1331NO_UPDATE:\r
1332\r
49789216
BZ
1333 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) &&\r
1334 (Tcb->SndUna == Tcb->SndNxt))\r
1335 {\r
a3bcde70 1336 DEBUG (\r
c49ca4a2 1337 (DEBUG_NET,\r
d1050b9d
MK
1338 "TcpInput: local FIN is ACKed by peer for connected TCB %p\n",\r
1339 Tcb)\r
a3bcde70
HT
1340 );\r
1341\r
1342 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED);\r
1343 }\r
1344\r
1345 //\r
1346 // Transit the state if proper.\r
1347 //\r
1348 switch (Tcb->State) {\r
d1050b9d 1349 case TCP_FIN_WAIT_1:\r
a3bcde70 1350\r
d1050b9d
MK
1351 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
1352 TcpSetState (Tcb, TCP_FIN_WAIT_2);\r
a3bcde70 1353\r
d1050b9d
MK
1354 TcpClearAllTimer (Tcb);\r
1355 TcpSetTimer (Tcb, TCP_TIMER_FINWAIT2, Tcb->FinWait2Timeout);\r
1356 }\r
a3bcde70 1357\r
d1050b9d 1358 case TCP_FIN_WAIT_2:\r
a3bcde70 1359\r
d1050b9d 1360 break;\r
a3bcde70 1361\r
d1050b9d
MK
1362 case TCP_CLOSE_WAIT:\r
1363 break;\r
a3bcde70 1364\r
d1050b9d 1365 case TCP_CLOSING:\r
a3bcde70 1366\r
d1050b9d
MK
1367 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
1368 TcpSetState (Tcb, TCP_TIME_WAIT);\r
1369\r
1370 TcpClearAllTimer (Tcb);\r
a3bcde70 1371\r
d1050b9d
MK
1372 if (Tcb->TimeWaitTimeout != 0) {\r
1373 TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
1374 } else {\r
1375 DEBUG (\r
1376 (DEBUG_WARN,\r
1377 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",\r
1378 Tcb)\r
1379 );\r
a3bcde70 1380\r
d1050b9d
MK
1381 TcpClose (Tcb);\r
1382 }\r
1383 }\r
a3bcde70 1384\r
d1050b9d 1385 break;\r
a3bcde70 1386\r
d1050b9d 1387 case TCP_LAST_ACK:\r
a3bcde70 1388\r
d1050b9d
MK
1389 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
1390 TcpSetState (Tcb, TCP_CLOSED);\r
1391 }\r
1392\r
1393 break;\r
1394\r
1395 case TCP_TIME_WAIT:\r
1396\r
1397 TcpSendAck (Tcb);\r
1398\r
1399 if (Tcb->TimeWaitTimeout != 0) {\r
a3bcde70
HT
1400 TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
1401 } else {\r
a3bcde70 1402 DEBUG (\r
c49ca4a2 1403 (DEBUG_WARN,\r
d1050b9d
MK
1404 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",\r
1405 Tcb)\r
a3bcde70
HT
1406 );\r
1407\r
1408 TcpClose (Tcb);\r
1409 }\r
a3bcde70 1410\r
d1050b9d 1411 break;\r
a3bcde70 1412\r
d1050b9d
MK
1413 default:\r
1414 break;\r
a3bcde70 1415 }\r
d1050b9d 1416\r
a3bcde70
HT
1417 //\r
1418 // Sixth step: Check the URG bit.update the Urg point\r
1419 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.\r
1420 //\r
1421StepSix:\r
1422\r
1423 Tcb->Idle = 0;\r
1424 TcpSetKeepaliveTimer (Tcb);\r
1425\r
1426 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) && !TCP_FIN_RCVD (Tcb->State)) {\r
a3bcde70 1427 DEBUG (\r
c49ca4a2 1428 (DEBUG_NET,\r
d1050b9d
MK
1429 "TcpInput: received urgent data from peer for connected TCB %p\n",\r
1430 Tcb)\r
a3bcde70
HT
1431 );\r
1432\r
1433 Urg = Seg->Seq + Seg->Urg;\r
1434\r
49789216
BZ
1435 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&\r
1436 TCP_SEQ_GT (Urg, Tcb->RcvUp))\r
1437 {\r
a3bcde70
HT
1438 Tcb->RcvUp = Urg;\r
1439 } else {\r
a3bcde70
HT
1440 Tcb->RcvUp = Urg;\r
1441 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG);\r
1442 }\r
1443 }\r
d1050b9d 1444\r
a3bcde70
HT
1445 //\r
1446 // Seventh step: Process the segment data\r
1447 //\r
1448 if (Seg->End != Seg->Seq) {\r
a3bcde70 1449 if (TCP_FIN_RCVD (Tcb->State)) {\r
a3bcde70 1450 DEBUG (\r
c49ca4a2 1451 (DEBUG_WARN,\r
d1050b9d
MK
1452 "TcpInput: connection reset because data is lost for connected TCB %p\n",\r
1453 Tcb)\r
a3bcde70
HT
1454 );\r
1455\r
1456 goto RESET_THEN_DROP;\r
1457 }\r
1458\r
1459 if (TCP_LOCAL_CLOSED (Tcb->State) && (Nbuf->TotalSize != 0)) {\r
1460 DEBUG (\r
c49ca4a2 1461 (DEBUG_WARN,\r
d1050b9d
MK
1462 "TcpInput: connection reset because data is lost for connected TCB %p\n",\r
1463 Tcb)\r
a3bcde70
HT
1464 );\r
1465\r
1466 goto RESET_THEN_DROP;\r
1467 }\r
1468\r
786a4d19
JW
1469 if (TcpQueueData (Tcb, Nbuf) == 0) {\r
1470 DEBUG (\r
c49ca4a2 1471 (DEBUG_ERROR,\r
d1050b9d
MK
1472 "TcpInput: discard a broken segment for TCB %p\n",\r
1473 Tcb)\r
786a4d19
JW
1474 );\r
1475\r
1476 goto DISCARD;\r
1477 }\r
f75a7f56 1478\r
a3bcde70
HT
1479 if (TcpDeliverData (Tcb) == -1) {\r
1480 goto RESET_THEN_DROP;\r
1481 }\r
1482\r
1483 if (!IsListEmpty (&Tcb->RcvQue)) {\r
1484 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
1485 }\r
1486 }\r
1487\r
1488 //\r
1489 // Eighth step: check the FIN.\r
1490 // This step is moved to TcpDeliverData. FIN will be\r
1491 // processed in sequence there. Check the comments in\r
1492 // the beginning of the file header for information.\r
1493 //\r
1494\r
1495 //\r
1496 // Tcb is a new child of the listening Parent,\r
1497 // commit it.\r
1498 //\r
1499 if (Parent != NULL) {\r
1500 Tcb->Parent = Parent;\r
1501 TcpInsertTcb (Tcb);\r
1502 }\r
1503\r
1504 if ((Tcb->State != TCP_CLOSED) &&\r
1505 (TcpToSendData (Tcb, 0) == 0) &&\r
49789216
BZ
1506 (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || (Nbuf->TotalSize != 0)))\r
1507 {\r
a3bcde70
HT
1508 TcpToSendAck (Tcb);\r
1509 }\r
1510\r
1511 NetbufFree (Nbuf);\r
1512 return 0;\r
1513\r
1514RESET_THEN_DROP:\r
1515 TcpSendReset (Tcb, Head, Len, Dst, Src, Version);\r
1516\r
1517DROP_CONNECTION:\r
1518 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));\r
1519\r
1520 NetbufFree (Nbuf);\r
1521 TcpClose (Tcb);\r
1522\r
1523 return -1;\r
1524\r
1525SEND_RESET:\r
1526\r
1527 TcpSendReset (Tcb, Head, Len, Dst, Src, Version);\r
1528\r
1529DISCARD:\r
1530\r
1531 //\r
1532 // Tcb is a child of Parent, and it doesn't survive\r
1533 //\r
c49ca4a2 1534 DEBUG ((DEBUG_WARN, "TcpInput: Discard a packet\n"));\r
a3bcde70
HT
1535 NetbufFree (Nbuf);\r
1536\r
1537 if ((Parent != NULL) && (Tcb != NULL)) {\r
a3bcde70
HT
1538 ASSERT (Tcb->Sk != NULL);\r
1539 TcpClose (Tcb);\r
1540 }\r
1541\r
1542 return 0;\r
1543}\r
1544\r
1545/**\r
1546 Process the received ICMP error messages for TCP.\r
1547\r
1548 @param[in] Nbuf The buffer that contains part of the TCP segment without an IP header\r
1549 truncated from the ICMP error packet.\r
1550 @param[in] IcmpErr The ICMP error code interpreted from an ICMP error packet.\r
1551 @param[in] Src Source address of the ICMP error message.\r
1552 @param[in] Dst Destination address of the ICMP error message.\r
1553 @param[in] Version IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates\r
1554 IP6 stack.\r
1555\r
1556**/\r
1557VOID\r
1558TcpIcmpInput (\r
1559 IN NET_BUF *Nbuf,\r
1560 IN UINT8 IcmpErr,\r
1561 IN EFI_IP_ADDRESS *Src,\r
1562 IN EFI_IP_ADDRESS *Dst,\r
1563 IN UINT8 Version\r
1564 )\r
1565{\r
d1050b9d
MK
1566 TCP_HEAD *Head;\r
1567 TCP_CB *Tcb;\r
1568 TCP_SEQNO Seq;\r
1569 EFI_STATUS IcmpErrStatus;\r
1570 BOOLEAN IcmpErrIsHard;\r
1571 BOOLEAN IcmpErrNotify;\r
a3bcde70 1572\r
37b68011
FS
1573 if (Nbuf->TotalSize < sizeof (TCP_HEAD)) {\r
1574 goto CLEAN_EXIT;\r
1575 }\r
f75a7f56 1576\r
d1050b9d 1577 Head = (TCP_HEAD *)NetbufGetByte (Nbuf, 0, NULL);\r
a3bcde70
HT
1578 ASSERT (Head != NULL);\r
1579\r
1580 Tcb = TcpLocateTcb (\r
1581 Head->DstPort,\r
1582 Dst,\r
1583 Head->SrcPort,\r
1584 Src,\r
1585 Version,\r
1586 FALSE\r
1587 );\r
d1050b9d 1588 if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {\r
a3bcde70
HT
1589 goto CLEAN_EXIT;\r
1590 }\r
1591\r
1592 //\r
1593 // Validate the sequence number.\r
1594 //\r
1595 Seq = NTOHL (Head->Seq);\r
1596 if (!(TCP_SEQ_LEQ (Tcb->SndUna, Seq) && TCP_SEQ_LT (Seq, Tcb->SndNxt))) {\r
a3bcde70
HT
1597 goto CLEAN_EXIT;\r
1598 }\r
1599\r
49789216
BZ
1600 IcmpErrStatus = IpIoGetIcmpErrStatus (\r
1601 IcmpErr,\r
1602 Tcb->Sk->IpVersion,\r
1603 &IcmpErrIsHard,\r
1604 &IcmpErrNotify\r
1605 );\r
a3bcde70
HT
1606\r
1607 if (IcmpErrNotify) {\r
a3bcde70
HT
1608 SOCK_ERROR (Tcb->Sk, IcmpErrStatus);\r
1609 }\r
1610\r
1611 if (IcmpErrIsHard) {\r
a3bcde70
HT
1612 TcpClose (Tcb);\r
1613 }\r
1614\r
1615CLEAN_EXIT:\r
1616\r
1617 NetbufFree (Nbuf);\r
1618}\r