1 /** @file
2   TCP input process routines.
3 
4   Copyright (c) 2009 - 2015, 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->RcvWl2, 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_INFO,
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_INFO,
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_INFO,
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_INFO,
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_INFO,
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_INFO,
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_INFO,
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_INFO,
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   Len     = Nbuf->TotalSize - (Head->HeadLen << 2);
752 
753   if ((Head->HeadLen < 5) || (Len < 0)) {
754 
755     DEBUG ((EFI_D_INFO, "TcpInput: received a malformed packet\n"));
756     goto DISCARD;
757   }
758 
759   if (Version == IP_VERSION_4) {
760     Checksum = NetPseudoHeadChecksum (Src->Addr[0], Dst->Addr[0], 6, 0);
761   } else {
762     Checksum = NetIp6PseudoHeadChecksum (&Src->v6, &Dst->v6, 6, 0);
763   }
764 
765   Checksum = TcpChecksum (Nbuf, Checksum);
766 
767   if (Checksum != 0) {
768     DEBUG ((EFI_D_ERROR, "TcpInput: received a checksum error packet\n"));
769     goto DISCARD;
770   }
771 
772   if (TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)) {
773     Len++;
774   }
775 
776   if (TCP_FLG_ON (Head->Flag, TCP_FLG_FIN)) {
777     Len++;
778   }
779 
780   Tcb = TcpLocateTcb (
781           Head->DstPort,
782           Dst,
783           Head->SrcPort,
784           Src,
785           Version,
786           (BOOLEAN) TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)
787           );
788 
789   if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {
790     DEBUG ((EFI_D_INFO, "TcpInput: send reset because no TCB found\n"));
791 
792     Tcb = NULL;
793     goto SEND_RESET;
794   }
795 
796   Seg = TcpFormatNetbuf (Tcb, Nbuf);
797 
798   //
799   // RFC1122 recommended reaction to illegal option
800   // (in fact, an illegal option length) is reset.
801   //
802   if (TcpParseOption (Nbuf->Tcp, &Option) == -1) {
803     DEBUG (
804       (EFI_D_ERROR,
805       "TcpInput: reset the peer because of malformed option for TCB %p\n",
806       Tcb)
807       );
808 
809     goto SEND_RESET;
810   }
811 
812   //
813   // From now on, the segment is headless
814   //
815   NetbufTrim (Nbuf, (Head->HeadLen << 2), NET_BUF_HEAD);
816   Nbuf->Tcp = NULL;
817 
818   //
819   // Process the segment in LISTEN state.
820   //
821   if (Tcb->State == TCP_LISTEN) {
822     //
823     // First step: Check RST
824     //
825     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
826       DEBUG (
827         (EFI_D_WARN,
828         "TcpInput: discard a reset segment for TCB %p in listening\n",
829         Tcb)
830         );
831 
832       goto DISCARD;
833     }
834 
835     //
836     // Second step: Check ACK.
837     // Any ACK sent to TCP in LISTEN is reseted.
838     //
839     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
840       DEBUG (
841         (EFI_D_WARN,
842         "TcpInput: send reset because of segment with ACK for TCB %p in listening\n",
843         Tcb)
844         );
845 
846       goto SEND_RESET;
847     }
848 
849     //
850     // Third step: Check SYN
851     //
852     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
853       //
854       // create a child TCB to handle the data
855       //
856       Parent  = Tcb;
857 
858       Tcb     = TcpCloneTcb (Parent);
859       if (Tcb == NULL) {
860         DEBUG (
861           (EFI_D_ERROR,
862           "TcpInput: discard a segment because failed to clone a child for TCB %p\n",
863           Tcb)
864           );
865 
866         goto DISCARD;
867       }
868 
869       DEBUG (
870         (EFI_D_INFO,
871         "TcpInput: create a child for TCB %p in listening\n",
872         Tcb)
873         );
874 
875       //
876       // init the TCB structure
877       //
878       IP6_COPY_ADDRESS (&Tcb->LocalEnd.Ip, Dst);
879       IP6_COPY_ADDRESS (&Tcb->RemoteEnd.Ip, Src);
880       Tcb->LocalEnd.Port  = Head->DstPort;
881       Tcb->RemoteEnd.Port = Head->SrcPort;
882 
883       TcpInitTcbLocal (Tcb);
884       TcpInitTcbPeer (Tcb, Seg, &Option);
885 
886       TcpSetState (Tcb, TCP_SYN_RCVD);
887       TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);
888       TcpTrimInWnd (Tcb, Nbuf);
889 
890       goto StepSix;
891     }
892 
893     goto DISCARD;
894 
895   } else if (Tcb->State == TCP_SYN_SENT) {
896     //
897     // First step: Check ACK bit
898     //
899     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK) && (Seg->Ack != Tcb->Iss + 1)) {
900 
901       DEBUG (
902         (EFI_D_WARN,
903         "TcpInput: send reset because of wrong ACK received for TCB %p in SYN_SENT\n",
904         Tcb)
905         );
906 
907       goto SEND_RESET;
908     }
909 
910     //
911     // Second step: Check RST bit
912     //
913     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
914 
915       if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
916 
917         DEBUG (
918           (EFI_D_WARN,
919           "TcpInput: connection reset by peer for TCB %p in SYN_SENT\n",
920           Tcb)
921           );
922 
923         SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);
924         goto DROP_CONNECTION;
925       } else {
926 
927         DEBUG (
928           (EFI_D_WARN,
929           "TcpInput: discard a reset segment because of no ACK for TCB %p in SYN_SENT\n",
930           Tcb)
931           );
932 
933         goto DISCARD;
934       }
935     }
936 
937     //
938     // Third step: Check security and precedence. Skipped
939     //
940 
941     //
942     // Fourth step: Check SYN. Pay attention to simultaneous open
943     //
944     if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
945 
946       TcpInitTcbPeer (Tcb, Seg, &Option);
947 
948       if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
949 
950         Tcb->SndUna = Seg->Ack;
951       }
952 
953       TcpClearTimer (Tcb, TCP_TIMER_REXMIT);
954 
955       if (TCP_SEQ_GT (Tcb->SndUna, Tcb->Iss)) {
956 
957         TcpSetState (Tcb, TCP_ESTABLISHED);
958 
959         TcpClearTimer (Tcb, TCP_TIMER_CONNECT);
960         TcpDeliverData (Tcb);
961 
962         if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&
963             TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON))
964         {
965 
966           TcpComputeRtt (Tcb, Tcb->RttMeasure);
967           TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
968         }
969 
970         TcpTrimInWnd (Tcb, Nbuf);
971 
972         TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
973 
974         DEBUG (
975           (EFI_D_INFO,
976           "TcpInput: connection established for TCB %p in SYN_SENT\n",
977           Tcb)
978           );
979 
980         goto StepSix;
981       } else {
982         //
983         // Received a SYN segment without ACK, simultanous open.
984         //
985         TcpSetState (Tcb, TCP_SYN_RCVD);
986 
987         ASSERT (Tcb->SndNxt == Tcb->Iss + 1);
988         TcpAdjustSndQue (Tcb, Tcb->SndNxt);
989 
990         TcpTrimInWnd (Tcb, Nbuf);
991 
992         DEBUG (
993           (EFI_D_WARN,
994           "TcpInput: simultaneous open for TCB %p in SYN_SENT\n",
995           Tcb)
996           );
997 
998         goto StepSix;
999       }
1000     }
1001 
1002     goto DISCARD;
1003   }
1004 
1005   //
1006   // Process segment in SYN_RCVD or TCP_CONNECTED states
1007   //
1008 
1009   //
1010   // Clear probe timer since the RecvWindow is opened.
1011   //
1012   if (Tcb->ProbeTimerOn && (Seg->Wnd != 0)) {
1013     TcpClearTimer (Tcb, TCP_TIMER_PROBE);
1014     Tcb->ProbeTimerOn = FALSE;
1015   }
1016 
1017   //
1018   // First step: Check whether SEG.SEQ is acceptable
1019   //
1020   if (TcpSeqAcceptable (Tcb, Seg) == 0) {
1021     DEBUG (
1022       (EFI_D_WARN,
1023       "TcpInput: sequence acceptance test failed for segment of TCB %p\n",
1024       Tcb)
1025       );
1026 
1027     if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
1028       TcpSendAck (Tcb);
1029     }
1030 
1031     goto DISCARD;
1032   }
1033 
1034   if ((TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2)) &&
1035       (Tcb->RcvWl2 == Seg->End) &&
1036       !TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN))
1037   {
1038 
1039     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
1040   }
1041 
1042   //
1043   // Second step: Check the RST
1044   //
1045   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {
1046 
1047     DEBUG ((EFI_D_WARN, "TcpInput: connection reset for TCB %p\n", Tcb));
1048 
1049     if (Tcb->State == TCP_SYN_RCVD) {
1050 
1051       SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_REFUSED);
1052 
1053       //
1054       // This TCB comes from either a LISTEN TCB,
1055       // or active open TCB with simultanous open.
1056       // Do NOT signal user CONNECTION refused
1057       // if it comes from a LISTEN TCB.
1058       //
1059     } else if ((Tcb->State == TCP_ESTABLISHED) ||
1060                (Tcb->State == TCP_FIN_WAIT_1) ||
1061                (Tcb->State == TCP_FIN_WAIT_2) ||
1062                (Tcb->State == TCP_CLOSE_WAIT))
1063     {
1064 
1065       SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);
1066 
1067     } else {
1068     }
1069 
1070     goto DROP_CONNECTION;
1071   }
1072 
1073   //
1074   // Trim the data and flags.
1075   //
1076   TcpTrimInWnd (Tcb, Nbuf);
1077 
1078   //
1079   // Third step: Check security and precedence, Ignored
1080   //
1081 
1082   //
1083   // Fourth step: Check the SYN bit.
1084   //
1085   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
1086 
1087     DEBUG (
1088       (EFI_D_WARN,
1089       "TcpInput: connection reset because received extra SYN for TCB %p\n",
1090       Tcb)
1091       );
1092 
1093     SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);
1094     goto RESET_THEN_DROP;
1095   }
1096   //
1097   // Fifth step: Check the ACK
1098   //
1099   if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {
1100     DEBUG (
1101       (EFI_D_WARN,
1102       "TcpInput: segment discard because of no ACK for connected TCB %p\n",
1103       Tcb)
1104       );
1105 
1106     goto DISCARD;
1107   } else {
1108     if (Tcb->IpInfo->IpVersion == IP_VERSION_6 && Tcb->Tick == 0) {
1109       Tcp6RefreshNeighbor (Tcb, Src, TCP6_KEEP_NEIGHBOR_TIME * TICKS_PER_SECOND);
1110       Tcb->Tick = TCP6_REFRESH_NEIGHBOR_TICK;
1111     }
1112   }
1113 
1114   if (Tcb->State == TCP_SYN_RCVD) {
1115 
1116     if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) &&
1117         TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt))
1118     {
1119 
1120       Tcb->SndWnd     = Seg->Wnd;
1121       Tcb->SndWndMax  = MAX (Tcb->SndWnd, Tcb->SndWndMax);
1122       Tcb->SndWl1     = Seg->Seq;
1123       Tcb->SndWl2     = Seg->Ack;
1124       TcpSetState (Tcb, TCP_ESTABLISHED);
1125 
1126       TcpClearTimer (Tcb, TCP_TIMER_CONNECT);
1127       TcpDeliverData (Tcb);
1128 
1129       DEBUG (
1130         (EFI_D_INFO,
1131         "TcpInput: connection established for TCB %p in SYN_RCVD\n",
1132         Tcb)
1133         );
1134 
1135       //
1136       // Continue the process as ESTABLISHED state
1137       //
1138     } else {
1139       DEBUG (
1140         (EFI_D_WARN,
1141         "TcpInput: send reset because of wrong ACK for TCB %p in SYN_RCVD\n",
1142         Tcb)
1143         );
1144 
1145       goto SEND_RESET;
1146     }
1147   }
1148 
1149   if (TCP_SEQ_LT (Seg->Ack, Tcb->SndUna)) {
1150 
1151     DEBUG (
1152       (EFI_D_WARN,
1153       "TcpInput: ignore the out-of-data ACK for connected TCB %p\n",
1154       Tcb)
1155       );
1156 
1157     goto StepSix;
1158 
1159   } else if (TCP_SEQ_GT (Seg->Ack, Tcb->SndNxt)) {
1160 
1161     DEBUG (
1162       (EFI_D_WARN,
1163       "TcpInput: discard segment for future ACK for connected TCB %p\n",
1164       Tcb)
1165       );
1166 
1167     TcpSendAck (Tcb);
1168     goto DISCARD;
1169   }
1170 
1171   //
1172   // From now on: SND.UNA <= SEG.ACK <= SND.NXT.
1173   //
1174   if (TCP_FLG_ON (Option.Flag, TCP_OPTION_RCVD_TS)) {
1175     //
1176     // update TsRecent as specified in page 16 RFC1323.
1177     // RcvWl2 equals to the variable "LastAckSent"
1178     // defined there.
1179     //
1180     if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) &&
1181         TCP_SEQ_LT (Tcb->RcvWl2, Seg->End))
1182     {
1183 
1184       Tcb->TsRecent     = Option.TSVal;
1185       Tcb->TsRecentAge  = mTcpTick;
1186     }
1187 
1188     TcpComputeRtt (Tcb, TCP_SUB_TIME (mTcpTick, Option.TSEcr));
1189 
1190   } else if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {
1191 
1192     ASSERT (Tcb->CongestState == TCP_CONGEST_OPEN);
1193 
1194     TcpComputeRtt (Tcb, Tcb->RttMeasure);
1195     TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
1196   }
1197 
1198   if (Seg->Ack == Tcb->SndNxt) {
1199 
1200     TcpClearTimer (Tcb, TCP_TIMER_REXMIT);
1201   } else {
1202 
1203     TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);
1204   }
1205 
1206   //
1207   // Count duplicate acks.
1208   //
1209   if ((Seg->Ack == Tcb->SndUna) &&
1210       (Tcb->SndUna != Tcb->SndNxt) &&
1211       (Seg->Wnd == Tcb->SndWnd) &&
1212       (0 == Len))
1213   {
1214 
1215     Tcb->DupAck++;
1216   } else {
1217 
1218     Tcb->DupAck = 0;
1219   }
1220 
1221   //
1222   // Congestion avoidance, fast recovery and fast retransmission.
1223   //
1224   if (((Tcb->CongestState == TCP_CONGEST_OPEN) && (Tcb->DupAck < 3)) ||
1225       (Tcb->CongestState == TCP_CONGEST_LOSS))
1226   {
1227 
1228     if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {
1229 
1230       if (Tcb->CWnd < Tcb->Ssthresh) {
1231 
1232         Tcb->CWnd += Tcb->SndMss;
1233       } else {
1234 
1235         Tcb->CWnd += MAX (Tcb->SndMss * Tcb->SndMss / Tcb->CWnd, 1);
1236       }
1237 
1238       Tcb->CWnd = MIN (Tcb->CWnd, TCP_MAX_WIN << Tcb->SndWndScale);
1239     }
1240 
1241     if (Tcb->CongestState == TCP_CONGEST_LOSS) {
1242       TcpFastLossRecover (Tcb, Seg);
1243     }
1244   } else {
1245 
1246     TcpFastRecover (Tcb, Seg);
1247   }
1248 
1249   if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {
1250 
1251     TcpAdjustSndQue (Tcb, Seg->Ack);
1252     Tcb->SndUna = Seg->Ack;
1253 
1254     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&
1255         TCP_SEQ_LT (Tcb->SndUp, Seg->Ack))
1256     {
1257 
1258       TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);
1259     }
1260   }
1261 
1262   //
1263   // Update window info
1264   //
1265   if (TCP_SEQ_LT (Tcb->SndWl1, Seg->Seq) ||
1266       ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack)))
1267   {
1268 
1269     Right = Seg->Ack + Seg->Wnd;
1270 
1271     if (TCP_SEQ_LT (Right, Tcb->SndWl2 + Tcb->SndWnd)) {
1272 
1273       if ((Tcb->SndWl1 == Seg->Seq) &&
1274           (Tcb->SndWl2 == Seg->Ack) &&
1275           (Len == 0))
1276       {
1277 
1278         goto NO_UPDATE;
1279       }
1280 
1281       DEBUG (
1282         (EFI_D_WARN,
1283         "TcpInput: peer shrinks the window for connected TCB %p\n",
1284         Tcb)
1285         );
1286 
1287       if ((Tcb->CongestState == TCP_CONGEST_RECOVER) &&
1288           (TCP_SEQ_LT (Right, Tcb->Recover)))
1289       {
1290 
1291         Tcb->Recover = Right;
1292       }
1293 
1294       if ((Tcb->CongestState == TCP_CONGEST_LOSS) &&
1295           (TCP_SEQ_LT (Right, Tcb->LossRecover)))
1296       {
1297 
1298         Tcb->LossRecover = Right;
1299       }
1300 
1301       if (TCP_SEQ_LT (Right, Tcb->SndNxt)) {
1302 
1303         Tcb->SndNxt = Right;
1304 
1305         if (Right == Tcb->SndUna) {
1306 
1307           TcpClearTimer (Tcb, TCP_TIMER_REXMIT);
1308           TcpSetProbeTimer (Tcb);
1309         }
1310       }
1311     }
1312 
1313     Tcb->SndWnd     = Seg->Wnd;
1314     Tcb->SndWndMax  = MAX (Tcb->SndWnd, Tcb->SndWndMax);
1315     Tcb->SndWl1     = Seg->Seq;
1316     Tcb->SndWl2     = Seg->Ack;
1317   }
1318 
1319 NO_UPDATE:
1320 
1321   if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) &&
1322       (Tcb->SndUna == Tcb->SndNxt))
1323   {
1324 
1325     DEBUG (
1326       (EFI_D_INFO,
1327       "TcpInput: local FIN is ACKed by peer for connected TCB %p\n",
1328       Tcb)
1329       );
1330 
1331     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED);
1332   }
1333 
1334   //
1335   // Transit the state if proper.
1336   //
1337   switch (Tcb->State) {
1338   case TCP_FIN_WAIT_1:
1339 
1340     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {
1341 
1342       TcpSetState (Tcb, TCP_FIN_WAIT_2);
1343 
1344       TcpClearAllTimer (Tcb);
1345       TcpSetTimer (Tcb, TCP_TIMER_FINWAIT2, Tcb->FinWait2Timeout);
1346     }
1347 
1348   case TCP_FIN_WAIT_2:
1349 
1350     break;
1351 
1352   case TCP_CLOSE_WAIT:
1353     break;
1354 
1355   case TCP_CLOSING:
1356 
1357     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {
1358 
1359       TcpSetState (Tcb, TCP_TIME_WAIT);
1360 
1361       TcpClearAllTimer (Tcb);
1362 
1363       if (Tcb->TimeWaitTimeout != 0) {
1364 
1365         TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);
1366       } else {
1367 
1368         DEBUG (
1369           (EFI_D_WARN,
1370           "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1371           Tcb)
1372           );
1373 
1374         TcpClose (Tcb);
1375       }
1376     }
1377     break;
1378 
1379   case TCP_LAST_ACK:
1380 
1381     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {
1382 
1383       TcpSetState (Tcb, TCP_CLOSED);
1384     }
1385 
1386     break;
1387 
1388   case TCP_TIME_WAIT:
1389 
1390     TcpSendAck (Tcb);
1391 
1392     if (Tcb->TimeWaitTimeout != 0) {
1393 
1394       TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);
1395     } else {
1396 
1397       DEBUG (
1398         (EFI_D_WARN,
1399         "Connection closed immediately because app disables TIME_WAIT timer for %p\n",
1400         Tcb)
1401         );
1402 
1403       TcpClose (Tcb);
1404     }
1405     break;
1406 
1407   default:
1408     break;
1409   }
1410   //
1411   // Sixth step: Check the URG bit.update the Urg point
1412   // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.
1413   //
1414 StepSix:
1415 
1416   Tcb->Idle = 0;
1417   TcpSetKeepaliveTimer (Tcb);
1418 
1419   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) && !TCP_FIN_RCVD (Tcb->State)) {
1420 
1421     DEBUG (
1422       (EFI_D_INFO,
1423       "TcpInput: received urgent data from peer for connected TCB %p\n",
1424       Tcb)
1425       );
1426 
1427     Urg = Seg->Seq + Seg->Urg;
1428 
1429     if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&
1430         TCP_SEQ_GT (Urg, Tcb->RcvUp))
1431     {
1432 
1433       Tcb->RcvUp = Urg;
1434     } else {
1435 
1436       Tcb->RcvUp = Urg;
1437       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG);
1438     }
1439   }
1440   //
1441   // Seventh step: Process the segment data
1442   //
1443   if (Seg->End != Seg->Seq) {
1444 
1445     if (TCP_FIN_RCVD (Tcb->State)) {
1446 
1447       DEBUG (
1448         (EFI_D_WARN,
1449         "TcpInput: connection reset because data is lost for connected TCB %p\n",
1450         Tcb)
1451         );
1452 
1453       goto RESET_THEN_DROP;
1454     }
1455 
1456     if (TCP_LOCAL_CLOSED (Tcb->State) && (Nbuf->TotalSize != 0)) {
1457       DEBUG (
1458         (EFI_D_WARN,
1459         "TcpInput: connection reset because data is lost for connected TCB %p\n",
1460         Tcb)
1461         );
1462 
1463       goto RESET_THEN_DROP;
1464     }
1465 
1466     TcpQueueData (Tcb, Nbuf);
1467     if (TcpDeliverData (Tcb) == -1) {
1468       goto RESET_THEN_DROP;
1469     }
1470 
1471     if (!IsListEmpty (&Tcb->RcvQue)) {
1472       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
1473     }
1474   }
1475 
1476   //
1477   // Eighth step: check the FIN.
1478   // This step is moved to TcpDeliverData. FIN will be
1479   // processed in sequence there. Check the comments in
1480   // the beginning of the file header for information.
1481   //
1482 
1483   //
1484   // Tcb is a new child of the listening Parent,
1485   // commit it.
1486   //
1487   if (Parent != NULL) {
1488     Tcb->Parent = Parent;
1489     TcpInsertTcb (Tcb);
1490   }
1491 
1492   if ((Tcb->State != TCP_CLOSED) &&
1493       (TcpToSendData (Tcb, 0) == 0) &&
1494       (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || (Nbuf->TotalSize != 0)))
1495   {
1496 
1497     TcpToSendAck (Tcb);
1498   }
1499 
1500   NetbufFree (Nbuf);
1501   return 0;
1502 
1503 RESET_THEN_DROP:
1504   TcpSendReset (Tcb, Head, Len, Dst, Src, Version);
1505 
1506 DROP_CONNECTION:
1507   ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));
1508 
1509   NetbufFree (Nbuf);
1510   TcpClose (Tcb);
1511 
1512   return -1;
1513 
1514 SEND_RESET:
1515 
1516   TcpSendReset (Tcb, Head, Len, Dst, Src, Version);
1517 
1518 DISCARD:
1519 
1520   //
1521   // Tcb is a child of Parent, and it doesn't survive
1522   //
1523   DEBUG ((EFI_D_WARN, "TcpInput: Discard a packet\n"));
1524   NetbufFree (Nbuf);
1525 
1526   if ((Parent != NULL) && (Tcb != NULL)) {
1527 
1528     ASSERT (Tcb->Sk != NULL);
1529     TcpClose (Tcb);
1530   }
1531 
1532   return 0;
1533 }
1534 
1535 /**
1536   Process the received ICMP error messages for TCP.
1537 
1538   @param[in]  Nbuf     The buffer that contains part of the TCP segment without an IP header
1539                        truncated from the ICMP error packet.
1540   @param[in]  IcmpErr  The ICMP error code interpreted from an ICMP error packet.
1541   @param[in]  Src      Source address of the ICMP error message.
1542   @param[in]  Dst      Destination address of the ICMP error message.
1543   @param[in]  Version  IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates
1544                        IP6 stack.
1545 
1546 **/
1547 VOID
TcpIcmpInput(IN NET_BUF * Nbuf,IN UINT8 IcmpErr,IN EFI_IP_ADDRESS * Src,IN EFI_IP_ADDRESS * Dst,IN UINT8 Version)1548 TcpIcmpInput (
1549   IN NET_BUF         *Nbuf,
1550   IN UINT8           IcmpErr,
1551   IN EFI_IP_ADDRESS  *Src,
1552   IN EFI_IP_ADDRESS  *Dst,
1553   IN UINT8           Version
1554   )
1555 {
1556   TCP_HEAD         *Head;
1557   TCP_CB           *Tcb;
1558   TCP_SEQNO        Seq;
1559   EFI_STATUS       IcmpErrStatus;
1560   BOOLEAN          IcmpErrIsHard;
1561   BOOLEAN          IcmpErrNotify;
1562 
1563   Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);
1564   ASSERT (Head != NULL);
1565 
1566   Tcb = TcpLocateTcb (
1567           Head->DstPort,
1568           Dst,
1569           Head->SrcPort,
1570           Src,
1571           Version,
1572           FALSE
1573           );
1574   if (Tcb == NULL || Tcb->State == TCP_CLOSED) {
1575 
1576     goto CLEAN_EXIT;
1577   }
1578 
1579   //
1580   // Validate the sequence number.
1581   //
1582   Seq = NTOHL (Head->Seq);
1583   if (!(TCP_SEQ_LEQ (Tcb->SndUna, Seq) && TCP_SEQ_LT (Seq, Tcb->SndNxt))) {
1584 
1585     goto CLEAN_EXIT;
1586   }
1587 
1588   IcmpErrStatus = IpIoGetIcmpErrStatus (
1589                     IcmpErr,
1590                     Tcb->Sk->IpVersion,
1591                     &IcmpErrIsHard,
1592                     &IcmpErrNotify
1593                     );
1594 
1595   if (IcmpErrNotify) {
1596 
1597     SOCK_ERROR (Tcb->Sk, IcmpErrStatus);
1598   }
1599 
1600   if (IcmpErrIsHard) {
1601 
1602     TcpClose (Tcb);
1603   }
1604 
1605 CLEAN_EXIT:
1606 
1607   NetbufFree (Nbuf);
1608 }
1609