]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Input.c
Fixing function headers.
[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
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
8a67d61d 285 }\r
286\r
287 //\r
288 // Adjust the buffer header\r
289 //\r
290 if (TCP_SEQ_LT (Seg->Seq, Left)) {\r
291\r
292 Drop = TCP_SUB_SEQ (Left, Seg->Seq);\r
293 Urg = Seg->Seq + Seg->Urg;\r
294 Seg->Seq = Left;\r
295\r
296 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
297 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_SYN);\r
298 Drop--;\r
299 }\r
300\r
301 //\r
302 // Adjust the urgent point\r
303 //\r
304 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG)) {\r
305\r
306 if (TCP_SEQ_LT (Urg, Seg->Seq)) {\r
307\r
308 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG);\r
309 } else {\r
310 Seg->Urg = (UINT16) TCP_SUB_SEQ (Urg, Seg->Seq);\r
311 }\r
312 }\r
313\r
85511ddf 314 if (Drop != 0) {\r
8a67d61d 315 NetbufTrim (Nbuf, Drop, NET_BUF_HEAD);\r
316 }\r
317 }\r
318\r
319 //\r
320 // Adjust the buffer tail\r
321 //\r
322 if (TCP_SEQ_GT (Seg->End, Right)) {\r
323\r
324 Drop = TCP_SUB_SEQ (Seg->End, Right);\r
325 Seg->End = Right;\r
326\r
327 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
328 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_FIN);\r
329 Drop--;\r
330 }\r
331\r
85511ddf 332 if (Drop != 0) {\r
8a67d61d 333 NetbufTrim (Nbuf, Drop, NET_BUF_TAIL);\r
334 }\r
335 }\r
336\r
120db52c 337 ASSERT (TcpVerifySegment (Nbuf) != 0);\r
8a67d61d 338}\r
339\r
340\r
341/**\r
342 Trim off the data outside the tcb's receive window.\r
343\r
344 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
345 @param Nbuf Pointer to the NET_BUF containing the received tcp segment.\r
346\r
8a67d61d 347**/\r
276dcc1b 348VOID\r
8a67d61d 349TcpTrimInWnd (\r
350 IN TCP_CB *Tcb,\r
351 IN NET_BUF *Nbuf\r
352 )\r
353{\r
276dcc1b 354 TcpTrimSegment (Nbuf, Tcb->RcvNxt, Tcb->RcvWl2 + Tcb->RcvWnd);\r
8a67d61d 355}\r
356\r
357\r
358/**\r
359 Process the data and FIN flag, check whether to deliver\r
360 data to the socket layer.\r
361\r
362 @param Tcb Pointer to the TCP_CB of this TCP instance.\r
363\r
364 @retval 0 No error occurred to deliver data.\r
365 @retval -1 Error condition occurred. Proper response is to reset the\r
366 connection.\r
367\r
368**/\r
369INTN\r
370TcpDeliverData (\r
371 IN TCP_CB *Tcb\r
372 )\r
373{\r
e48e37fc 374 LIST_ENTRY *Entry;\r
8a67d61d 375 NET_BUF *Nbuf;\r
376 TCP_SEQNO Seq;\r
377 TCP_SEG *Seg;\r
378 UINT32 Urgent;\r
379\r
120db52c 380 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));\r
8a67d61d 381\r
382 //\r
383 // make sure there is some data queued,\r
384 // and TCP is in a proper state\r
385 //\r
e48e37fc 386 if (IsListEmpty (&Tcb->RcvQue) || !TCP_CONNECTED (Tcb->State)) {\r
8a67d61d 387\r
388 return 0;\r
389 }\r
390\r
391 //\r
392 // Deliver data to the socket layer\r
393 //\r
394 Entry = Tcb->RcvQue.ForwardLink;\r
395 Seq = Tcb->RcvNxt;\r
396\r
397 while (Entry != &Tcb->RcvQue) {\r
398 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
399 Seg = TCPSEG_NETBUF (Nbuf);\r
400\r
120db52c 401 ASSERT (TcpVerifySegment (Nbuf) != 0);\r
8a67d61d 402 ASSERT (Nbuf->Tcp == NULL);\r
403\r
404 if (TCP_SEQ_GT (Seg->Seq, Seq)) {\r
405 break;\r
406 }\r
407\r
408 Entry = Entry->ForwardLink;\r
409 Seq = Seg->End;\r
410 Tcb->RcvNxt = Seq;\r
411\r
e48e37fc 412 RemoveEntryList (&Nbuf->List);\r
8a67d61d 413\r
414 //\r
415 // RFC793 Eighth step: process FIN in sequence\r
416 //\r
417 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
418\r
419 //\r
420 // The peer sends to us junky data after FIN,\r
421 // reset the connection.\r
422 //\r
e48e37fc 423 if (!IsListEmpty (&Tcb->RcvQue)) {\r
424 DEBUG ((EFI_D_ERROR, "TcpDeliverData: data received after"\r
0e549d5b 425 " FIN from peer of TCB %p, reset connection\n", Tcb));\r
8a67d61d 426\r
427 NetbufFree (Nbuf);\r
428 return -1;\r
429 }\r
430\r
e48e37fc 431 DEBUG ((EFI_D_INFO, "TcpDeliverData: processing FIN "\r
0e549d5b 432 "from peer of TCB %p\n", Tcb));\r
8a67d61d 433\r
434 switch (Tcb->State) {\r
435 case TCP_SYN_RCVD:\r
436 case TCP_ESTABLISHED:\r
437\r
438 TcpSetState (Tcb, TCP_CLOSE_WAIT);\r
439 break;\r
440\r
441 case TCP_FIN_WAIT_1:\r
442\r
443 if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
444\r
445 TcpSetState (Tcb, TCP_CLOSING);\r
446 break;\r
447 }\r
448\r
449 //\r
450 // fall through\r
451 //\r
452 case TCP_FIN_WAIT_2:\r
453\r
454 TcpSetState (Tcb, TCP_TIME_WAIT);\r
455 TcpClearAllTimer (Tcb);\r
456\r
457 if (Tcb->TimeWaitTimeout != 0) {\r
458\r
459 TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
460 } else {\r
461\r
e48e37fc 462 DEBUG ((EFI_D_WARN, "Connection closed immediately "\r
0e549d5b 463 "because app disables TIME_WAIT timer for %p\n", Tcb));\r
8a67d61d 464\r
465 TcpSendAck (Tcb);\r
466 TcpClose (Tcb);\r
467 }\r
468 break;\r
469\r
470 case TCP_CLOSE_WAIT:\r
471 case TCP_CLOSING:\r
472 case TCP_LAST_ACK:\r
473 case TCP_TIME_WAIT:\r
474 //\r
475 // The peer sends to us junk FIN byte. Discard\r
476 // the buffer then reset the connection\r
477 //\r
478 NetbufFree (Nbuf);\r
479 return -1;\r
480 break;\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
498 if (Nbuf->TotalSize) {\r
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
535 IN TCP_CB *Tcb,\r
536 IN NET_BUF *Nbuf\r
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
8a67d61d 801 "failed to clone a child for TCB%x\n", Tcb));\r
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
927 //\r
928 // First step: Check whether SEG.SEQ is acceptable\r
929 //\r
85511ddf 930 if (TcpSeqAcceptable (Tcb, Seg) == 0) {\r
e48e37fc 931 DEBUG ((EFI_D_WARN, "TcpInput: sequence acceptance"\r
0e549d5b 932 " test failed for segment of TCB %p\n", Tcb));\r
8a67d61d 933\r
934 if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
935 TcpSendAck (Tcb);\r
936 }\r
937\r
938 goto DISCARD;\r
939 }\r
940\r
941 if ((TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2)) &&\r
942 (Tcb->RcvWl2 == Seg->End) &&\r
943 !TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN)) {\r
944\r
945 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
946 }\r
947\r
948 //\r
949 // Second step: Check the RST\r
950 //\r
951 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
952\r
0e549d5b 953 DEBUG ((EFI_D_WARN, "TcpInput: connection reset for TCB %p\n", Tcb));\r
8a67d61d 954\r
955 if (Tcb->State == TCP_SYN_RCVD) {\r
956\r
957 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_REFUSED);\r
958\r
959 //\r
960 // This TCB comes from either a LISTEN TCB,\r
961 // or active open TCB with simultanous open.\r
962 // Do NOT signal user CONNECTION refused\r
963 // if it comes from a LISTEN TCB.\r
964 //\r
965 } else if ((Tcb->State == TCP_ESTABLISHED) ||\r
120db52c 966 (Tcb->State == TCP_FIN_WAIT_1) ||\r
967 (Tcb->State == TCP_FIN_WAIT_2) ||\r
968 (Tcb->State == TCP_CLOSE_WAIT)) {\r
8a67d61d 969\r
970 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
971\r
972 } else {\r
dfc1f033 973\r
8a67d61d 974 }\r
975\r
976 goto DROP_CONNECTION;\r
977 }\r
978\r
979 //\r
980 // Trim the data and flags.\r
981 //\r
982 TcpTrimInWnd (Tcb, Nbuf);\r
983\r
984 //\r
985 // Third step: Check security and precedence, Ignored\r
986 //\r
987\r
988 //\r
989 // Fourth step: Check the SYN bit.\r
990 //\r
991 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
992\r
e48e37fc 993 DEBUG ((EFI_D_WARN, "TcpInput: connection reset "\r
0e549d5b 994 "because received extra SYN for TCB %p\n", Tcb));\r
8a67d61d 995\r
996 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
997 goto RESET_THEN_DROP;\r
998 }\r
999\r
1000 //\r
1001 // Fifth step: Check the ACK\r
1002 //\r
1003 if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
e48e37fc 1004 DEBUG ((EFI_D_WARN, "TcpInput: segment discard because"\r
0e549d5b 1005 " of no ACK for connected TCB %p\n", Tcb));\r
8a67d61d 1006\r
1007 goto DISCARD;\r
1008\r
1009 }\r
1010\r
1011 if (Tcb->State == TCP_SYN_RCVD) {\r
1012\r
1013 if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) &&\r
1014 TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt)) {\r
1015\r
1016 Tcb->SndWnd = Seg->Wnd;\r
36ee91ca 1017 Tcb->SndWndMax = MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
8a67d61d 1018 Tcb->SndWl1 = Seg->Seq;\r
1019 Tcb->SndWl2 = Seg->Ack;\r
1020 TcpSetState (Tcb, TCP_ESTABLISHED);\r
1021\r
1022 TcpClearTimer (Tcb, TCP_TIMER_CONNECT);\r
1023 TcpDeliverData (Tcb);\r
1024\r
e48e37fc 1025 DEBUG ((EFI_D_INFO, "TcpInput: connection established "\r
0e549d5b 1026 " for TCB %p in SYN_RCVD\n", Tcb));\r
8a67d61d 1027\r
1028 //\r
1029 // Continue the process as ESTABLISHED state\r
1030 //\r
1031 } else {\r
e48e37fc 1032 DEBUG ((EFI_D_WARN, "TcpInput: send reset because of"\r
0e549d5b 1033 " wrong ACK for TCB %p in SYN_RCVD\n", Tcb));\r
8a67d61d 1034\r
1035 goto SEND_RESET;\r
1036 }\r
1037 }\r
1038\r
1039 if (TCP_SEQ_LT (Seg->Ack, Tcb->SndUna)) {\r
1040\r
e48e37fc 1041 DEBUG ((EFI_D_WARN, "TcpInput: ignore the out-of-data"\r
0e549d5b 1042 " ACK for connected TCB %p\n", Tcb));\r
8a67d61d 1043\r
1044 goto StepSix;\r
1045\r
1046 } else if (TCP_SEQ_GT (Seg->Ack, Tcb->SndNxt)) {\r
1047\r
e48e37fc 1048 DEBUG ((EFI_D_WARN, "TcpInput: discard segment for "\r
0e549d5b 1049 "future ACK for connected TCB %p\n", Tcb));\r
8a67d61d 1050\r
1051 TcpSendAck (Tcb);\r
1052 goto DISCARD;\r
1053 }\r
1054\r
1055 //\r
1056 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.\r
1057 //\r
1058 if (TCP_FLG_ON (Option.Flag, TCP_OPTION_RCVD_TS)) {\r
1059 //\r
1060 // update TsRecent as specified in page 16 RFC1323.\r
1061 // RcvWl2 equals to the variable "LastAckSent"\r
1062 // defined there.\r
1063 //\r
1064 if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) &&\r
1065 TCP_SEQ_LT (Tcb->RcvWl2, Seg->End)) {\r
1066\r
1067 Tcb->TsRecent = Option.TSVal;\r
1068 Tcb->TsRecentAge = mTcpTick;\r
1069 }\r
1070\r
1071 TcpComputeRtt (Tcb, TCP_SUB_TIME (mTcpTick, Option.TSEcr));\r
1072\r
1073 } else if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
1074\r
1075 ASSERT (Tcb->CongestState == TCP_CONGEST_OPEN);\r
1076\r
1077 TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
1078 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
1079 }\r
1080\r
1081 if (Seg->Ack == Tcb->SndNxt) {\r
1082\r
1083 TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
1084 } else {\r
1085\r
1086 TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);\r
1087 }\r
1088\r
1089 //\r
1090 // Count duplicate acks.\r
1091 //\r
1092 if ((Seg->Ack == Tcb->SndUna) &&\r
1093 (Tcb->SndUna != Tcb->SndNxt) &&\r
1094 (Seg->Wnd == Tcb->SndWnd) &&\r
1095 (0 == Len)) {\r
1096\r
1097 Tcb->DupAck++;\r
1098 } else {\r
1099\r
1100 Tcb->DupAck = 0;\r
1101 }\r
1102\r
1103 //\r
1104 // Congestion avoidance, fast recovery and fast retransmission.\r
1105 //\r
1106 if (((Tcb->CongestState == TCP_CONGEST_OPEN) && (Tcb->DupAck < 3)) ||\r
1107 (Tcb->CongestState == TCP_CONGEST_LOSS)) {\r
1108\r
1109 if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
1110\r
1111 if (Tcb->CWnd < Tcb->Ssthresh) {\r
1112\r
1113 Tcb->CWnd += Tcb->SndMss;\r
1114 } else {\r
1115\r
36ee91ca 1116 Tcb->CWnd += MAX (Tcb->SndMss * Tcb->SndMss / Tcb->CWnd, 1);\r
8a67d61d 1117 }\r
1118\r
36ee91ca 1119 Tcb->CWnd = MIN (Tcb->CWnd, TCP_MAX_WIN << Tcb->SndWndScale);\r
8a67d61d 1120 }\r
1121\r
1122 if (Tcb->CongestState == TCP_CONGEST_LOSS) {\r
1123 TcpFastLossRecover (Tcb, Seg);\r
1124 }\r
1125 } else {\r
1126\r
1127 TcpFastRecover (Tcb, Seg);\r
1128 }\r
1129\r
1130 if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
1131\r
1132 TcpAdjustSndQue (Tcb, Seg->Ack);\r
1133 Tcb->SndUna = Seg->Ack;\r
1134\r
1135 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&\r
120db52c 1136 TCP_SEQ_LT (Tcb->SndUp, Seg->Ack)) {\r
8a67d61d 1137\r
1138 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);\r
1139 }\r
1140 }\r
1141\r
1142 //\r
1143 // Update window info\r
1144 //\r
1145 if (TCP_SEQ_LT (Tcb->SndWl1, Seg->Seq) ||\r
1146 ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack))) {\r
1147\r
1148 Right = Seg->Ack + Seg->Wnd;\r
1149\r
1150 if (TCP_SEQ_LT (Right, Tcb->SndWl2 + Tcb->SndWnd)) {\r
1151\r
1152 if ((Tcb->SndWl1 == Seg->Seq) &&\r
1153 (Tcb->SndWl2 == Seg->Ack) &&\r
1154 (Len == 0)) {\r
1155\r
1156 goto NO_UPDATE;\r
1157 }\r
1158\r
e48e37fc 1159 DEBUG ((EFI_D_WARN, "TcpInput: peer shrinks the"\r
dfc1f033 1160 " window for connected TCB %p\n", Tcb));\r
8a67d61d 1161\r
1162 if ((Tcb->CongestState == TCP_CONGEST_RECOVER) &&\r
1163 (TCP_SEQ_LT (Right, Tcb->Recover))) {\r
1164\r
1165 Tcb->Recover = Right;\r
1166 }\r
1167\r
1168 if ((Tcb->CongestState == TCP_CONGEST_LOSS) &&\r
1169 (TCP_SEQ_LT (Right, Tcb->LossRecover))) {\r
1170\r
1171 Tcb->LossRecover = Right;\r
1172 }\r
1173\r
1174 if (TCP_SEQ_LT (Right, Tcb->SndNxt)) {\r
1175\r
1176 Tcb->SndNxt = Right;\r
1177\r
1178 if (Right == Tcb->SndUna) {\r
1179\r
1180 TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
1181 TcpSetProbeTimer (Tcb);\r
1182 }\r
1183 }\r
1184 }\r
1185\r
1186 Tcb->SndWnd = Seg->Wnd;\r
36ee91ca 1187 Tcb->SndWndMax = MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
8a67d61d 1188 Tcb->SndWl1 = Seg->Seq;\r
1189 Tcb->SndWl2 = Seg->Ack;\r
1190 }\r
1191\r
1192NO_UPDATE:\r
1193\r
1194 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) &&\r
1195 (Tcb->SndUna == Tcb->SndNxt)) {\r
1196\r
e48e37fc 1197 DEBUG ((EFI_D_INFO, "TcpInput: local FIN is ACKed by"\r
0e549d5b 1198 " peer for connected TCB %p\n", Tcb));\r
8a67d61d 1199\r
1200 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED);\r
1201 }\r
1202\r
1203 //\r
1204 // Transit the state if proper.\r
1205 //\r
1206 switch (Tcb->State) {\r
1207 case TCP_FIN_WAIT_1:\r
1208\r
1209 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
1210\r
1211 TcpSetState (Tcb, TCP_FIN_WAIT_2);\r
1212\r
1213 TcpClearAllTimer (Tcb);\r
1214 TcpSetTimer (Tcb, TCP_TIMER_FINWAIT2, Tcb->FinWait2Timeout);\r
1215 }\r
1216\r
1217 case TCP_FIN_WAIT_2:\r
1218\r
1219 break;\r
1220\r
1221 case TCP_CLOSE_WAIT:\r
1222 break;\r
1223\r
1224 case TCP_CLOSING:\r
1225\r
1226 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
1227\r
1228 TcpSetState (Tcb, TCP_TIME_WAIT);\r
1229\r
1230 TcpClearAllTimer (Tcb);\r
1231\r
1232 if (Tcb->TimeWaitTimeout != 0) {\r
1233\r
1234 TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
1235 } else {\r
1236\r
e48e37fc 1237 DEBUG ((EFI_D_WARN, "Connection closed immediately "\r
0e549d5b 1238 "because app disables TIME_WAIT timer for %p\n", Tcb));\r
8a67d61d 1239\r
1240 TcpClose (Tcb);\r
1241 }\r
1242 }\r
1243 break;\r
1244\r
1245 case TCP_LAST_ACK:\r
1246\r
1247 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
1248\r
1249 TcpSetState (Tcb, TCP_CLOSED);\r
1250 }\r
1251\r
1252 break;\r
1253\r
1254 case TCP_TIME_WAIT:\r
1255\r
1256 TcpSendAck (Tcb);\r
1257\r
1258 if (Tcb->TimeWaitTimeout != 0) {\r
1259\r
1260 TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
1261 } else {\r
1262\r
e48e37fc 1263 DEBUG ((EFI_D_WARN, "Connection closed immediately "\r
0e549d5b 1264 "because app disables TIME_WAIT timer for %p\n", Tcb));\r
8a67d61d 1265\r
1266 TcpClose (Tcb);\r
1267 }\r
1268 break;\r
1269 }\r
1270\r
1271 //\r
1272 // Sixth step: Check the URG bit.update the Urg point\r
1273 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.\r
1274 //\r
1275StepSix:\r
1276\r
1277 Tcb->Idle = 0;\r
1278 TcpSetKeepaliveTimer (Tcb);\r
1279\r
1280 if (TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_PROBE)) {\r
1281\r
1282 TcpClearTimer (Tcb, TCP_TIMER_PROBE);\r
1283 }\r
1284\r
1285 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) &&\r
1286 !TCP_FIN_RCVD (Tcb->State)) {\r
1287\r
e48e37fc 1288 DEBUG ((EFI_D_INFO, "TcpInput: received urgent data "\r
0e549d5b 1289 "from peer for connected TCB %p\n", Tcb));\r
8a67d61d 1290\r
1291 Urg = Seg->Seq + Seg->Urg;\r
1292\r
1293 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&\r
1294 TCP_SEQ_GT (Urg, Tcb->RcvUp)) {\r
1295\r
1296 Tcb->RcvUp = Urg;\r
1297 } else {\r
1298\r
1299 Tcb->RcvUp = Urg;\r
1300 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG);\r
1301 }\r
1302 }\r
1303\r
1304 //\r
1305 // Seventh step: Process the segment data\r
1306 //\r
1307 if (Seg->End != Seg->Seq) {\r
1308\r
1309 if (TCP_FIN_RCVD (Tcb->State)) {\r
1310\r
e48e37fc 1311 DEBUG ((EFI_D_WARN, "TcpInput: connection reset because"\r
0e549d5b 1312 " data is lost for connected TCB %p\n", Tcb));\r
8a67d61d 1313\r
1314 goto RESET_THEN_DROP;\r
1315 }\r
1316\r
1317 if (TCP_LOCAL_CLOSED (Tcb->State) && (Nbuf->TotalSize != 0)) {\r
e48e37fc 1318 DEBUG ((EFI_D_WARN, "TcpInput: connection reset because"\r
0e549d5b 1319 " data is lost for connected TCB %p\n", Tcb));\r
8a67d61d 1320\r
1321 goto RESET_THEN_DROP;\r
1322 }\r
1323\r
1324 TcpQueueData (Tcb, Nbuf);\r
1325 if (TcpDeliverData (Tcb) == -1) {\r
1326 goto RESET_THEN_DROP;\r
1327 }\r
1328\r
e48e37fc 1329 if (!IsListEmpty (&Tcb->RcvQue)) {\r
8a67d61d 1330 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
1331 }\r
1332 }\r
1333\r
1334 //\r
1335 // Eighth step: check the FIN.\r
1336 // This step is moved to TcpDeliverData. FIN will be\r
1337 // processed in sequence there. Check the comments in\r
1338 // the beginning of the file header for information.\r
1339 //\r
1340\r
1341 //\r
1342 // Tcb is a new child of the listening Parent,\r
1343 // commit it.\r
1344 //\r
85511ddf 1345 if (Parent != NULL) {\r
8a67d61d 1346 Tcb->Parent = Parent;\r
1347 TcpInsertTcb (Tcb);\r
1348 }\r
1349\r
1350 if ((Tcb->State != TCP_CLOSED) &&\r
85511ddf 1351 (TcpToSendData (Tcb, 0) == 0) &&\r
8a67d61d 1352 (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || Nbuf->TotalSize)) {\r
1353\r
1354 TcpToSendAck (Tcb);\r
1355 }\r
1356\r
1357 NetbufFree (Nbuf);\r
1358 return 0;\r
1359\r
1360RESET_THEN_DROP:\r
1361 TcpSendReset (Tcb, Head, Len, Dst, Src);\r
1362\r
1363DROP_CONNECTION:\r
120db52c 1364 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));\r
8a67d61d 1365\r
1366 NetbufFree (Nbuf);\r
1367 TcpClose (Tcb);\r
1368\r
1369 return -1;\r
1370\r
1371SEND_RESET:\r
1372\r
1373 TcpSendReset (Tcb, Head, Len, Dst, Src);\r
1374\r
1375DISCARD:\r
1376\r
1377 //\r
1378 // Tcb is a child of Parent, and it doesn't survive\r
1379 //\r
e48e37fc 1380 DEBUG ((EFI_D_WARN, "Tcp4Input: Discard a packet\n"));\r
8a67d61d 1381 NetbufFree (Nbuf);\r
1382\r
85511ddf 1383 if ((Parent != NULL) && (Tcb != NULL)) {\r
8a67d61d 1384\r
120db52c 1385 ASSERT (Tcb->Sk != NULL);\r
8a67d61d 1386 TcpClose (Tcb);\r
1387 }\r
1388\r
1389 return 0;\r
1390}\r
1391\r
1392\r
1393/**\r
1394 Process the received ICMP error messages for TCP.\r
1395\r
1396 @param Nbuf Buffer that contains part of the TCP segment without IP header\r
1397 truncated from the ICMP error packet.\r
1398 @param IcmpErr The ICMP error code interpreted from ICMP error packet.\r
1399 @param Src Source address of the ICMP error message.\r
1400 @param Dst Destination address of the ICMP error message.\r
1401\r
8a67d61d 1402**/\r
1403VOID\r
1404TcpIcmpInput (\r
1405 IN NET_BUF *Nbuf,\r
1406 IN ICMP_ERROR IcmpErr,\r
1407 IN UINT32 Src,\r
1408 IN UINT32 Dst\r
1409 )\r
1410{\r
1411 TCP_HEAD *Head;\r
1412 TCP_CB *Tcb;\r
1413 TCP_SEQNO Seq;\r
1414 EFI_STATUS IcmpErrStatus;\r
1415 BOOLEAN IcmpErrIsHard;\r
1416 BOOLEAN IcmpErrNotify;\r
1417\r
1418 Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
1419 Tcb = TcpLocateTcb (\r
1420 Head->DstPort,\r
1421 Dst,\r
1422 Head->SrcPort,\r
1423 Src,\r
1424 FALSE\r
1425 );\r
1426 if (Tcb == NULL || Tcb->State == TCP_CLOSED) {\r
1427\r
1428 goto CLEAN_EXIT;\r
1429 }\r
1430\r
1431 //\r
1432 // Validate the sequence number.\r
1433 //\r
1434 Seq = NTOHL (Head->Seq);\r
1435 if (!(TCP_SEQ_LEQ (Tcb->SndUna, Seq) && TCP_SEQ_LT (Seq, Tcb->SndNxt))) {\r
1436\r
1437 goto CLEAN_EXIT;\r
1438 }\r
1439\r
1440 IcmpErrStatus = IpIoGetIcmpErrStatus (IcmpErr, &IcmpErrIsHard, &IcmpErrNotify);\r
1441\r
1442 if (IcmpErrNotify) {\r
1443\r
1444 SOCK_ERROR (Tcb->Sk, IcmpErrStatus);\r
1445 }\r
1446\r
1447 if (IcmpErrIsHard) {\r
1448\r
1449 TcpClose (Tcb);\r
1450 }\r
1451\r
1452CLEAN_EXIT:\r
1453 NetbufFree (Nbuf);\r
1454}\r