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