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