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