]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Input.c
MdeModulePkg: Check received packet size before use it.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / Tcp4Input.c
CommitLineData
8a67d61d 1/** @file\r
dfc1f033 2 TCP input process routines.\r
8a67d61d 3\r
1b31acb6 4Copyright (c) 2005 - 2016, 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
49789216 64 FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);\r
8a67d61d 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
49789216 112 FlightSize = TCP_SUB_SEQ (Tcb->SndNxt, Tcb->SndUna);\r
8a67d61d 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
49789216 559 return;\r
8a67d61d 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
49789216
BZ
566 Cur != Head;\r
567 Prev = Cur, Cur = Cur->ForwardLink) {\r
8a67d61d 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
49789216 588 return;\r
8a67d61d 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
a56b6e03 713 ASSERT (Head != NULL);\r
1b31acb6
FS
714\r
715 if (Nbuf->TotalSize < sizeof (TCP_HEAD)) {\r
716 DEBUG ((EFI_D_INFO, "TcpInput: received a malformed packet\n"));\r
717 goto DISCARD;\r
718 }\r
719 \r
8a67d61d 720 Len = Nbuf->TotalSize - (Head->HeadLen << 2);\r
721\r
722 if ((Head->HeadLen < 5) || (Len < 0) ||\r
85511ddf 723 (TcpChecksum (Nbuf, NetPseudoHeadChecksum (Src, Dst, 6, 0)) != 0)) {\r
8a67d61d 724\r
1b31acb6 725 DEBUG ((EFI_D_INFO, "TcpInput: received a malformed packet\n"));\r
8a67d61d 726 goto DISCARD;\r
727 }\r
728\r
729 if (TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)) {\r
730 Len++;\r
731 }\r
732\r
733 if (TCP_FLG_ON (Head->Flag, TCP_FLG_FIN)) {\r
734 Len++;\r
735 }\r
736\r
737 Tcb = TcpLocateTcb (\r
738 Head->DstPort,\r
739 Dst,\r
740 Head->SrcPort,\r
741 Src,\r
742 (BOOLEAN) TCP_FLG_ON (Head->Flag, TCP_FLG_SYN)\r
743 );\r
744\r
745 if ((Tcb == NULL) || (Tcb->State == TCP_CLOSED)) {\r
49789216 746 DEBUG ((EFI_D_INFO, "TcpInput: send reset because no TCB found\n"));\r
8a67d61d 747\r
748 Tcb = NULL;\r
749 goto SEND_RESET;\r
750 }\r
751\r
752 Seg = TcpFormatNetbuf (Tcb, Nbuf);\r
753\r
754 //\r
755 // RFC1122 recommended reaction to illegal option\r
756 // (in fact, an illegal option length) is reset.\r
757 //\r
758 if (TcpParseOption (Nbuf->Tcp, &Option) == -1) {\r
e48e37fc 759 DEBUG ((EFI_D_ERROR, "TcpInput: reset the peer because"\r
49789216 760 " of malformed option for TCB %p\n", Tcb));\r
8a67d61d 761\r
762 goto SEND_RESET;\r
763 }\r
764\r
765 //\r
766 // From now on, the segment is headless\r
767 //\r
768 NetbufTrim (Nbuf, (Head->HeadLen << 2), NET_BUF_HEAD);\r
769 Nbuf->Tcp = NULL;\r
770\r
8a67d61d 771 //\r
772 // Process the segment in LISTEN state.\r
773 //\r
774 if (Tcb->State == TCP_LISTEN) {\r
775 //\r
776 // First step: Check RST\r
777 //\r
778 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
e48e37fc 779 DEBUG ((EFI_D_WARN, "TcpInput: discard a reset segment "\r
0e549d5b 780 "for TCB %p in listening\n", Tcb));\r
8a67d61d 781\r
782 goto DISCARD;\r
783 }\r
784\r
785 //\r
786 // Second step: Check ACK.\r
787 // Any ACK sent to TCP in LISTEN is reseted.\r
788 //\r
789 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
e48e37fc 790 DEBUG ((EFI_D_WARN, "TcpInput: send reset because of"\r
0e549d5b 791 " segment with ACK for TCB %p in listening\n", Tcb));\r
8a67d61d 792\r
793 goto SEND_RESET;\r
794 }\r
795\r
796 //\r
797 // Third step: Check SYN\r
798 //\r
799 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
800 //\r
801 // create a child TCB to handle the data\r
802 //\r
803 Parent = Tcb;\r
804\r
805 Tcb = TcpCloneTcb (Parent);\r
806 if (Tcb == NULL) {\r
e48e37fc 807 DEBUG ((EFI_D_ERROR, "TcpInput: discard a segment because"\r
49789216 808 " failed to clone a child for TCB %p\n", Tcb));\r
8a67d61d 809\r
810 goto DISCARD;\r
811 }\r
812\r
0e549d5b 813 DEBUG ((EFI_D_INFO, "TcpInput: create a child for TCB %p"\r
8a67d61d 814 " in listening\n", Tcb));\r
815\r
816 //\r
817 // init the TCB structure\r
818 //\r
819 Tcb->LocalEnd.Ip = Dst;\r
820 Tcb->LocalEnd.Port = Head->DstPort;\r
821 Tcb->RemoteEnd.Ip = Src;\r
822 Tcb->RemoteEnd.Port = Head->SrcPort;\r
823\r
824 TcpInitTcbLocal (Tcb);\r
825 TcpInitTcbPeer (Tcb, Seg, &Option);\r
826\r
827 TcpSetState (Tcb, TCP_SYN_RCVD);\r
828 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
829 TcpTrimInWnd (Tcb, Nbuf);\r
830\r
831 goto StepSix;\r
832 }\r
833\r
834 goto DISCARD;\r
835\r
836 } else if (Tcb->State == TCP_SYN_SENT) {\r
837 //\r
838 // First step: Check ACK bit\r
839 //\r
840 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK) && (Seg->Ack != Tcb->Iss + 1)) {\r
841\r
e48e37fc 842 DEBUG ((EFI_D_WARN, "TcpInput: send reset because of "\r
0e549d5b 843 "wrong ACK received for TCB %p in SYN_SENT\n", Tcb));\r
8a67d61d 844\r
845 goto SEND_RESET;\r
846 }\r
847\r
848 //\r
849 // Second step: Check RST bit\r
850 //\r
851 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
852\r
853 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
854\r
e48e37fc 855 DEBUG ((EFI_D_WARN, "TcpInput: connection reset by"\r
dfc1f033 856 " peer for TCB %p in SYN_SENT\n", Tcb));\r
8a67d61d 857\r
858 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
859 goto DROP_CONNECTION;\r
860 } else {\r
861\r
e48e37fc 862 DEBUG ((EFI_D_WARN, "TcpInput: discard a reset segment "\r
dfc1f033 863 "because of no ACK for TCB %p in SYN_SENT\n", Tcb));\r
8a67d61d 864\r
865 goto DISCARD;\r
866 }\r
867 }\r
868\r
869 //\r
870 // Third step: Check security and precedence. Skipped\r
871 //\r
872\r
873 //\r
49789216 874 // Fourth step: Check SYN. Pay attention to simultaneous open\r
8a67d61d 875 //\r
876 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
877\r
878 TcpInitTcbPeer (Tcb, Seg, &Option);\r
879\r
880 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
881\r
882 Tcb->SndUna = Seg->Ack;\r
883 }\r
884\r
885 TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
886\r
887 if (TCP_SEQ_GT (Tcb->SndUna, Tcb->Iss)) {\r
888\r
889 TcpSetState (Tcb, TCP_ESTABLISHED);\r
890\r
891 TcpClearTimer (Tcb, TCP_TIMER_CONNECT);\r
892 TcpDeliverData (Tcb);\r
893\r
894 if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&\r
895 TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
896\r
897 TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
898 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
899 }\r
900\r
901 TcpTrimInWnd (Tcb, Nbuf);\r
902\r
903 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
904\r
e48e37fc 905 DEBUG ((EFI_D_INFO, "TcpInput: connection established"\r
0e549d5b 906 " for TCB %p in SYN_SENT\n", Tcb));\r
8a67d61d 907\r
908 goto StepSix;\r
909 } else {\r
910 //\r
49789216 911 // Received a SYN segment without ACK, simultaneous open.\r
8a67d61d 912 //\r
913 TcpSetState (Tcb, TCP_SYN_RCVD);\r
914\r
915 ASSERT (Tcb->SndNxt == Tcb->Iss + 1);\r
916 TcpAdjustSndQue (Tcb, Tcb->SndNxt);\r
917\r
918 TcpTrimInWnd (Tcb, Nbuf);\r
919\r
49789216 920 DEBUG ((EFI_D_WARN, "TcpInput: simultaneous open "\r
0e549d5b 921 "for TCB %p in SYN_SENT\n", Tcb));\r
8a67d61d 922\r
923 goto StepSix;\r
924 }\r
925 }\r
926\r
927 goto DISCARD;\r
928 }\r
929\r
930 //\r
931 // Process segment in SYN_RCVD or TCP_CONNECTED states\r
932 //\r
933\r
ac8cca2a 934 //\r
935 // Clear probe timer since the RecvWindow is opened.\r
936 //\r
937 if (Tcb->ProbeTimerOn && (Seg->Wnd != 0)) {\r
938 TcpClearTimer (Tcb, TCP_TIMER_PROBE);\r
939 Tcb->ProbeTimerOn = FALSE;\r
940 }\r
941\r
8a67d61d 942 //\r
943 // First step: Check whether SEG.SEQ is acceptable\r
944 //\r
85511ddf 945 if (TcpSeqAcceptable (Tcb, Seg) == 0) {\r
e48e37fc 946 DEBUG ((EFI_D_WARN, "TcpInput: sequence acceptance"\r
0e549d5b 947 " test failed for segment of TCB %p\n", Tcb));\r
8a67d61d 948\r
949 if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
950 TcpSendAck (Tcb);\r
951 }\r
952\r
953 goto DISCARD;\r
954 }\r
955\r
956 if ((TCP_SEQ_LT (Seg->Seq, Tcb->RcvWl2)) &&\r
957 (Tcb->RcvWl2 == Seg->End) &&\r
958 !TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN | TCP_FLG_FIN)) {\r
959\r
960 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
961 }\r
962\r
963 //\r
964 // Second step: Check the RST\r
965 //\r
966 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_RST)) {\r
967\r
0e549d5b 968 DEBUG ((EFI_D_WARN, "TcpInput: connection reset for TCB %p\n", Tcb));\r
8a67d61d 969\r
970 if (Tcb->State == TCP_SYN_RCVD) {\r
971\r
972 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_REFUSED);\r
973\r
974 //\r
975 // This TCB comes from either a LISTEN TCB,\r
976 // or active open TCB with simultanous open.\r
977 // Do NOT signal user CONNECTION refused\r
978 // if it comes from a LISTEN TCB.\r
979 //\r
980 } else if ((Tcb->State == TCP_ESTABLISHED) ||\r
120db52c 981 (Tcb->State == TCP_FIN_WAIT_1) ||\r
982 (Tcb->State == TCP_FIN_WAIT_2) ||\r
983 (Tcb->State == TCP_CLOSE_WAIT)) {\r
8a67d61d 984\r
985 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
986\r
987 } else {\r
dfc1f033 988\r
8a67d61d 989 }\r
990\r
991 goto DROP_CONNECTION;\r
992 }\r
993\r
994 //\r
995 // Trim the data and flags.\r
996 //\r
997 TcpTrimInWnd (Tcb, Nbuf);\r
998\r
999 //\r
1000 // Third step: Check security and precedence, Ignored\r
1001 //\r
1002\r
1003 //\r
1004 // Fourth step: Check the SYN bit.\r
1005 //\r
1006 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
1007\r
e48e37fc 1008 DEBUG ((EFI_D_WARN, "TcpInput: connection reset "\r
0e549d5b 1009 "because received extra SYN for TCB %p\n", Tcb));\r
8a67d61d 1010\r
1011 SOCK_ERROR (Tcb->Sk, EFI_CONNECTION_RESET);\r
1012 goto RESET_THEN_DROP;\r
1013 }\r
1014\r
1015 //\r
1016 // Fifth step: Check the ACK\r
1017 //\r
1018 if (!TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
e48e37fc 1019 DEBUG ((EFI_D_WARN, "TcpInput: segment discard because"\r
0e549d5b 1020 " of no ACK for connected TCB %p\n", Tcb));\r
8a67d61d 1021\r
1022 goto DISCARD;\r
1023\r
1024 }\r
1025\r
1026 if (Tcb->State == TCP_SYN_RCVD) {\r
1027\r
1028 if (TCP_SEQ_LT (Tcb->SndUna, Seg->Ack) &&\r
1029 TCP_SEQ_LEQ (Seg->Ack, Tcb->SndNxt)) {\r
1030\r
1031 Tcb->SndWnd = Seg->Wnd;\r
36ee91ca 1032 Tcb->SndWndMax = MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
8a67d61d 1033 Tcb->SndWl1 = Seg->Seq;\r
1034 Tcb->SndWl2 = Seg->Ack;\r
1035 TcpSetState (Tcb, TCP_ESTABLISHED);\r
1036\r
1037 TcpClearTimer (Tcb, TCP_TIMER_CONNECT);\r
1038 TcpDeliverData (Tcb);\r
1039\r
e48e37fc 1040 DEBUG ((EFI_D_INFO, "TcpInput: connection established "\r
0e549d5b 1041 " for TCB %p in SYN_RCVD\n", Tcb));\r
8a67d61d 1042\r
1043 //\r
1044 // Continue the process as ESTABLISHED state\r
1045 //\r
1046 } else {\r
e48e37fc 1047 DEBUG ((EFI_D_WARN, "TcpInput: send reset because of"\r
0e549d5b 1048 " wrong ACK for TCB %p in SYN_RCVD\n", Tcb));\r
8a67d61d 1049\r
1050 goto SEND_RESET;\r
1051 }\r
1052 }\r
1053\r
1054 if (TCP_SEQ_LT (Seg->Ack, Tcb->SndUna)) {\r
1055\r
e48e37fc 1056 DEBUG ((EFI_D_WARN, "TcpInput: ignore the out-of-data"\r
0e549d5b 1057 " ACK for connected TCB %p\n", Tcb));\r
8a67d61d 1058\r
1059 goto StepSix;\r
1060\r
1061 } else if (TCP_SEQ_GT (Seg->Ack, Tcb->SndNxt)) {\r
1062\r
e48e37fc 1063 DEBUG ((EFI_D_WARN, "TcpInput: discard segment for "\r
0e549d5b 1064 "future ACK for connected TCB %p\n", Tcb));\r
8a67d61d 1065\r
1066 TcpSendAck (Tcb);\r
1067 goto DISCARD;\r
1068 }\r
1069\r
1070 //\r
1071 // From now on: SND.UNA <= SEG.ACK <= SND.NXT.\r
1072 //\r
1073 if (TCP_FLG_ON (Option.Flag, TCP_OPTION_RCVD_TS)) {\r
1074 //\r
1075 // update TsRecent as specified in page 16 RFC1323.\r
1076 // RcvWl2 equals to the variable "LastAckSent"\r
1077 // defined there.\r
1078 //\r
1079 if (TCP_SEQ_LEQ (Seg->Seq, Tcb->RcvWl2) &&\r
1080 TCP_SEQ_LT (Tcb->RcvWl2, Seg->End)) {\r
1081\r
1082 Tcb->TsRecent = Option.TSVal;\r
1083 Tcb->TsRecentAge = mTcpTick;\r
1084 }\r
1085\r
1086 TcpComputeRtt (Tcb, TCP_SUB_TIME (mTcpTick, Option.TSEcr));\r
1087\r
1088 } else if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
1089\r
1090 ASSERT (Tcb->CongestState == TCP_CONGEST_OPEN);\r
1091\r
1092 TcpComputeRtt (Tcb, Tcb->RttMeasure);\r
1093 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
1094 }\r
1095\r
1096 if (Seg->Ack == Tcb->SndNxt) {\r
1097\r
1098 TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
1099 } else {\r
1100\r
1101 TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);\r
1102 }\r
1103\r
1104 //\r
1105 // Count duplicate acks.\r
1106 //\r
1107 if ((Seg->Ack == Tcb->SndUna) &&\r
1108 (Tcb->SndUna != Tcb->SndNxt) &&\r
1109 (Seg->Wnd == Tcb->SndWnd) &&\r
1110 (0 == Len)) {\r
1111\r
1112 Tcb->DupAck++;\r
1113 } else {\r
1114\r
1115 Tcb->DupAck = 0;\r
1116 }\r
1117\r
1118 //\r
1119 // Congestion avoidance, fast recovery and fast retransmission.\r
1120 //\r
1121 if (((Tcb->CongestState == TCP_CONGEST_OPEN) && (Tcb->DupAck < 3)) ||\r
1122 (Tcb->CongestState == TCP_CONGEST_LOSS)) {\r
1123\r
1124 if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
1125\r
1126 if (Tcb->CWnd < Tcb->Ssthresh) {\r
1127\r
1128 Tcb->CWnd += Tcb->SndMss;\r
1129 } else {\r
1130\r
36ee91ca 1131 Tcb->CWnd += MAX (Tcb->SndMss * Tcb->SndMss / Tcb->CWnd, 1);\r
8a67d61d 1132 }\r
1133\r
36ee91ca 1134 Tcb->CWnd = MIN (Tcb->CWnd, TCP_MAX_WIN << Tcb->SndWndScale);\r
8a67d61d 1135 }\r
1136\r
1137 if (Tcb->CongestState == TCP_CONGEST_LOSS) {\r
1138 TcpFastLossRecover (Tcb, Seg);\r
1139 }\r
1140 } else {\r
1141\r
1142 TcpFastRecover (Tcb, Seg);\r
1143 }\r
1144\r
1145 if (TCP_SEQ_GT (Seg->Ack, Tcb->SndUna)) {\r
1146\r
1147 TcpAdjustSndQue (Tcb, Seg->Ack);\r
1148 Tcb->SndUna = Seg->Ack;\r
1149\r
1150 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&\r
120db52c 1151 TCP_SEQ_LT (Tcb->SndUp, Seg->Ack)) {\r
8a67d61d 1152\r
1153 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_URG);\r
1154 }\r
1155 }\r
1156\r
1157 //\r
1158 // Update window info\r
1159 //\r
1160 if (TCP_SEQ_LT (Tcb->SndWl1, Seg->Seq) ||\r
1161 ((Tcb->SndWl1 == Seg->Seq) && TCP_SEQ_LEQ (Tcb->SndWl2, Seg->Ack))) {\r
1162\r
1163 Right = Seg->Ack + Seg->Wnd;\r
1164\r
1165 if (TCP_SEQ_LT (Right, Tcb->SndWl2 + Tcb->SndWnd)) {\r
1166\r
1167 if ((Tcb->SndWl1 == Seg->Seq) &&\r
1168 (Tcb->SndWl2 == Seg->Ack) &&\r
1169 (Len == 0)) {\r
1170\r
1171 goto NO_UPDATE;\r
1172 }\r
1173\r
e48e37fc 1174 DEBUG ((EFI_D_WARN, "TcpInput: peer shrinks the"\r
dfc1f033 1175 " window for connected TCB %p\n", Tcb));\r
8a67d61d 1176\r
1177 if ((Tcb->CongestState == TCP_CONGEST_RECOVER) &&\r
1178 (TCP_SEQ_LT (Right, Tcb->Recover))) {\r
1179\r
1180 Tcb->Recover = Right;\r
1181 }\r
1182\r
1183 if ((Tcb->CongestState == TCP_CONGEST_LOSS) &&\r
1184 (TCP_SEQ_LT (Right, Tcb->LossRecover))) {\r
1185\r
1186 Tcb->LossRecover = Right;\r
1187 }\r
1188\r
1189 if (TCP_SEQ_LT (Right, Tcb->SndNxt)) {\r
1190\r
1191 Tcb->SndNxt = Right;\r
1192\r
1193 if (Right == Tcb->SndUna) {\r
1194\r
1195 TcpClearTimer (Tcb, TCP_TIMER_REXMIT);\r
1196 TcpSetProbeTimer (Tcb);\r
1197 }\r
1198 }\r
1199 }\r
1200\r
1201 Tcb->SndWnd = Seg->Wnd;\r
36ee91ca 1202 Tcb->SndWndMax = MAX (Tcb->SndWnd, Tcb->SndWndMax);\r
8a67d61d 1203 Tcb->SndWl1 = Seg->Seq;\r
1204 Tcb->SndWl2 = Seg->Ack;\r
1205 }\r
1206\r
1207NO_UPDATE:\r
1208\r
1209 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT) &&\r
1210 (Tcb->SndUna == Tcb->SndNxt)) {\r
1211\r
e48e37fc 1212 DEBUG ((EFI_D_INFO, "TcpInput: local FIN is ACKed by"\r
0e549d5b 1213 " peer for connected TCB %p\n", Tcb));\r
8a67d61d 1214\r
1215 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED);\r
1216 }\r
1217\r
1218 //\r
1219 // Transit the state if proper.\r
1220 //\r
1221 switch (Tcb->State) {\r
1222 case TCP_FIN_WAIT_1:\r
1223\r
1224 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
1225\r
1226 TcpSetState (Tcb, TCP_FIN_WAIT_2);\r
1227\r
1228 TcpClearAllTimer (Tcb);\r
1229 TcpSetTimer (Tcb, TCP_TIMER_FINWAIT2, Tcb->FinWait2Timeout);\r
1230 }\r
1231\r
1232 case TCP_FIN_WAIT_2:\r
1233\r
1234 break;\r
1235\r
1236 case TCP_CLOSE_WAIT:\r
1237 break;\r
1238\r
1239 case TCP_CLOSING:\r
1240\r
1241 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
1242\r
1243 TcpSetState (Tcb, TCP_TIME_WAIT);\r
1244\r
1245 TcpClearAllTimer (Tcb);\r
1246\r
1247 if (Tcb->TimeWaitTimeout != 0) {\r
1248\r
1249 TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
1250 } else {\r
1251\r
e48e37fc 1252 DEBUG ((EFI_D_WARN, "Connection closed immediately "\r
0e549d5b 1253 "because app disables TIME_WAIT timer for %p\n", Tcb));\r
8a67d61d 1254\r
1255 TcpClose (Tcb);\r
1256 }\r
1257 }\r
1258 break;\r
1259\r
1260 case TCP_LAST_ACK:\r
1261\r
1262 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_ACKED)) {\r
1263\r
1264 TcpSetState (Tcb, TCP_CLOSED);\r
1265 }\r
1266\r
1267 break;\r
1268\r
1269 case TCP_TIME_WAIT:\r
1270\r
1271 TcpSendAck (Tcb);\r
1272\r
1273 if (Tcb->TimeWaitTimeout != 0) {\r
1274\r
1275 TcpSetTimer (Tcb, TCP_TIMER_2MSL, Tcb->TimeWaitTimeout);\r
1276 } else {\r
1277\r
e48e37fc 1278 DEBUG ((EFI_D_WARN, "Connection closed immediately "\r
0e549d5b 1279 "because app disables TIME_WAIT timer for %p\n", Tcb));\r
8a67d61d 1280\r
1281 TcpClose (Tcb);\r
1282 }\r
1283 break;\r
c191cdd1 1284\r
1285 default:\r
1286 break;\r
8a67d61d 1287 }\r
1288\r
1289 //\r
1290 // Sixth step: Check the URG bit.update the Urg point\r
1291 // if in TCP_CAN_RECV, otherwise, leave the RcvUp intact.\r
1292 //\r
1293StepSix:\r
1294\r
1295 Tcb->Idle = 0;\r
1296 TcpSetKeepaliveTimer (Tcb);\r
1297\r
8a67d61d 1298 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_URG) &&\r
49789216
BZ
1299 !TCP_FIN_RCVD (Tcb->State)) \r
1300 {\r
8a67d61d 1301\r
e48e37fc 1302 DEBUG ((EFI_D_INFO, "TcpInput: received urgent data "\r
0e549d5b 1303 "from peer for connected TCB %p\n", Tcb));\r
8a67d61d 1304\r
1305 Urg = Seg->Seq + Seg->Urg;\r
1306\r
1307 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG) &&\r
1308 TCP_SEQ_GT (Urg, Tcb->RcvUp)) {\r
1309\r
1310 Tcb->RcvUp = Urg;\r
1311 } else {\r
1312\r
1313 Tcb->RcvUp = Urg;\r
1314 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_URG);\r
1315 }\r
1316 }\r
1317\r
1318 //\r
1319 // Seventh step: Process the segment data\r
1320 //\r
1321 if (Seg->End != Seg->Seq) {\r
1322\r
1323 if (TCP_FIN_RCVD (Tcb->State)) {\r
1324\r
e48e37fc 1325 DEBUG ((EFI_D_WARN, "TcpInput: connection reset because"\r
0e549d5b 1326 " data is lost for connected TCB %p\n", Tcb));\r
8a67d61d 1327\r
1328 goto RESET_THEN_DROP;\r
1329 }\r
1330\r
1331 if (TCP_LOCAL_CLOSED (Tcb->State) && (Nbuf->TotalSize != 0)) {\r
e48e37fc 1332 DEBUG ((EFI_D_WARN, "TcpInput: connection reset because"\r
0e549d5b 1333 " data is lost for connected TCB %p\n", Tcb));\r
8a67d61d 1334\r
1335 goto RESET_THEN_DROP;\r
1336 }\r
1337\r
1338 TcpQueueData (Tcb, Nbuf);\r
1339 if (TcpDeliverData (Tcb) == -1) {\r
1340 goto RESET_THEN_DROP;\r
1341 }\r
1342\r
e48e37fc 1343 if (!IsListEmpty (&Tcb->RcvQue)) {\r
8a67d61d 1344 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
1345 }\r
1346 }\r
1347\r
1348 //\r
1349 // Eighth step: check the FIN.\r
1350 // This step is moved to TcpDeliverData. FIN will be\r
1351 // processed in sequence there. Check the comments in\r
1352 // the beginning of the file header for information.\r
1353 //\r
1354\r
1355 //\r
1356 // Tcb is a new child of the listening Parent,\r
1357 // commit it.\r
1358 //\r
85511ddf 1359 if (Parent != NULL) {\r
8a67d61d 1360 Tcb->Parent = Parent;\r
1361 TcpInsertTcb (Tcb);\r
1362 }\r
1363\r
1364 if ((Tcb->State != TCP_CLOSED) &&\r
85511ddf 1365 (TcpToSendData (Tcb, 0) == 0) &&\r
52b2a308 1366 (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || (Nbuf->TotalSize != 0))) {\r
8a67d61d 1367\r
1368 TcpToSendAck (Tcb);\r
1369 }\r
1370\r
1371 NetbufFree (Nbuf);\r
1372 return 0;\r
1373\r
1374RESET_THEN_DROP:\r
1375 TcpSendReset (Tcb, Head, Len, Dst, Src);\r
1376\r
1377DROP_CONNECTION:\r
120db52c 1378 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));\r
8a67d61d 1379\r
1380 NetbufFree (Nbuf);\r
1381 TcpClose (Tcb);\r
1382\r
1383 return -1;\r
1384\r
1385SEND_RESET:\r
1386\r
1387 TcpSendReset (Tcb, Head, Len, Dst, Src);\r
1388\r
1389DISCARD:\r
1390\r
1391 //\r
1392 // Tcb is a child of Parent, and it doesn't survive\r
1393 //\r
e48e37fc 1394 DEBUG ((EFI_D_WARN, "Tcp4Input: Discard a packet\n"));\r
8a67d61d 1395 NetbufFree (Nbuf);\r
1396\r
85511ddf 1397 if ((Parent != NULL) && (Tcb != NULL)) {\r
8a67d61d 1398\r
120db52c 1399 ASSERT (Tcb->Sk != NULL);\r
8a67d61d 1400 TcpClose (Tcb);\r
1401 }\r
1402\r
1403 return 0;\r
1404}\r
1405\r
1406\r
1407/**\r
1408 Process the received ICMP error messages for TCP.\r
1409\r
1410 @param Nbuf Buffer that contains part of the TCP segment without IP header\r
1411 truncated from the ICMP error packet.\r
1412 @param IcmpErr The ICMP error code interpreted from ICMP error packet.\r
1413 @param Src Source address of the ICMP error message.\r
1414 @param Dst Destination address of the ICMP error message.\r
1415\r
8a67d61d 1416**/\r
1417VOID\r
1418TcpIcmpInput (\r
1419 IN NET_BUF *Nbuf,\r
b45b45b2 1420 IN UINT8 IcmpErr,\r
8a67d61d 1421 IN UINT32 Src,\r
1422 IN UINT32 Dst\r
1423 )\r
1424{\r
1425 TCP_HEAD *Head;\r
1426 TCP_CB *Tcb;\r
1427 TCP_SEQNO Seq;\r
1428 EFI_STATUS IcmpErrStatus;\r
1429 BOOLEAN IcmpErrIsHard;\r
1430 BOOLEAN IcmpErrNotify;\r
1431\r
1b31acb6
FS
1432 if (Nbuf->TotalSize < sizeof (TCP_HEAD)) {\r
1433 goto CLEAN_EXIT;\r
1434 }\r
1435\r
8a67d61d 1436 Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
a56b6e03 1437 ASSERT (Head != NULL);\r
8a67d61d 1438 Tcb = TcpLocateTcb (\r
1439 Head->DstPort,\r
1440 Dst,\r
1441 Head->SrcPort,\r
1442 Src,\r
1443 FALSE\r
1444 );\r
1445 if (Tcb == NULL || Tcb->State == TCP_CLOSED) {\r
1446\r
1447 goto CLEAN_EXIT;\r
1448 }\r
1449\r
1450 //\r
1451 // Validate the sequence number.\r
1452 //\r
1453 Seq = NTOHL (Head->Seq);\r
1454 if (!(TCP_SEQ_LEQ (Tcb->SndUna, Seq) && TCP_SEQ_LT (Seq, Tcb->SndNxt))) {\r
1455\r
1456 goto CLEAN_EXIT;\r
1457 }\r
1458\r
fb115c61 1459 IcmpErrStatus = IpIoGetIcmpErrStatus (\r
1460 IcmpErr,\r
1461 IP_VERSION_4,\r
1462 &IcmpErrIsHard,\r
1463 &IcmpErrNotify\r
1464 );\r
8a67d61d 1465\r
1466 if (IcmpErrNotify) {\r
1467\r
1468 SOCK_ERROR (Tcb->Sk, IcmpErrStatus);\r
1469 }\r
1470\r
1471 if (IcmpErrIsHard) {\r
1472\r
1473 TcpClose (Tcb);\r
1474 }\r
1475\r
1476CLEAN_EXIT:\r
1477 NetbufFree (Nbuf);\r
1478}\r