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