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