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