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