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