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