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