]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/TcpDxe/TcpInput.c
SecurityPkg: Add TPM PTP support in TCG2 SMM.
[mirror_edk2.git] / NetworkPkg / TcpDxe / TcpInput.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 TCP input process routines.\r
3\r
49789216 4 Copyright (c) 2009 - 2015, 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
34 return (TCP_SEQ_LEQ (Tcb->RcvWl2, Seg->End) &&\r
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
751 Len = Nbuf->TotalSize - (Head->HeadLen << 2);\r
752\r
753 if ((Head->HeadLen < 5) || (Len < 0)) {\r
754\r
49789216 755 DEBUG ((EFI_D_INFO, "TcpInput: received a malformed packet\n"));\r
a3bcde70
HT
756 goto DISCARD;\r
757 }\r
758\r
759 if (Version == IP_VERSION_4) {\r
760 Checksum = NetPseudoHeadChecksum (Src->Addr[0], Dst->Addr[0], 6, 0);\r
761 } else {\r
762 Checksum = NetIp6PseudoHeadChecksum (&Src->v6, &Dst->v6, 6, 0);\r
763 }\r
764\r
765 Checksum = TcpChecksum (Nbuf, Checksum);\r
766\r
767 if (Checksum != 0) {\r
768 DEBUG ((EFI_D_ERROR, "TcpInput: received a checksum error packet\n"));\r
769 goto DISCARD;\r
770 }\r
771\r
772 if (TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)) {\r
773 Len++;\r
774 }\r
775\r
776 if (TCP_FLG_ON (Head->Flag, TCP_FLG_FIN)) {\r
777 Len++;\r
778 }\r
779\r
780 Tcb = TcpLocateTcb (\r
781 Head->DstPort,\r
782 Dst,\r
783 Head->SrcPort,\r
784 Src,\r
785 Version,\r
786 (BOOLEAN) TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)\r
787 );\r
788\r
789 if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {\r
49789216 790 DEBUG ((EFI_D_INFO, "TcpInput: send reset because no TCB found\n"));\r
a3bcde70
HT
791\r
792 Tcb = NULL;\r
793 goto SEND_RESET;\r
794 }\r
795\r
796 Seg = TcpFormatNetbuf (Tcb, Nbuf);\r
797\r
798 //\r
799 // RFC1122 recommended reaction to illegal option\r
800 // (in fact, an illegal option length) is reset.\r
801 //\r
802 if (TcpParseOption (Nbuf->Tcp, &Option) == -1) {\r
803 DEBUG (\r
804 (EFI_D_ERROR,\r
49789216 805 "TcpInput: reset the peer because of malformed option for TCB %p\n",\r
a3bcde70
HT
806 Tcb)\r
807 );\r
808\r
809 goto SEND_RESET;\r
810 }\r
811\r
812 //\r
813 // From now on, the segment is headless\r
814 //\r
815 NetbufTrim (Nbuf, (Head->HeadLen << 2), NET_BUF_HEAD);\r
816 Nbuf->Tcp = NULL;\r
817\r
818 //\r
819 // Process the segment in LISTEN state.\r
820 //\r
821 if (Tcb->State == TCP_LISTEN) {\r
822 //\r
823 // First step: Check RST\r
824 //\r
825 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
826 DEBUG (\r
827 (EFI_D_WARN,\r
828 "TcpInput: discard a reset segment for TCB %p in listening\n",\r
829 Tcb)\r
830 );\r
831\r
832 goto DISCARD;\r
833 }\r
834\r
835 //\r
836 // Second step: Check ACK.\r
837 // Any ACK sent to TCP in LISTEN is reseted.\r
838 //\r
839 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
840 DEBUG (\r
841 (EFI_D_WARN,\r
842 "TcpInput: send reset because of segment with ACK for TCB %p in listening\n",\r
843 Tcb)\r
844 );\r
845\r
846 goto SEND_RESET;\r
847 }\r
848\r
849 //\r
850 // Third step: Check SYN\r
851 //\r
852 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
853 //\r
854 // create a child TCB to handle the data\r
855 //\r
856 Parent = Tcb;\r
857\r
858 Tcb = TcpCloneTcb (Parent);\r
859 if (Tcb == NULL) {\r
860 DEBUG (\r
861 (EFI_D_ERROR,\r
49789216 862 "TcpInput: discard a segment because failed to clone a child for TCB %p\n",\r
a3bcde70
HT
863 Tcb)\r
864 );\r
865\r
866 goto DISCARD;\r
867 }\r
868\r
869 DEBUG (\r
870 (EFI_D_INFO,\r
871 "TcpInput: create a child for TCB %p in listening\n",\r
872 Tcb)\r
873 );\r
874\r
875 //\r
876 // init the TCB structure\r
877 //\r
878 IP6_COPY_ADDRESS (&Tcb->LocalEnd.Ip, Dst);\r
879 IP6_COPY_ADDRESS (&Tcb->RemoteEnd.Ip, Src);\r
880 Tcb->LocalEnd.Port = Head->DstPort;\r
881 Tcb->RemoteEnd.Port = Head->SrcPort;\r
882\r
883 TcpInitTcbLocal (Tcb);\r
884 TcpInitTcbPeer (Tcb, Seg, &Option);\r
885\r
886 TcpSetState (Tcb, TCP_SYN_RCVD);\r
887 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
888 TcpTrimInWnd (Tcb, Nbuf);\r
889\r
890 goto StepSix;\r
891 }\r
892\r
893 goto DISCARD;\r
894\r
895 } else if (Tcb->State == TCP_SYN_SENT) {\r
896 //\r
897 // First step: Check ACK bit\r
898 //\r
899 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK) && (Seg->Ack != Tcb->Iss + 1)) {\r
900\r
901 DEBUG (\r
902 (EFI_D_WARN,\r
903 "TcpInput: send reset because of wrong ACK received for TCB %p in SYN_SENT\n",\r
904 Tcb)\r
905 );\r
906\r
907 goto SEND_RESET;\r
908 }\r
909\r
910 //\r
911 // Second step: Check RST bit\r
912 //\r
913 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
914\r
915 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
916\r
917 DEBUG (\r
918 (EFI_D_WARN,\r
919 "TcpInput: connection reset by peer for TCB %p in SYN_SENT\n",\r
920 Tcb)\r
921 );\r
922\r
923 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
924 goto DROP_CONNECTION;\r
925 } else {\r
926\r
927 DEBUG (\r
928 (EFI_D_WARN,\r
929 "TcpInput: discard a reset segment because of no ACK for TCB %p in SYN_SENT\n",\r
930 Tcb)\r
931 );\r
932\r
933 goto DISCARD;\r
934 }\r
935 }\r
936\r
937 //\r
938 // Third step: Check security and precedence. Skipped\r
939 //\r
940\r
941 //\r
49789216 942 // Fourth step: Check SYN. Pay attention to simultaneous open\r
a3bcde70
HT
943 //\r
944 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
945\r
946 TcpInitTcbPeer (Tcb, Seg, &Option);\r
947\r
948 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
949\r
950 Tcb->SndUna = Seg->Ack;\r
951 }\r
952\r
953 TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
954\r
955 if (TCP_SEQ_GT (Tcb->SndUna, Tcb->Iss)) {\r
956\r
957 TcpSetState (Tcb, TCP_ESTABLISHED);\r
958\r
959 TcpClearTimer (Tcb, TCP_TIMER_CONNECT);\r
960 TcpDeliverData (Tcb);\r
961\r
962 if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&\r
49789216
BZ
963 TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON))\r
964 {\r
a3bcde70
HT
965\r
966 TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
967 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
968 }\r
969\r
970 TcpTrimInWnd (Tcb, Nbuf);\r
971\r
972 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
973\r
974 DEBUG (\r
975 (EFI_D_INFO,\r
976 "TcpInput: connection established for TCB %p in SYN_SENT\n",\r
977 Tcb)\r
978 );\r
979\r
980 goto StepSix;\r
981 } else {\r
982 //\r
983 // Received a SYN segment without ACK, simultanous open.\r
984 //\r
985 TcpSetState (Tcb, TCP_SYN_RCVD);\r
986\r
987 ASSERT (Tcb->SndNxt == Tcb->Iss + 1);\r
988 TcpAdjustSndQue (Tcb, Tcb->SndNxt);\r
989\r
990 TcpTrimInWnd (Tcb, Nbuf);\r
991\r
992 DEBUG (\r
993 (EFI_D_WARN,\r
49789216 994 "TcpInput: simultaneous open for TCB %p in SYN_SENT\n",\r
a3bcde70
HT
995 Tcb)\r
996 );\r
997\r
998 goto StepSix;\r
999 }\r
1000 }\r
1001\r
1002 goto DISCARD;\r
1003 }\r
1004\r
1005 //\r
1006 // Process segment in SYN_RCVD or TCP_CONNECTED states\r
1007 //\r
1008\r
1009 //\r
1010 // Clear probe timer since the RecvWindow is opened.\r
1011 //\r
1012 if (Tcb->ProbeTimerOn && (Seg->Wnd != 0)) {\r
1013 TcpClearTimer (Tcb, TCP_TIMER_PROBE);\r
1014 Tcb->ProbeTimerOn = FALSE;\r
1015 }\r
1016\r
1017 //\r
1018 // First step: Check whether SEG.SEQ is acceptable\r
1019 //\r
1020 if (TcpSeqAcceptable (Tcb, Seg) == 0) {\r
1021 DEBUG (\r
1022 (EFI_D_WARN,\r
1023 "TcpInput: sequence acceptance test failed for segment of TCB %p\n",\r
1024 Tcb)\r
1025 );\r
1026\r
1027 if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
1028 TcpSendAck (Tcb);\r
1029 }\r
1030\r
1031 goto DISCARD;\r
1032 }\r
1033\r
1034 if ((TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2)) &&\r
1035 (Tcb->RcvWl2 == Seg->End) &&\r
49789216
BZ
1036 !TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN))\r
1037 {\r
a3bcde70
HT
1038\r
1039 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
1040 }\r
1041\r
1042 //\r
1043 // Second step: Check the RST\r
1044 //\r
1045 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
1046\r
1047 DEBUG ((EFI_D_WARN, "TcpInput: connection reset for TCB %p\n", Tcb));\r
1048\r
1049 if (Tcb->State == TCP_SYN_RCVD) {\r
1050\r
1051 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_REFUSED);\r
1052\r
1053 //\r
1054 // This TCB comes from either a LISTEN TCB,\r
1055 // or active open TCB with simultanous open.\r
1056 // Do NOT signal user CONNECTION refused\r
1057 // if it comes from a LISTEN TCB.\r
1058 //\r
1059 } else if ((Tcb->State == TCP_ESTABLISHED) ||\r
49789216
BZ
1060 (Tcb->State == TCP_FIN_WAIT_1) ||\r
1061 (Tcb->State == TCP_FIN_WAIT_2) ||\r
1062 (Tcb->State == TCP_CLOSE_WAIT))\r
1063 {\r
a3bcde70
HT
1064\r
1065 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
1066\r
1067 } else {\r
1068 }\r
1069\r
1070 goto DROP_CONNECTION;\r
1071 }\r
1072\r
1073 //\r
1074 // Trim the data and flags.\r
1075 //\r
1076 TcpTrimInWnd (Tcb, Nbuf);\r
1077\r
1078 //\r
1079 // Third step: Check security and precedence, Ignored\r
1080 //\r
1081\r
1082 //\r
1083 // Fourth step: Check the SYN bit.\r
1084 //\r
1085 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
1086\r
1087 DEBUG (\r
1088 (EFI_D_WARN,\r
1089 "TcpInput: connection reset because received extra SYN for TCB %p\n",\r
1090 Tcb)\r
1091 );\r
1092\r
1093 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
1094 goto RESET_THEN_DROP;\r
1095 }\r
1096 //\r
1097 // Fifth step: Check the ACK\r
1098 //\r
1099 if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
1100 DEBUG (\r
1101 (EFI_D_WARN,\r
1102 "TcpInput: segment discard because of no ACK for connected TCB %p\n",\r
1103 Tcb)\r
1104 );\r
1105\r
1106 goto DISCARD;\r
1107 } else {\r
1108 if (Tcb->IpInfo->IpVersion == IP_VERSION_6 && Tcb->Tick == 0) {\r
1109 Tcp6RefreshNeighbor (Tcb, Src, TCP6_KEEP_NEIGHBOR_TIME * TICKS_PER_SECOND);\r
1110 Tcb->Tick = TCP6_REFRESH_NEIGHBOR_TICK;\r
1111 }\r
1112 }\r
1113\r
1114 if (Tcb->State == TCP_SYN_RCVD) {\r
1115\r
49789216
BZ
1116 if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) &&\r
1117 TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt))\r
1118 {\r
a3bcde70
HT
1119\r
1120 Tcb->SndWnd = Seg->Wnd;\r
1121 Tcb->SndWndMax = MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
1122 Tcb->SndWl1 = Seg->Seq;\r
1123 Tcb->SndWl2 = Seg->Ack;\r
1124 TcpSetState (Tcb, TCP_ESTABLISHED);\r
1125\r
1126 TcpClearTimer (Tcb, TCP_TIMER_CONNECT);\r
1127 TcpDeliverData (Tcb);\r
1128\r
1129 DEBUG (\r
1130 (EFI_D_INFO,\r
49789216 1131 "TcpInput: connection established for TCB %p in SYN_RCVD\n",\r
a3bcde70
HT
1132 Tcb)\r
1133 );\r
1134\r
1135 //\r
1136 // Continue the process as ESTABLISHED state\r
1137 //\r
1138 } else {\r
1139 DEBUG (\r
1140 (EFI_D_WARN,\r
1141 "TcpInput: send reset because of wrong ACK for TCB %p in SYN_RCVD\n",\r
1142 Tcb)\r
1143 );\r
1144\r
1145 goto SEND_RESET;\r
1146 }\r
1147 }\r
1148\r
1149 if (TCP_SEQ_LT (Seg->Ack, Tcb->SndUna)) {\r
1150\r
1151 DEBUG (\r
1152 (EFI_D_WARN,\r
1153 "TcpInput: ignore the out-of-data ACK for connected TCB %p\n",\r
1154 Tcb)\r
1155 );\r
1156\r
1157 goto StepSix;\r
1158\r
1159 } else if (TCP_SEQ_GT (Seg->Ack, Tcb->SndNxt)) {\r
1160\r
1161 DEBUG (\r
1162 (EFI_D_WARN,\r
1163 "TcpInput: discard segment for future ACK for connected TCB %p\n",\r
1164 Tcb)\r
1165 );\r
1166\r
1167 TcpSendAck (Tcb);\r
1168 goto DISCARD;\r
1169 }\r
1170\r
1171 //\r
1172 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.\r
1173 //\r
1174 if (TCP_FLG_ON (Option.Flag, TCP_OPTION_RCVD_TS)) {\r
1175 //\r
1176 // update TsRecent as specified in page 16 RFC1323.\r
1177 // RcvWl2 equals to the variable "LastAckSent"\r
1178 // defined there.\r
1179 //\r
49789216
BZ
1180 if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) &&\r
1181 TCP_SEQ_LT (Tcb->RcvWl2, Seg->End))\r
1182 {\r
a3bcde70
HT
1183\r
1184 Tcb->TsRecent = Option.TSVal;\r
1185 Tcb->TsRecentAge = mTcpTick;\r
1186 }\r
1187\r
1188 TcpComputeRtt (Tcb, TCP_SUB_TIME (mTcpTick, Option.TSEcr));\r
1189\r
1190 } else if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
1191\r
1192 ASSERT (Tcb->CongestState == TCP_CONGEST_OPEN);\r
1193\r
1194 TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
1195 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
1196 }\r
1197\r
1198 if (Seg->Ack == Tcb->SndNxt) {\r
1199\r
1200 TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
1201 } else {\r
1202\r
1203 TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);\r
1204 }\r
1205\r
1206 //\r
1207 // Count duplicate acks.\r
1208 //\r
1209 if ((Seg->Ack == Tcb->SndUna) &&\r
1210 (Tcb->SndUna != Tcb->SndNxt) &&\r
1211 (Seg->Wnd == Tcb->SndWnd) &&\r
49789216
BZ
1212 (0 == Len))\r
1213 {\r
a3bcde70
HT
1214\r
1215 Tcb->DupAck++;\r
1216 } else {\r
1217\r
1218 Tcb->DupAck = 0;\r
1219 }\r
1220\r
1221 //\r
1222 // Congestion avoidance, fast recovery and fast retransmission.\r
1223 //\r
1224 if (((Tcb->CongestState == TCP_CONGEST_OPEN) && (Tcb->DupAck < 3)) ||\r
49789216
BZ
1225 (Tcb->CongestState == TCP_CONGEST_LOSS))\r
1226 {\r
a3bcde70
HT
1227\r
1228 if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
1229\r
1230 if (Tcb->CWnd < Tcb->Ssthresh) {\r
1231\r
1232 Tcb->CWnd += Tcb->SndMss;\r
1233 } else {\r
1234\r
1235 Tcb->CWnd += MAX (Tcb->SndMss * Tcb->SndMss / Tcb->CWnd, 1);\r
1236 }\r
1237\r
1238 Tcb->CWnd = MIN (Tcb->CWnd, TCP_MAX_WIN << Tcb->SndWndScale);\r
1239 }\r
1240\r
1241 if (Tcb->CongestState == TCP_CONGEST_LOSS) {\r
1242 TcpFastLossRecover (Tcb, Seg);\r
1243 }\r
1244 } else {\r
1245\r
1246 TcpFastRecover (Tcb, Seg);\r
1247 }\r
1248\r
1249 if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
1250\r
1251 TcpAdjustSndQue (Tcb, Seg->Ack);\r
1252 Tcb->SndUna = Seg->Ack;\r
1253\r
1254 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&\r
49789216
BZ
1255 TCP_SEQ_LT (Tcb->SndUp, Seg->Ack))\r
1256 {\r
a3bcde70
HT
1257\r
1258 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);\r
1259 }\r
1260 }\r
1261\r
1262 //\r
1263 // Update window info\r
1264 //\r
1265 if (TCP_SEQ_LT (Tcb->SndWl1, Seg->Seq) ||\r
49789216
BZ
1266 ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack)))\r
1267 {\r
a3bcde70
HT
1268\r
1269 Right = Seg->Ack + Seg->Wnd;\r
1270\r
1271 if (TCP_SEQ_LT (Right, Tcb->SndWl2 + Tcb->SndWnd)) {\r
1272\r
1273 if ((Tcb->SndWl1 == Seg->Seq) &&\r
1274 (Tcb->SndWl2 == Seg->Ack) &&\r
49789216
BZ
1275 (Len == 0))\r
1276 {\r
a3bcde70
HT
1277\r
1278 goto NO_UPDATE;\r
1279 }\r
1280\r
1281 DEBUG (\r
1282 (EFI_D_WARN,\r
1283 "TcpInput: peer shrinks the window for connected TCB %p\n",\r
1284 Tcb)\r
1285 );\r
1286\r
49789216
BZ
1287 if ((Tcb->CongestState == TCP_CONGEST_RECOVER) &&\r
1288 (TCP_SEQ_LT (Right, Tcb->Recover)))\r
1289 {\r
a3bcde70
HT
1290\r
1291 Tcb->Recover = Right;\r
1292 }\r
1293\r
49789216
BZ
1294 if ((Tcb->CongestState == TCP_CONGEST_LOSS) &&\r
1295 (TCP_SEQ_LT (Right, Tcb->LossRecover)))\r
1296 {\r
a3bcde70
HT
1297\r
1298 Tcb->LossRecover = Right;\r
1299 }\r
1300\r
1301 if (TCP_SEQ_LT (Right, Tcb->SndNxt)) {\r
1302\r
1303 Tcb->SndNxt = Right;\r
1304\r
1305 if (Right == Tcb->SndUna) {\r
1306\r
1307 TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
1308 TcpSetProbeTimer (Tcb);\r
1309 }\r
1310 }\r
1311 }\r
1312\r
1313 Tcb->SndWnd = Seg->Wnd;\r
1314 Tcb->SndWndMax = MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
1315 Tcb->SndWl1 = Seg->Seq;\r
1316 Tcb->SndWl2 = Seg->Ack;\r
1317 }\r
1318\r
1319NO_UPDATE:\r
1320\r
49789216
BZ
1321 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) &&\r
1322 (Tcb->SndUna == Tcb->SndNxt))\r
1323 {\r
a3bcde70
HT
1324\r
1325 DEBUG (\r
1326 (EFI_D_INFO,\r
1327 "TcpInput: local FIN is ACKed by peer for connected TCB %p\n",\r
1328 Tcb)\r
1329 );\r
1330\r
1331 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED);\r
1332 }\r
1333\r
1334 //\r
1335 // Transit the state if proper.\r
1336 //\r
1337 switch (Tcb->State) {\r
1338 case TCP_FIN_WAIT_1:\r
1339\r
1340 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
1341\r
1342 TcpSetState (Tcb, TCP_FIN_WAIT_2);\r
1343\r
1344 TcpClearAllTimer (Tcb);\r
1345 TcpSetTimer (Tcb, TCP_TIMER_FINWAIT2, Tcb->FinWait2Timeout);\r
1346 }\r
1347\r
1348 case TCP_FIN_WAIT_2:\r
1349\r
1350 break;\r
1351\r
1352 case TCP_CLOSE_WAIT:\r
1353 break;\r
1354\r
1355 case TCP_CLOSING:\r
1356\r
1357 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
1358\r
1359 TcpSetState (Tcb, TCP_TIME_WAIT);\r
1360\r
1361 TcpClearAllTimer (Tcb);\r
1362\r
1363 if (Tcb->TimeWaitTimeout != 0) {\r
1364\r
1365 TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
1366 } else {\r
1367\r
1368 DEBUG (\r
1369 (EFI_D_WARN,\r
1370 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",\r
1371 Tcb)\r
1372 );\r
1373\r
1374 TcpClose (Tcb);\r
1375 }\r
1376 }\r
1377 break;\r
1378\r
1379 case TCP_LAST_ACK:\r
1380\r
1381 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
1382\r
1383 TcpSetState (Tcb, TCP_CLOSED);\r
1384 }\r
1385\r
1386 break;\r
1387\r
1388 case TCP_TIME_WAIT:\r
1389\r
1390 TcpSendAck (Tcb);\r
1391\r
1392 if (Tcb->TimeWaitTimeout != 0) {\r
1393\r
1394 TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
1395 } else {\r
1396\r
1397 DEBUG (\r
1398 (EFI_D_WARN,\r
1399 "Connection closed immediately because app disables TIME_WAIT timer for %p\n",\r
1400 Tcb)\r
1401 );\r
1402\r
1403 TcpClose (Tcb);\r
1404 }\r
1405 break;\r
1406\r
1407 default:\r
1408 break;\r
1409 }\r
1410 //\r
1411 // Sixth step: Check the URG bit.update the Urg point\r
1412 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.\r
1413 //\r
1414StepSix:\r
1415\r
1416 Tcb->Idle = 0;\r
1417 TcpSetKeepaliveTimer (Tcb);\r
1418\r
1419 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) && !TCP_FIN_RCVD (Tcb->State)) {\r
1420\r
1421 DEBUG (\r
1422 (EFI_D_INFO,\r
1423 "TcpInput: received urgent data from peer for connected TCB %p\n",\r
1424 Tcb)\r
1425 );\r
1426\r
1427 Urg = Seg->Seq + Seg->Urg;\r
1428\r
49789216
BZ
1429 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&\r
1430 TCP_SEQ_GT (Urg, Tcb->RcvUp))\r
1431 {\r
a3bcde70
HT
1432\r
1433 Tcb->RcvUp = Urg;\r
1434 } else {\r
1435\r
1436 Tcb->RcvUp = Urg;\r
1437 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG);\r
1438 }\r
1439 }\r
1440 //\r
1441 // Seventh step: Process the segment data\r
1442 //\r
1443 if (Seg->End != Seg->Seq) {\r
1444\r
1445 if (TCP_FIN_RCVD (Tcb->State)) {\r
1446\r
1447 DEBUG (\r
1448 (EFI_D_WARN,\r
1449 "TcpInput: connection reset because data is lost for connected TCB %p\n",\r
1450 Tcb)\r
1451 );\r
1452\r
1453 goto RESET_THEN_DROP;\r
1454 }\r
1455\r
1456 if (TCP_LOCAL_CLOSED (Tcb->State) && (Nbuf->TotalSize != 0)) {\r
1457 DEBUG (\r
1458 (EFI_D_WARN,\r
1459 "TcpInput: connection reset because data is lost for connected TCB %p\n",\r
1460 Tcb)\r
1461 );\r
1462\r
1463 goto RESET_THEN_DROP;\r
1464 }\r
1465\r
1466 TcpQueueData (Tcb, Nbuf);\r
1467 if (TcpDeliverData (Tcb) == -1) {\r
1468 goto RESET_THEN_DROP;\r
1469 }\r
1470\r
1471 if (!IsListEmpty (&Tcb->RcvQue)) {\r
1472 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
1473 }\r
1474 }\r
1475\r
1476 //\r
1477 // Eighth step: check the FIN.\r
1478 // This step is moved to TcpDeliverData. FIN will be\r
1479 // processed in sequence there. Check the comments in\r
1480 // the beginning of the file header for information.\r
1481 //\r
1482\r
1483 //\r
1484 // Tcb is a new child of the listening Parent,\r
1485 // commit it.\r
1486 //\r
1487 if (Parent != NULL) {\r
1488 Tcb->Parent = Parent;\r
1489 TcpInsertTcb (Tcb);\r
1490 }\r
1491\r
1492 if ((Tcb->State != TCP_CLOSED) &&\r
1493 (TcpToSendData (Tcb, 0) == 0) &&\r
49789216
BZ
1494 (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || (Nbuf->TotalSize != 0)))\r
1495 {\r
a3bcde70
HT
1496\r
1497 TcpToSendAck (Tcb);\r
1498 }\r
1499\r
1500 NetbufFree (Nbuf);\r
1501 return 0;\r
1502\r
1503RESET_THEN_DROP:\r
1504 TcpSendReset (Tcb, Head, Len, Dst, Src, Version);\r
1505\r
1506DROP_CONNECTION:\r
1507 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));\r
1508\r
1509 NetbufFree (Nbuf);\r
1510 TcpClose (Tcb);\r
1511\r
1512 return -1;\r
1513\r
1514SEND_RESET:\r
1515\r
1516 TcpSendReset (Tcb, Head, Len, Dst, Src, Version);\r
1517\r
1518DISCARD:\r
1519\r
1520 //\r
1521 // Tcb is a child of Parent, and it doesn't survive\r
1522 //\r
1523 DEBUG ((EFI_D_WARN, "TcpInput: Discard a packet\n"));\r
1524 NetbufFree (Nbuf);\r
1525\r
1526 if ((Parent != NULL) && (Tcb != NULL)) {\r
1527\r
1528 ASSERT (Tcb->Sk != NULL);\r
1529 TcpClose (Tcb);\r
1530 }\r
1531\r
1532 return 0;\r
1533}\r
1534\r
1535/**\r
1536 Process the received ICMP error messages for TCP.\r
1537\r
1538 @param[in] Nbuf The buffer that contains part of the TCP segment without an IP header\r
1539 truncated from the ICMP error packet.\r
1540 @param[in] IcmpErr The ICMP error code interpreted from an ICMP error packet.\r
1541 @param[in] Src Source address of the ICMP error message.\r
1542 @param[in] Dst Destination address of the ICMP error message.\r
1543 @param[in] Version IP_VERSION_4 indicates IP4 stack. IP_VERSION_6 indicates\r
1544 IP6 stack.\r
1545\r
1546**/\r
1547VOID\r
1548TcpIcmpInput (\r
1549 IN NET_BUF *Nbuf,\r
1550 IN UINT8 IcmpErr,\r
1551 IN EFI_IP_ADDRESS *Src,\r
1552 IN EFI_IP_ADDRESS *Dst,\r
1553 IN UINT8 Version\r
1554 )\r
1555{\r
1556 TCP_HEAD *Head;\r
1557 TCP_CB *Tcb;\r
1558 TCP_SEQNO Seq;\r
1559 EFI_STATUS IcmpErrStatus;\r
1560 BOOLEAN IcmpErrIsHard;\r
1561 BOOLEAN IcmpErrNotify;\r
1562\r
1563 Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
1564 ASSERT (Head != NULL);\r
1565\r
1566 Tcb = TcpLocateTcb (\r
1567 Head->DstPort,\r
1568 Dst,\r
1569 Head->SrcPort,\r
1570 Src,\r
1571 Version,\r
1572 FALSE\r
1573 );\r
1574 if (Tcb == NULL || Tcb->State == TCP_CLOSED) {\r
1575\r
1576 goto CLEAN_EXIT;\r
1577 }\r
1578\r
1579 //\r
1580 // Validate the sequence number.\r
1581 //\r
1582 Seq = NTOHL (Head->Seq);\r
1583 if (!(TCP_SEQ_LEQ (Tcb->SndUna, Seq) && TCP_SEQ_LT (Seq, Tcb->SndNxt))) {\r
1584\r
1585 goto CLEAN_EXIT;\r
1586 }\r
1587\r
49789216
BZ
1588 IcmpErrStatus = IpIoGetIcmpErrStatus (\r
1589 IcmpErr,\r
1590 Tcb->Sk->IpVersion,\r
1591 &IcmpErrIsHard,\r
1592 &IcmpErrNotify\r
1593 );\r
a3bcde70
HT
1594\r
1595 if (IcmpErrNotify) {\r
1596\r
1597 SOCK_ERROR (Tcb->Sk, IcmpErrStatus);\r
1598 }\r
1599\r
1600 if (IcmpErrIsHard) {\r
1601\r
1602 TcpClose (Tcb);\r
1603 }\r
1604\r
1605CLEAN_EXIT:\r
1606\r
1607 NetbufFree (Nbuf);\r
1608}\r