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