VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/NetworkPkg/TcpDxe/TcpInput.c

Last change on this file was 105670, checked in by vboxsync, 4 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette