• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   TCP input process routines.
3 
4   Copyright (c) 2009 - 2016, 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
TcpSeqAcceptable(IN TCP_CB * Tcb,IN TCP_SEG * Seg)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
TcpFastRecover(IN OUT TCP_CB * Tcb,IN TCP_SEG * Seg)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
TcpFastLossRecover(IN OUT TCP_CB * Tcb,IN TCP_SEG * Seg)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
TcpComputeRtt(IN OUT TCP_CB * Tcb,IN UINT32 Measure)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 **/
285 VOID
TcpTrimSegment(IN NET_BUF * Nbuf,IN TCP_SEQNO Left,IN TCP_SEQNO Right)286 TcpTrimSegment (
287   IN NET_BUF   *Nbuf,
288   IN TCP_SEQNO Left,
289   IN TCP_SEQNO Right
290   )
291 {
292   TCP_SEG   *Seg;
293   TCP_SEQNO Urg;
294   UINT32    Drop;
295 
296   Seg = TCPSEG_NETBUF (Nbuf);
297 
298   //
299   // If the segment is completely out of window,
300   // truncate every thing, include SYN and FIN.
301   //
302   if (TCP_SEQ_LEQ (Seg->End, Left) || TCP_SEQ_LEQ (Right, Seg->Seq)) {
303 
304     TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);
305     TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);
306 
307     Seg->Seq = Seg->End;
308     NetbufTrim (Nbuf, Nbuf->TotalSize, NET_BUF_HEAD);
309     return;
310   }
311 
312   //
313   // Adjust the buffer header
314   //
315   if (TCP_SEQ_LT (Seg->Seq, Left)) {
316 
317     Drop      = TCP_SUB_SEQ (Left, Seg->Seq);
318     Urg       = Seg->Seq + Seg->Urg;
319     Seg->Seq  = Left;
320 
321     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
322       TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);
323       Drop--;
324     }
325 
326     //
327     // Adjust the urgent point
328     //
329     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG)) {
330 
331       if (TCP_SEQ_LT (Urg, Seg->Seq)) {
332 
333         TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG);
334       } else {
335         Seg->Urg = (UINT16) TCP_SUB_SEQ (Urg, Seg->Seq);
336       }
337     }
338 
339     if (Drop != 0) {
340       NetbufTrim (Nbuf, Drop, NET_BUF_HEAD);
341     }
342   }
343 
344   //
345   // Adjust the buffer tail
346   //
347   if (TCP_SEQ_GT (Seg->End, Right)) {
348 
349     Drop      = TCP_SUB_SEQ (Seg->End, Right);
350     Seg->End  = Right;
351 
352     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
353       TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);
354       Drop--;
355     }
356 
357     if (Drop != 0) {
358       NetbufTrim (Nbuf, Drop, NET_BUF_TAIL);
359     }
360   }
361 
362   ASSERT (TcpVerifySegment (Nbuf) != 0);
363 }
364 
365 /**
366   Trim off the data outside the tcb's receive window.
367 
368   @param[in]  Tcb      Pointer to the TCP_CB of this TCP instance.
369   @param[in]  Nbuf     Pointer to the NET_BUF containing the received tcp segment.
370 
371 **/
372 VOID
TcpTrimInWnd(IN TCP_CB * Tcb,IN NET_BUF * Nbuf)373 TcpTrimInWnd (
374   IN TCP_CB  *Tcb,
375   IN NET_BUF *Nbuf
376   )
377 {
378   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
TcpDeliverData(IN OUT TCP_CB * Tcb)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     ASSERT (TcpVerifySegment (Nbuf) != 0);
425     ASSERT (Nbuf->Tcp == NULL);
426 
427     if (TCP_SEQ_GT (Seg->Seq, Seq)) {
428       break;
429     }
430 
431     Entry       = Entry->ForwardLink;
432     Seq         = Seg->End;
433     Tcb->RcvNxt = Seq;
434 
435     RemoveEntryList (&Nbuf->List);
436 
437     //
438     // RFC793 Eighth step: process FIN in sequence
439     //
440     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
441 
442       //
443       // The peer sends to us junky data after FIN,
444       // reset the connection.
445       //
446       if (!IsListEmpty (&Tcb->RcvQue)) {
447         DEBUG (
448           (EFI_D_ERROR,
449           "TcpDeliverData: data received after FIN from peer of TCB %p, reset connection\n",
450           Tcb)
451           );
452 
453         NetbufFree (Nbuf);
454         return -1;
455       }
456 
457       DEBUG (
458         (EFI_D_NET,
459         "TcpDeliverData: processing FIN from peer of TCB %p\n",
460         Tcb)
461         );
462 
463       switch (Tcb->State) {
464       case TCP_SYN_RCVD:
465       case TCP_ESTABLISHED:
466 
467         TcpSetState (Tcb, TCP_CLOSE_WAIT);
468         break;
469 
470       case TCP_FIN_WAIT_1:
471 
472         if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {
473 
474           TcpSetState (Tcb, TCP_CLOSING);
475           break;
476         }
477 
478       //
479       // fall through
480       //
481       case TCP_FIN_WAIT_2:
482 
483         TcpSetState (Tcb, TCP_TIME_WAIT);
484         TcpClearAllTimer (Tcb);
485 
486         if (Tcb->TimeWaitTimeout != 0) {
487 
488           TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);
489         } else {
490 
491           DEBUG (
492             (EFI_D_WARN,
493             "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
494             Tcb)
495             );
496 
497           TcpSendAck (Tcb);
498           TcpClose (Tcb);
499         }
500         break;
501 
502       case TCP_CLOSE_WAIT:
503       case TCP_CLOSING:
504       case TCP_LAST_ACK:
505       case TCP_TIME_WAIT:
506         //
507         // The peer sends to us junk FIN byte. Discard
508         // the buffer then reset the connection
509         //
510         NetbufFree (Nbuf);
511         return -1;
512         break;
513       default:
514         break;
515       }
516 
517       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
518 
519       Seg->End--;
520     }
521 
522     //
523     // Don't delay the ack if PUSH flag is on.
524     //
525     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_PSH)) {
526 
527       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
528     }
529 
530     if (Nbuf->TotalSize != 0) {
531       Urgent = 0;
532 
533       if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&
534           TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvUp))
535       {
536 
537         if (TCP_SEQ_LEQ (Seg->End, Tcb->RcvUp)) {
538           Urgent = Nbuf->TotalSize;
539         } else {
540           Urgent = TCP_SUB_SEQ (Tcb->RcvUp, Seg->Seq) + 1;
541         }
542       }
543 
544       SockDataRcvd (Tcb->Sk, Nbuf, Urgent);
545     }
546 
547     if (TCP_FIN_RCVD (Tcb->State)) {
548 
549       SockNoMoreData (Tcb->Sk);
550     }
551 
552     NetbufFree (Nbuf);
553   }
554 
555   return 0;
556 }
557 
558 /**
559   Store the data into the reassemble queue.
560 
561   @param[in, out]  Tcb   Pointer to the TCP_CB of this TCP instance.
562   @param[in]       Nbuf  Pointer to the buffer containing the data to be queued.
563 
564 **/
565 VOID
TcpQueueData(IN OUT TCP_CB * Tcb,IN NET_BUF * Nbuf)566 TcpQueueData (
567   IN OUT TCP_CB  *Tcb,
568   IN     NET_BUF *Nbuf
569   )
570 {
571   TCP_SEG         *Seg;
572   LIST_ENTRY      *Head;
573   LIST_ENTRY      *Prev;
574   LIST_ENTRY      *Cur;
575   NET_BUF         *Node;
576 
577   ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));
578 
579   NET_GET_REF (Nbuf);
580 
581   Seg   = TCPSEG_NETBUF (Nbuf);
582   Head  = &Tcb->RcvQue;
583 
584   //
585   // Fast path to process normal case. That is,
586   // no out-of-order segments are received.
587   //
588   if (IsListEmpty (Head)) {
589 
590     InsertTailList (Head, &Nbuf->List);
591     return;
592   }
593 
594   //
595   // Find the point to insert the buffer
596   //
597   for (Prev = Head, Cur = Head->ForwardLink;
598        Cur != Head;
599        Prev = Cur, Cur = Cur->ForwardLink) {
600 
601     Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
602 
603     if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->Seq)) {
604       break;
605     }
606   }
607 
608   //
609   // Check whether the current segment overlaps with the
610   // previous segment.
611   //
612   if (Prev != Head) {
613     Node = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);
614 
615     if (TCP_SEQ_LT (Seg->Seq, TCPSEG_NETBUF (Node)->End)) {
616 
617       if (TCP_SEQ_LEQ (Seg->End, TCPSEG_NETBUF (Node)->End)) {
618 
619         NetbufFree (Nbuf);
620         return;
621       }
622 
623       TcpTrimSegment (Nbuf, TCPSEG_NETBUF (Node)->End, Seg->End);
624     }
625   }
626 
627   InsertHeadList (Prev, &Nbuf->List);
628 
629   TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
630 
631   //
632   // Check the segments after the insert point.
633   //
634   while (Cur != Head) {
635     Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
636 
637     if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->End, Seg->End)) {
638 
639       Cur = Cur->ForwardLink;
640 
641       RemoveEntryList (&Node->List);
642       NetbufFree (Node);
643       continue;
644     }
645 
646     if (TCP_SEQ_LT (TCPSEG_NETBUF (Node)->Seq, Seg->End)) {
647 
648       if (TCP_SEQ_LEQ (TCPSEG_NETBUF (Node)->Seq, Seg->Seq)) {
649 
650         RemoveEntryList (&Nbuf->List);
651         NetbufFree (Nbuf);
652         return;
653       }
654 
655       TcpTrimSegment (Nbuf, Seg->Seq, TCPSEG_NETBUF (Node)->Seq);
656       break;
657     }
658 
659     Cur = Cur->ForwardLink;
660   }
661 }
662 
663 
664 /**
665   Adjust the send queue or the retransmit queue.
666 
667   @param[in]  Tcb      Pointer to the TCP_CB of this TCP instance.
668   @param[in]  Ack      The acknowledge seuqence number of the received segment.
669 
670 **/
671 VOID
TcpAdjustSndQue(IN TCP_CB * Tcb,IN TCP_SEQNO Ack)672 TcpAdjustSndQue (
673   IN TCP_CB    *Tcb,
674   IN TCP_SEQNO Ack
675   )
676 {
677   LIST_ENTRY      *Head;
678   LIST_ENTRY      *Cur;
679   NET_BUF         *Node;
680   TCP_SEG         *Seg;
681 
682   Head  = &Tcb->SndQue;
683   Cur   = Head->ForwardLink;
684 
685   while (Cur != Head) {
686     Node  = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
687     Seg   = TCPSEG_NETBUF (Node);
688 
689     if (TCP_SEQ_GEQ (Seg->Seq, Ack)) {
690       break;
691     }
692 
693     //
694     // Remove completely ACKed segments
695     //
696     if (TCP_SEQ_LEQ (Seg->End, Ack)) {
697       Cur = Cur->ForwardLink;
698 
699       RemoveEntryList (&Node->List);
700       NetbufFree (Node);
701       continue;
702     }
703 
704     TcpTrimSegment (Node, Ack, Seg->End);
705     break;
706   }
707 }
708 
709 /**
710   Process the received TCP segments.
711 
712   @param[in]  Nbuf     Buffer that contains received a TCP segment without an IP header.
713   @param[in]  Src      Source address of the segment, or the peer's IP address.
714   @param[in]  Dst      Destination address of the segment, or the local end's IP
715                        address.
716   @param[in]  Version  IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates
717                        IP6 stack.
718 
719   @retval 0        Segment  processed successfully. It is either accepted or
720                    discarded. However, no connection is reset by the segment.
721   @retval -1       A connection is reset by the segment.
722 
723 **/
724 INTN
TcpInput(IN NET_BUF * Nbuf,IN EFI_IP_ADDRESS * Src,IN EFI_IP_ADDRESS * Dst,IN UINT8 Version)725 TcpInput (
726   IN NET_BUF         *Nbuf,
727   IN EFI_IP_ADDRESS  *Src,
728   IN EFI_IP_ADDRESS  *Dst,
729   IN UINT8           Version
730   )
731 {
732   TCP_CB      *Tcb;
733   TCP_CB      *Parent;
734   TCP_OPTION  Option;
735   TCP_HEAD    *Head;
736   INT32       Len;
737   TCP_SEG     *Seg;
738   TCP_SEQNO   Right;
739   TCP_SEQNO   Urg;
740   UINT16      Checksum;
741 
742   ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));
743 
744   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
745 
746   Parent  = NULL;
747   Tcb     = NULL;
748 
749   Head    = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);
750   ASSERT (Head != NULL);
751 
752   if (Nbuf->TotalSize < sizeof (TCP_HEAD)) {
753     DEBUG ((EFI_D_NET, "TcpInput: received a malformed packet\n"));
754     goto DISCARD;
755   }
756 
757   Len     = Nbuf->TotalSize - (Head->HeadLen << 2);
758 
759   if ((Head->HeadLen < 5) || (Len < 0)) {
760 
761     DEBUG ((EFI_D_NET, "TcpInput: received a malformed packet\n"));
762 
763     goto DISCARD;
764   }
765 
766   if (Version == IP_VERSION_4) {
767     Checksum = NetPseudoHeadChecksum (Src->Addr[0], Dst->Addr[0], 6, 0);
768   } else {
769     Checksum = NetIp6PseudoHeadChecksum (&Src->v6, &Dst->v6, 6, 0);
770   }
771 
772   Checksum = TcpChecksum (Nbuf, Checksum);
773 
774   if (Checksum != 0) {
775     DEBUG ((EFI_D_ERROR, "TcpInput: received a checksum error packet\n"));
776     goto DISCARD;
777   }
778 
779   if (TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)) {
780     Len++;
781   }
782 
783   if (TCP_FLG_ON (Head->Flag, TCP_FLG_FIN)) {
784     Len++;
785   }
786 
787   Tcb = TcpLocateTcb (
788           Head->DstPort,
789           Dst,
790           Head->SrcPort,
791           Src,
792           Version,
793           (BOOLEAN) TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)
794           );
795 
796   if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {
797     DEBUG ((EFI_D_NET, "TcpInput: send reset because no TCB found\n"));
798 
799     Tcb = NULL;
800     goto SEND_RESET;
801   }
802 
803   Seg = TcpFormatNetbuf (Tcb, Nbuf);
804 
805   //
806   // RFC1122 recommended reaction to illegal option
807   // (in fact, an illegal option length) is reset.
808   //
809   if (TcpParseOption (Nbuf->Tcp, &Option) == -1) {
810     DEBUG (
811       (EFI_D_ERROR,
812       "TcpInput: reset the peer because of malformed option for TCB %p\n",
813       Tcb)
814       );
815 
816     goto SEND_RESET;
817   }
818 
819   //
820   // From now on, the segment is headless
821   //
822   NetbufTrim (Nbuf, (Head->HeadLen << 2), NET_BUF_HEAD);
823   Nbuf->Tcp = NULL;
824 
825   //
826   // Process the segment in LISTEN state.
827   //
828   if (Tcb->State == TCP_LISTEN) {
829     //
830     // First step: Check RST
831     //
832     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
833       DEBUG (
834         (EFI_D_WARN,
835         "TcpInput: discard a reset segment for TCB %p in listening\n",
836         Tcb)
837         );
838 
839       goto DISCARD;
840     }
841 
842     //
843     // Second step: Check ACK.
844     // Any ACK sent to TCP in LISTEN is reseted.
845     //
846     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
847       DEBUG (
848         (EFI_D_WARN,
849         "TcpInput: send reset because of segment with ACK for TCB %p in listening\n",
850         Tcb)
851         );
852 
853       goto SEND_RESET;
854     }
855 
856     //
857     // Third step: Check SYN
858     //
859     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
860       //
861       // create a child TCB to handle the data
862       //
863       Parent  = Tcb;
864 
865       Tcb     = TcpCloneTcb (Parent);
866       if (Tcb == NULL) {
867         DEBUG (
868           (EFI_D_ERROR,
869           "TcpInput: discard a segment because failed to clone a child for TCB %p\n",
870           Tcb)
871           );
872 
873         goto DISCARD;
874       }
875 
876       DEBUG (
877         (EFI_D_NET,
878         "TcpInput: create a child for TCB %p in listening\n",
879         Tcb)
880         );
881 
882       //
883       // init the TCB structure
884       //
885       IP6_COPY_ADDRESS (&Tcb->LocalEnd.Ip, Dst);
886       IP6_COPY_ADDRESS (&Tcb->RemoteEnd.Ip, Src);
887       Tcb->LocalEnd.Port  = Head->DstPort;
888       Tcb->RemoteEnd.Port = Head->SrcPort;
889 
890       TcpInitTcbLocal (Tcb);
891       TcpInitTcbPeer (Tcb, Seg, &Option);
892 
893       TcpSetState (Tcb, TCP_SYN_RCVD);
894       TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);
895       TcpTrimInWnd (Tcb, Nbuf);
896 
897       goto StepSix;
898     }
899 
900     goto DISCARD;
901 
902   } else if (Tcb->State == TCP_SYN_SENT) {
903     //
904     // First step: Check ACK bit
905     //
906     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK) && (Seg->Ack != Tcb->Iss + 1)) {
907 
908       DEBUG (
909         (EFI_D_WARN,
910         "TcpInput: send reset because of wrong ACK received for TCB %p in SYN_SENT\n",
911         Tcb)
912         );
913 
914       goto SEND_RESET;
915     }
916 
917     //
918     // Second step: Check RST bit
919     //
920     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
921 
922       if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
923 
924         DEBUG (
925           (EFI_D_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 
934         DEBUG (
935           (EFI_D_WARN,
936           "TcpInput: discard a reset segment because of no ACK for TCB %p in SYN_SENT\n",
937           Tcb)
938           );
939 
940         goto DISCARD;
941       }
942     }
943 
944     //
945     // Third step: Check security and precedence. Skipped
946     //
947 
948     //
949     // Fourth step: Check SYN. Pay attention to simultaneous open
950     //
951     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
952 
953       TcpInitTcbPeer (Tcb, Seg, &Option);
954 
955       if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
956 
957         Tcb->SndUna = Seg->Ack;
958       }
959 
960       TcpClearTimer (Tcb, TCP_TIMER_REXMIT);
961 
962       if (TCP_SEQ_GT (Tcb->SndUna, Tcb->Iss)) {
963 
964         TcpSetState (Tcb, TCP_ESTABLISHED);
965 
966         TcpClearTimer (Tcb, TCP_TIMER_CONNECT);
967         TcpDeliverData (Tcb);
968 
969         if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&
970             TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON))
971         {
972 
973           TcpComputeRtt (Tcb, Tcb->RttMeasure);
974           TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
975         }
976 
977         TcpTrimInWnd (Tcb, Nbuf);
978 
979         TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
980 
981         DEBUG (
982           (EFI_D_NET,
983           "TcpInput: connection established for TCB %p in SYN_SENT\n",
984           Tcb)
985           );
986 
987         goto StepSix;
988       } else {
989         //
990         // Received a SYN segment without ACK, simultanous open.
991         //
992         TcpSetState (Tcb, TCP_SYN_RCVD);
993 
994         ASSERT (Tcb->SndNxt == Tcb->Iss + 1);
995         TcpAdjustSndQue (Tcb, Tcb->SndNxt);
996 
997         TcpTrimInWnd (Tcb, Nbuf);
998 
999         DEBUG (
1000           (EFI_D_WARN,
1001           "TcpInput: simultaneous open for TCB %p in SYN_SENT\n",
1002           Tcb)
1003           );
1004 
1005         goto StepSix;
1006       }
1007     }
1008 
1009     goto DISCARD;
1010   }
1011 
1012   //
1013   // Process segment in SYN_RCVD or TCP_CONNECTED states
1014   //
1015 
1016   //
1017   // Clear probe timer since the RecvWindow is opened.
1018   //
1019   if (Tcb->ProbeTimerOn && (Seg->Wnd != 0)) {
1020     TcpClearTimer (Tcb, TCP_TIMER_PROBE);
1021     Tcb->ProbeTimerOn = FALSE;
1022   }
1023 
1024   //
1025   // First step: Check whether SEG.SEQ is acceptable
1026   //
1027   if (TcpSeqAcceptable (Tcb, Seg) == 0) {
1028     DEBUG (
1029       (EFI_D_WARN,
1030       "TcpInput: sequence acceptance test failed for segment of TCB %p\n",
1031       Tcb)
1032       );
1033 
1034     if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
1035       TcpSendAck (Tcb);
1036     }
1037 
1038     goto DISCARD;
1039   }
1040 
1041   if ((TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2)) &&
1042       (Tcb->RcvWl2 == Seg->End) &&
1043       !TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN))
1044   {
1045 
1046     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
1047   }
1048 
1049   //
1050   // Second step: Check the RST
1051   //
1052   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
1053 
1054     DEBUG ((EFI_D_WARN, "TcpInput: connection reset for TCB %p\n", Tcb));
1055 
1056     if (Tcb->State == TCP_SYN_RCVD) {
1057 
1058       SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_REFUSED);
1059 
1060       //
1061       // This TCB comes from either a LISTEN TCB,
1062       // or active open TCB with simultanous open.
1063       // Do NOT signal user CONNECTION refused
1064       // if it comes from a LISTEN TCB.
1065       //
1066     } else if ((Tcb->State == TCP_ESTABLISHED) ||
1067                (Tcb->State == TCP_FIN_WAIT_1) ||
1068                (Tcb->State == TCP_FIN_WAIT_2) ||
1069                (Tcb->State == TCP_CLOSE_WAIT))
1070     {
1071 
1072       SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);
1073 
1074     } else {
1075     }
1076 
1077     goto DROP_CONNECTION;
1078   }
1079 
1080   //
1081   // Trim the data and flags.
1082   //
1083   TcpTrimInWnd (Tcb, Nbuf);
1084 
1085   //
1086   // Third step: Check security and precedence, Ignored
1087   //
1088 
1089   //
1090   // Fourth step: Check the SYN bit.
1091   //
1092   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
1093 
1094     DEBUG (
1095       (EFI_D_WARN,
1096       "TcpInput: connection reset because received extra SYN for TCB %p\n",
1097       Tcb)
1098       );
1099 
1100     SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);
1101     goto RESET_THEN_DROP;
1102   }
1103   //
1104   // Fifth step: Check the ACK
1105   //
1106   if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
1107     DEBUG (
1108       (EFI_D_WARN,
1109       "TcpInput: segment discard because of no ACK for connected TCB %p\n",
1110       Tcb)
1111       );
1112 
1113     goto DISCARD;
1114   } else {
1115     if (Tcb->IpInfo->IpVersion == IP_VERSION_6 && Tcb->Tick == 0) {
1116       Tcp6RefreshNeighbor (Tcb, Src, TCP6_KEEP_NEIGHBOR_TIME * TICKS_PER_SECOND);
1117       Tcb->Tick = TCP6_REFRESH_NEIGHBOR_TICK;
1118     }
1119   }
1120 
1121   if (Tcb->State == TCP_SYN_RCVD) {
1122 
1123     if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) &&
1124         TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt))
1125     {
1126 
1127       Tcb->SndWnd     = Seg->Wnd;
1128       Tcb->SndWndMax  = MAX (Tcb->SndWnd, Tcb->SndWndMax);
1129       Tcb->SndWl1     = Seg->Seq;
1130       Tcb->SndWl2     = Seg->Ack;
1131       TcpSetState (Tcb, TCP_ESTABLISHED);
1132 
1133       TcpClearTimer (Tcb, TCP_TIMER_CONNECT);
1134       TcpDeliverData (Tcb);
1135 
1136       DEBUG (
1137         (EFI_D_NET,
1138         "TcpInput: connection established for TCB %p in SYN_RCVD\n",
1139         Tcb)
1140         );
1141 
1142       //
1143       // Continue the process as ESTABLISHED state
1144       //
1145     } else {
1146       DEBUG (
1147         (EFI_D_WARN,
1148         "TcpInput: send reset because of wrong ACK for TCB %p in SYN_RCVD\n",
1149         Tcb)
1150         );
1151 
1152       goto SEND_RESET;
1153     }
1154   }
1155 
1156   if (TCP_SEQ_LT (Seg->Ack, Tcb->SndUna)) {
1157 
1158     DEBUG (
1159       (EFI_D_WARN,
1160       "TcpInput: ignore the out-of-data ACK for connected TCB %p\n",
1161       Tcb)
1162       );
1163 
1164     goto StepSix;
1165 
1166   } else if (TCP_SEQ_GT (Seg->Ack, Tcb->SndNxt)) {
1167 
1168     DEBUG (
1169       (EFI_D_WARN,
1170       "TcpInput: discard segment for future ACK for connected TCB %p\n",
1171       Tcb)
1172       );
1173 
1174     TcpSendAck (Tcb);
1175     goto DISCARD;
1176   }
1177 
1178   //
1179   // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1180   //
1181   if (TCP_FLG_ON (Option.Flag, TCP_OPTION_RCVD_TS)) {
1182     //
1183     // update TsRecent as specified in page 16 RFC1323.
1184     // RcvWl2 equals to the variable "LastAckSent"
1185     // defined there.
1186     //
1187     if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) &&
1188         TCP_SEQ_LT (Tcb->RcvWl2, Seg->End))
1189     {
1190 
1191       Tcb->TsRecent     = Option.TSVal;
1192       Tcb->TsRecentAge  = mTcpTick;
1193     }
1194 
1195     TcpComputeRtt (Tcb, TCP_SUB_TIME (mTcpTick, Option.TSEcr));
1196 
1197   } else if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {
1198 
1199     ASSERT (Tcb->CongestState == TCP_CONGEST_OPEN);
1200 
1201     TcpComputeRtt (Tcb, Tcb->RttMeasure);
1202     TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
1203   }
1204 
1205   if (Seg->Ack == Tcb->SndNxt) {
1206 
1207     TcpClearTimer (Tcb, TCP_TIMER_REXMIT);
1208   } else {
1209 
1210     TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);
1211   }
1212 
1213   //
1214   // Count duplicate acks.
1215   //
1216   if ((Seg->Ack == Tcb->SndUna) &&
1217       (Tcb->SndUna != Tcb->SndNxt) &&
1218       (Seg->Wnd == Tcb->SndWnd) &&
1219       (0 == Len))
1220   {
1221 
1222     Tcb->DupAck++;
1223   } else {
1224 
1225     Tcb->DupAck = 0;
1226   }
1227 
1228   //
1229   // Congestion avoidance, fast recovery and fast retransmission.
1230   //
1231   if (((Tcb->CongestState == TCP_CONGEST_OPEN) && (Tcb->DupAck < 3)) ||
1232       (Tcb->CongestState == TCP_CONGEST_LOSS))
1233   {
1234 
1235     if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {
1236 
1237       if (Tcb->CWnd < Tcb->Ssthresh) {
1238 
1239         Tcb->CWnd += Tcb->SndMss;
1240       } else {
1241 
1242         Tcb->CWnd += MAX (Tcb->SndMss * Tcb->SndMss / Tcb->CWnd, 1);
1243       }
1244 
1245       Tcb->CWnd = MIN (Tcb->CWnd, TCP_MAX_WIN << Tcb->SndWndScale);
1246     }
1247 
1248     if (Tcb->CongestState == TCP_CONGEST_LOSS) {
1249       TcpFastLossRecover (Tcb, Seg);
1250     }
1251   } else {
1252 
1253     TcpFastRecover (Tcb, Seg);
1254   }
1255 
1256   if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {
1257 
1258     TcpAdjustSndQue (Tcb, Seg->Ack);
1259     Tcb->SndUna = Seg->Ack;
1260 
1261     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&
1262         TCP_SEQ_LT (Tcb->SndUp, Seg->Ack))
1263     {
1264 
1265       TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
1266     }
1267   }
1268 
1269   //
1270   // Update window info
1271   //
1272   if (TCP_SEQ_LT (Tcb->SndWl1, Seg->Seq) ||
1273       ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack)))
1274   {
1275 
1276     Right = Seg->Ack + Seg->Wnd;
1277 
1278     if (TCP_SEQ_LT (Right, Tcb->SndWl2 + Tcb->SndWnd)) {
1279 
1280       if ((Tcb->SndWl1 == Seg->Seq) &&
1281           (Tcb->SndWl2 == Seg->Ack) &&
1282           (Len == 0))
1283       {
1284 
1285         goto NO_UPDATE;
1286       }
1287 
1288       DEBUG (
1289         (EFI_D_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 
1298         Tcb->Recover = Right;
1299       }
1300 
1301       if ((Tcb->CongestState == TCP_CONGEST_LOSS) &&
1302           (TCP_SEQ_LT (Right, Tcb->LossRecover)))
1303       {
1304 
1305         Tcb->LossRecover = Right;
1306       }
1307 
1308       if (TCP_SEQ_LT (Right, Tcb->SndNxt)) {
1309 
1310         Tcb->SndNxt = Right;
1311 
1312         if (Right == Tcb->SndUna) {
1313 
1314           TcpClearTimer (Tcb, TCP_TIMER_REXMIT);
1315           TcpSetProbeTimer (Tcb);
1316         }
1317       }
1318     }
1319 
1320     Tcb->SndWnd     = Seg->Wnd;
1321     Tcb->SndWndMax  = MAX (Tcb->SndWnd, Tcb->SndWndMax);
1322     Tcb->SndWl1     = Seg->Seq;
1323     Tcb->SndWl2     = Seg->Ack;
1324   }
1325 
1326 NO_UPDATE:
1327 
1328   if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) &&
1329       (Tcb->SndUna == Tcb->SndNxt))
1330   {
1331 
1332     DEBUG (
1333       (EFI_D_NET,
1334       "TcpInput: local FIN is ACKed by peer for connected TCB %p\n",
1335       Tcb)
1336       );
1337 
1338     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED);
1339   }
1340 
1341   //
1342   // Transit the state if proper.
1343   //
1344   switch (Tcb->State) {
1345   case TCP_FIN_WAIT_1:
1346 
1347     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {
1348 
1349       TcpSetState (Tcb, TCP_FIN_WAIT_2);
1350 
1351       TcpClearAllTimer (Tcb);
1352       TcpSetTimer (Tcb, TCP_TIMER_FINWAIT2, Tcb->FinWait2Timeout);
1353     }
1354 
1355   case TCP_FIN_WAIT_2:
1356 
1357     break;
1358 
1359   case TCP_CLOSE_WAIT:
1360     break;
1361 
1362   case TCP_CLOSING:
1363 
1364     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {
1365 
1366       TcpSetState (Tcb, TCP_TIME_WAIT);
1367 
1368       TcpClearAllTimer (Tcb);
1369 
1370       if (Tcb->TimeWaitTimeout != 0) {
1371 
1372         TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);
1373       } else {
1374 
1375         DEBUG (
1376           (EFI_D_WARN,
1377           "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1378           Tcb)
1379           );
1380 
1381         TcpClose (Tcb);
1382       }
1383     }
1384     break;
1385 
1386   case TCP_LAST_ACK:
1387 
1388     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {
1389 
1390       TcpSetState (Tcb, TCP_CLOSED);
1391     }
1392 
1393     break;
1394 
1395   case TCP_TIME_WAIT:
1396 
1397     TcpSendAck (Tcb);
1398 
1399     if (Tcb->TimeWaitTimeout != 0) {
1400 
1401       TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);
1402     } else {
1403 
1404       DEBUG (
1405         (EFI_D_WARN,
1406         "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1407         Tcb)
1408         );
1409 
1410       TcpClose (Tcb);
1411     }
1412     break;
1413 
1414   default:
1415     break;
1416   }
1417   //
1418   // Sixth step: Check the URG bit.update the Urg point
1419   // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1420   //
1421 StepSix:
1422 
1423   Tcb->Idle = 0;
1424   TcpSetKeepaliveTimer (Tcb);
1425 
1426   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) && !TCP_FIN_RCVD (Tcb->State)) {
1427 
1428     DEBUG (
1429       (EFI_D_NET,
1430       "TcpInput: received urgent data from peer for connected TCB %p\n",
1431       Tcb)
1432       );
1433 
1434     Urg = Seg->Seq + Seg->Urg;
1435 
1436     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&
1437         TCP_SEQ_GT (Urg, Tcb->RcvUp))
1438     {
1439 
1440       Tcb->RcvUp = Urg;
1441     } else {
1442 
1443       Tcb->RcvUp = Urg;
1444       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG);
1445     }
1446   }
1447   //
1448   // Seventh step: Process the segment data
1449   //
1450   if (Seg->End != Seg->Seq) {
1451 
1452     if (TCP_FIN_RCVD (Tcb->State)) {
1453 
1454       DEBUG (
1455         (EFI_D_WARN,
1456         "TcpInput: connection reset because data is lost for connected TCB %p\n",
1457         Tcb)
1458         );
1459 
1460       goto RESET_THEN_DROP;
1461     }
1462 
1463     if (TCP_LOCAL_CLOSED (Tcb->State) && (Nbuf->TotalSize != 0)) {
1464       DEBUG (
1465         (EFI_D_WARN,
1466         "TcpInput: connection reset because data is lost for connected TCB %p\n",
1467         Tcb)
1468         );
1469 
1470       goto RESET_THEN_DROP;
1471     }
1472 
1473     TcpQueueData (Tcb, Nbuf);
1474     if (TcpDeliverData (Tcb) == -1) {
1475       goto RESET_THEN_DROP;
1476     }
1477 
1478     if (!IsListEmpty (&Tcb->RcvQue)) {
1479       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
1480     }
1481   }
1482 
1483   //
1484   // Eighth step: check the FIN.
1485   // This step is moved to TcpDeliverData. FIN will be
1486   // processed in sequence there. Check the comments in
1487   // the beginning of the file header for information.
1488   //
1489 
1490   //
1491   // Tcb is a new child of the listening Parent,
1492   // commit it.
1493   //
1494   if (Parent != NULL) {
1495     Tcb->Parent = Parent;
1496     TcpInsertTcb (Tcb);
1497   }
1498 
1499   if ((Tcb->State != TCP_CLOSED) &&
1500       (TcpToSendData (Tcb, 0) == 0) &&
1501       (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || (Nbuf->TotalSize != 0)))
1502   {
1503 
1504     TcpToSendAck (Tcb);
1505   }
1506 
1507   NetbufFree (Nbuf);
1508   return 0;
1509 
1510 RESET_THEN_DROP:
1511   TcpSendReset (Tcb, Head, Len, Dst, Src, Version);
1512 
1513 DROP_CONNECTION:
1514   ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));
1515 
1516   NetbufFree (Nbuf);
1517   TcpClose (Tcb);
1518 
1519   return -1;
1520 
1521 SEND_RESET:
1522 
1523   TcpSendReset (Tcb, Head, Len, Dst, Src, Version);
1524 
1525 DISCARD:
1526 
1527   //
1528   // Tcb is a child of Parent, and it doesn't survive
1529   //
1530   DEBUG ((EFI_D_WARN, "TcpInput: Discard a packet\n"));
1531   NetbufFree (Nbuf);
1532 
1533   if ((Parent != NULL) && (Tcb != NULL)) {
1534 
1535     ASSERT (Tcb->Sk != NULL);
1536     TcpClose (Tcb);
1537   }
1538 
1539   return 0;
1540 }
1541 
1542 /**
1543   Process the received ICMP error messages for TCP.
1544 
1545   @param[in]  Nbuf     The buffer that contains part of the TCP segment without an IP header
1546                        truncated from the ICMP error packet.
1547   @param[in]  IcmpErr  The ICMP error code interpreted from an ICMP error packet.
1548   @param[in]  Src      Source address of the ICMP error message.
1549   @param[in]  Dst      Destination address of the ICMP error message.
1550   @param[in]  Version  IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates
1551                        IP6 stack.
1552 
1553 **/
1554 VOID
TcpIcmpInput(IN NET_BUF * Nbuf,IN UINT8 IcmpErr,IN EFI_IP_ADDRESS * Src,IN EFI_IP_ADDRESS * Dst,IN UINT8 Version)1555 TcpIcmpInput (
1556   IN NET_BUF         *Nbuf,
1557   IN UINT8           IcmpErr,
1558   IN EFI_IP_ADDRESS  *Src,
1559   IN EFI_IP_ADDRESS  *Dst,
1560   IN UINT8           Version
1561   )
1562 {
1563   TCP_HEAD         *Head;
1564   TCP_CB           *Tcb;
1565   TCP_SEQNO        Seq;
1566   EFI_STATUS       IcmpErrStatus;
1567   BOOLEAN          IcmpErrIsHard;
1568   BOOLEAN          IcmpErrNotify;
1569 
1570   if (Nbuf->TotalSize < sizeof (TCP_HEAD)) {
1571     goto CLEAN_EXIT;
1572   }
1573 
1574   Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);
1575   ASSERT (Head != NULL);
1576 
1577   Tcb = TcpLocateTcb (
1578           Head->DstPort,
1579           Dst,
1580           Head->SrcPort,
1581           Src,
1582           Version,
1583           FALSE
1584           );
1585   if (Tcb == NULL || Tcb->State == TCP_CLOSED) {
1586 
1587     goto CLEAN_EXIT;
1588   }
1589 
1590   //
1591   // Validate the sequence number.
1592   //
1593   Seq = NTOHL (Head->Seq);
1594   if (!(TCP_SEQ_LEQ (Tcb->SndUna, Seq) && TCP_SEQ_LT (Seq, Tcb->SndNxt))) {
1595 
1596     goto CLEAN_EXIT;
1597   }
1598 
1599   IcmpErrStatus = IpIoGetIcmpErrStatus (
1600                     IcmpErr,
1601                     Tcb->Sk->IpVersion,
1602                     &IcmpErrIsHard,
1603                     &IcmpErrNotify
1604                     );
1605 
1606   if (IcmpErrNotify) {
1607 
1608     SOCK_ERROR (Tcb->Sk, IcmpErrStatus);
1609   }
1610 
1611   if (IcmpErrIsHard) {
1612 
1613     TcpClose (Tcb);
1614   }
1615 
1616 CLEAN_EXIT:
1617 
1618   NetbufFree (Nbuf);
1619 }
1620