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