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