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