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