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