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