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