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