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