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