]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/TcpDxe/TcpOutput.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / TcpDxe / TcpOutput.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 TCP output process routines.\r
3\r
f75a7f56 4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
a3bcde70 5\r
ecf98fbc 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a3bcde70
HT
7\r
8**/\r
9\r
10#include "TcpMain.h"\r
11\r
12UINT8 mTcpOutFlag[] = {\r
13 0, // TCP_CLOSED\r
14 0, // TCP_LISTEN\r
15 TCP_FLG_SYN, // TCP_SYN_SENT\r
16 TCP_FLG_SYN | TCP_FLG_ACK, // TCP_SYN_RCVD\r
17 TCP_FLG_ACK, // TCP_ESTABLISHED\r
18 TCP_FLG_FIN | TCP_FLG_ACK, // TCP_FIN_WAIT_1\r
19 TCP_FLG_ACK, // TCP_FIN_WAIT_2\r
20 TCP_FLG_ACK | TCP_FLG_FIN, // TCP_CLOSING\r
21 TCP_FLG_ACK, // TCP_TIME_WAIT\r
22 TCP_FLG_ACK, // TCP_CLOSE_WAIT\r
23 TCP_FLG_FIN | TCP_FLG_ACK // TCP_LAST_ACK\r
24};\r
25\r
26/**\r
27 Compute the sequence space left in the old receive window.\r
28\r
29 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
30\r
31 @return The sequence space left in the old receive window.\r
32\r
33**/\r
34UINT32\r
35TcpRcvWinOld (\r
d1050b9d 36 IN TCP_CB *Tcb\r
a3bcde70
HT
37 )\r
38{\r
39 UINT32 OldWin;\r
40\r
41 OldWin = 0;\r
42\r
43 if (TCP_SEQ_GT (Tcb->RcvWl2 + Tcb->RcvWnd, Tcb->RcvNxt)) {\r
a3bcde70 44 OldWin = TCP_SUB_SEQ (\r
d1050b9d
MK
45 Tcb->RcvWl2 + Tcb->RcvWnd,\r
46 Tcb->RcvNxt\r
47 );\r
a3bcde70
HT
48 }\r
49\r
50 return OldWin;\r
51}\r
52\r
53/**\r
54 Compute the current receive window.\r
55\r
56 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
57\r
58 @return The size of the current receive window, in bytes.\r
59\r
60**/\r
61UINT32\r
62TcpRcvWinNow (\r
d1050b9d 63 IN TCP_CB *Tcb\r
a3bcde70
HT
64 )\r
65{\r
66 SOCKET *Sk;\r
67 UINT32 Win;\r
68 UINT32 Increase;\r
69 UINT32 OldWin;\r
70\r
71 Sk = Tcb->Sk;\r
72 ASSERT (Sk != NULL);\r
73\r
d1050b9d 74 OldWin = TcpRcvWinOld (Tcb);\r
a3bcde70 75\r
d1050b9d 76 Win = SockGetFreeSpace (Sk, SOCK_RCV_BUF);\r
a3bcde70 77\r
d1050b9d 78 Increase = 0;\r
a3bcde70
HT
79 if (Win > OldWin) {\r
80 Increase = Win - OldWin;\r
81 }\r
82\r
83 //\r
84 // Receiver's SWS: don't advertise a bigger window\r
85 // unless it can be increased by at least one Mss or\r
86 // half of the receive buffer.\r
87 //\r
88 if ((Increase > Tcb->SndMss) || (2 * Increase >= GET_RCV_BUFFSIZE (Sk))) {\r
a3bcde70
HT
89 return Win;\r
90 }\r
91\r
92 return OldWin;\r
93}\r
94\r
95/**\r
96 Compute the value to fill in the window size field of the outgoing segment.\r
97\r
98 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
99 @param[in] Syn The flag to indicate whether the outgoing segment\r
100 is a SYN segment.\r
101\r
102 @return The value of the local receive window size used to fill the outgoing segment.\r
103\r
104**/\r
105UINT16\r
106TcpComputeWnd (\r
d1050b9d
MK
107 IN OUT TCP_CB *Tcb,\r
108 IN BOOLEAN Syn\r
a3bcde70
HT
109 )\r
110{\r
111 UINT32 Wnd;\r
112\r
113 //\r
114 // RFC requires that initial window not be scaled\r
115 //\r
116 if (Syn) {\r
a3bcde70
HT
117 Wnd = GET_RCV_BUFFSIZE (Tcb->Sk);\r
118 } else {\r
d1050b9d 119 Wnd = TcpRcvWinNow (Tcb);\r
a3bcde70
HT
120\r
121 Tcb->RcvWnd = Wnd;\r
122 }\r
123\r
124 Wnd = MIN (Wnd >> Tcb->RcvWndScale, 0xffff);\r
d1050b9d 125 return NTOHS ((UINT16)Wnd);\r
a3bcde70
HT
126}\r
127\r
128/**\r
129 Get the maximum SndNxt.\r
130\r
131 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
132\r
133 @return The sequence number of the maximum SndNxt.\r
134\r
135**/\r
136TCP_SEQNO\r
137TcpGetMaxSndNxt (\r
d1050b9d 138 IN TCP_CB *Tcb\r
a3bcde70
HT
139 )\r
140{\r
d1050b9d
MK
141 LIST_ENTRY *Entry;\r
142 NET_BUF *Nbuf;\r
a3bcde70
HT
143\r
144 if (IsListEmpty (&Tcb->SndQue)) {\r
145 return Tcb->SndNxt;\r
146 }\r
147\r
148 Entry = Tcb->SndQue.BackLink;\r
149 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
150\r
151 ASSERT (TCP_SEQ_GEQ (TCPSEG_NETBUF (Nbuf)->End, Tcb->SndNxt));\r
152 return TCPSEG_NETBUF (Nbuf)->End;\r
153}\r
154\r
155/**\r
156 Compute how much data to send.\r
157\r
158 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
159 @param[in] Force If TRUE, to ignore the sender's SWS avoidance algorithm and send\r
160 out data by force.\r
161\r
162 @return The length of the data can be sent. If 0, no data can be sent.\r
163\r
164**/\r
165UINT32\r
166TcpDataToSend (\r
d1050b9d
MK
167 IN TCP_CB *Tcb,\r
168 IN INTN Force\r
a3bcde70
HT
169 )\r
170{\r
171 SOCKET *Sk;\r
172 UINT32 Win;\r
173 UINT32 Len;\r
174 UINT32 Left;\r
175 UINT32 Limit;\r
176\r
177 Sk = Tcb->Sk;\r
178 ASSERT (Sk != NULL);\r
179\r
180 //\r
181 // TCP should NOT send data beyond the send window\r
182 // and congestion window. The right edge of send\r
183 // window is defined as SND.WL2 + SND.WND. The right\r
184 // edge of congestion window is defined as SND.UNA +\r
185 // CWND.\r
186 //\r
187 Win = 0;\r
188 Limit = Tcb->SndWl2 + Tcb->SndWnd;\r
189\r
190 if (TCP_SEQ_GT (Limit, Tcb->SndUna + Tcb->CWnd)) {\r
a3bcde70
HT
191 Limit = Tcb->SndUna + Tcb->CWnd;\r
192 }\r
193\r
194 if (TCP_SEQ_GT (Limit, Tcb->SndNxt)) {\r
195 Win = TCP_SUB_SEQ (Limit, Tcb->SndNxt);\r
196 }\r
197\r
198 //\r
199 // The data to send contains two parts: the data on the\r
200 // socket send queue, and the data on the TCB's send\r
201 // buffer. The later can be non-zero if the peer shrinks\r
202 // its advertised window.\r
203 //\r
d1050b9d 204 Left = GET_SND_DATASIZE (Sk) + TCP_SUB_SEQ (TcpGetMaxSndNxt (Tcb), Tcb->SndNxt);\r
a3bcde70 205\r
d1050b9d 206 Len = MIN (Win, Left);\r
a3bcde70
HT
207\r
208 if (Len > Tcb->SndMss) {\r
209 Len = Tcb->SndMss;\r
210 }\r
211\r
d1050b9d 212 if ((Force != 0) || ((Len == 0) && (Left == 0))) {\r
a3bcde70
HT
213 return Len;\r
214 }\r
215\r
d1050b9d 216 if ((Len == 0) && (Left != 0)) {\r
a3bcde70
HT
217 goto SetPersistTimer;\r
218 }\r
219\r
220 //\r
221 // Sender's SWS avoidance: Don't send a small segment unless\r
222 // a)A full-sized segment can be sent,\r
223 // b)At least one-half of the maximum sized windows that\r
224 // the other end has ever advertised.\r
225 // c)It can send everything it has, and either it isn't\r
226 // expecting an ACK, or the Nagle algorithm is disabled.\r
227 //\r
228 if ((Len == Tcb->SndMss) || (2 * Len >= Tcb->SndWndMax)) {\r
a3bcde70
HT
229 return Len;\r
230 }\r
231\r
232 if ((Len == Left) &&\r
233 ((Tcb->SndNxt == Tcb->SndUna) || TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE))\r
d1050b9d
MK
234 )\r
235 {\r
a3bcde70
HT
236 return Len;\r
237 }\r
238\r
239 //\r
240 // RFC1122 suggests to set a timer when SWSA forbids TCP\r
241 // sending more data, and combines it with a probe timer.\r
242 //\r
243SetPersistTimer:\r
244 if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) {\r
a3bcde70 245 DEBUG (\r
c49ca4a2 246 (DEBUG_WARN,\r
d1050b9d
MK
247 "TcpDataToSend: enter persistent state for TCB %p\n",\r
248 Tcb)\r
a3bcde70
HT
249 );\r
250\r
251 if (!Tcb->ProbeTimerOn) {\r
252 TcpSetProbeTimer (Tcb);\r
253 }\r
254 }\r
255\r
256 return 0;\r
257}\r
258\r
259/**\r
260 Build the TCP header of the TCP segment and transmit the segment by IP.\r
261\r
262 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
263 @param[in] Nbuf Pointer to the buffer containing the segment to be\r
264 sent out.\r
265\r
266 @retval 0 The segment was sent out successfully.\r
267 @retval -1 An error condition occurred.\r
268\r
269**/\r
270INTN\r
271TcpTransmitSegment (\r
d1050b9d
MK
272 IN OUT TCP_CB *Tcb,\r
273 IN NET_BUF *Nbuf\r
a3bcde70
HT
274 )\r
275{\r
276 UINT16 Len;\r
277 TCP_HEAD *Head;\r
278 TCP_SEG *Seg;\r
279 BOOLEAN Syn;\r
280 UINT32 DataLen;\r
281\r
786a4d19
JW
282 ASSERT ((Nbuf != NULL) && (Nbuf->Tcp == NULL));\r
283\r
284 if (TcpVerifySegment (Nbuf) == 0) {\r
f75a7f56 285 return -1;\r
786a4d19 286 }\r
a3bcde70
HT
287\r
288 DataLen = Nbuf->TotalSize;\r
289\r
d1050b9d
MK
290 Seg = TCPSEG_NETBUF (Nbuf);\r
291 Syn = TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN);\r
a3bcde70
HT
292\r
293 if (Syn) {\r
a3bcde70
HT
294 Len = TcpSynBuildOption (Tcb, Nbuf);\r
295 } else {\r
a3bcde70
HT
296 Len = TcpBuildOption (Tcb, Nbuf);\r
297 }\r
298\r
299 ASSERT ((Len % 4 == 0) && (Len <= 40));\r
300\r
301 Len += sizeof (TCP_HEAD);\r
302\r
d1050b9d
MK
303 Head = (TCP_HEAD *)NetbufAllocSpace (\r
304 Nbuf,\r
305 sizeof (TCP_HEAD),\r
306 NET_BUF_HEAD\r
307 );\r
a3bcde70
HT
308\r
309 ASSERT (Head != NULL);\r
310\r
d1050b9d 311 Nbuf->Tcp = Head;\r
a3bcde70 312\r
d1050b9d
MK
313 Head->SrcPort = Tcb->LocalEnd.Port;\r
314 Head->DstPort = Tcb->RemoteEnd.Port;\r
315 Head->Seq = NTOHL (Seg->Seq);\r
316 Head->Ack = NTOHL (Tcb->RcvNxt);\r
317 Head->HeadLen = (UINT8)(Len >> 2);\r
318 Head->Res = 0;\r
319 Head->Wnd = TcpComputeWnd (Tcb, Syn);\r
320 Head->Checksum = 0;\r
a3bcde70
HT
321\r
322 //\r
323 // Check whether to set the PSH flag.\r
324 //\r
325 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_PSH);\r
326\r
327 if (DataLen != 0) {\r
328 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_PSH) &&\r
329 TCP_SEQ_BETWEEN (Seg->Seq, Tcb->SndPsh, Seg->End)\r
d1050b9d
MK
330 )\r
331 {\r
a3bcde70
HT
332 TCP_SET_FLG (Seg->Flag, TCP_FLG_PSH);\r
333 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);\r
a3bcde70 334 } else if ((Seg->End == Tcb->SndNxt) && (GET_SND_DATASIZE (Tcb->Sk) == 0)) {\r
a3bcde70
HT
335 TCP_SET_FLG (Seg->Flag, TCP_FLG_PSH);\r
336 }\r
337 }\r
338\r
339 //\r
340 // Check whether to set the URG flag and the urgent pointer.\r
341 //\r
342 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG);\r
343\r
344 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) && TCP_SEQ_LEQ (Seg->Seq, Tcb->SndUp)) {\r
a3bcde70
HT
345 TCP_SET_FLG (Seg->Flag, TCP_FLG_URG);\r
346\r
347 if (TCP_SEQ_LT (Tcb->SndUp, Seg->End)) {\r
d1050b9d 348 Seg->Urg = (UINT16)TCP_SUB_SEQ (Tcb->SndUp, Seg->Seq);\r
a3bcde70 349 } else {\r
d1050b9d
MK
350 Seg->Urg = (UINT16)MIN (\r
351 TCP_SUB_SEQ (\r
352 Tcb->SndUp,\r
353 Seg->Seq\r
354 ),\r
355 0xffff\r
356 );\r
a3bcde70
HT
357 }\r
358 }\r
359\r
d1050b9d
MK
360 Head->Flag = Seg->Flag;\r
361 Head->Urg = NTOHS (Seg->Urg);\r
362 Head->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);\r
a3bcde70
HT
363\r
364 //\r
365 // Update the TCP session's control information.\r
366 //\r
367 Tcb->RcvWl2 = Tcb->RcvNxt;\r
368 if (Syn) {\r
369 Tcb->RcvWnd = NTOHS (Head->Wnd);\r
370 }\r
371\r
372 //\r
373 // Clear the delayedack flag.\r
374 //\r
375 Tcb->DelayedAck = 0;\r
376\r
377 return TcpSendIpPacket (Tcb, Nbuf, &Tcb->LocalEnd.Ip, &Tcb->RemoteEnd.Ip, Tcb->Sk->IpVersion);\r
378}\r
379\r
380/**\r
381 Get a segment from the Tcb's SndQue.\r
382\r
383 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
384 @param[in] Seq The sequence number of the segment.\r
385 @param[in] Len The maximum length of the segment.\r
386\r
387 @return Pointer to the segment. If NULL, some error occurred.\r
388\r
389**/\r
390NET_BUF *\r
391TcpGetSegmentSndQue (\r
d1050b9d
MK
392 IN TCP_CB *Tcb,\r
393 IN TCP_SEQNO Seq,\r
394 IN UINT32 Len\r
a3bcde70
HT
395 )\r
396{\r
d1050b9d
MK
397 LIST_ENTRY *Head;\r
398 LIST_ENTRY *Cur;\r
399 NET_BUF *Node;\r
400 TCP_SEG *Seg;\r
401 NET_BUF *Nbuf;\r
402 TCP_SEQNO End;\r
403 UINT8 *Data;\r
404 UINT8 Flag;\r
405 INT32 Offset;\r
406 INT32 CopyLen;\r
a3bcde70
HT
407\r
408 ASSERT ((Tcb != NULL) && TCP_SEQ_LEQ (Seq, Tcb->SndNxt) && (Len > 0));\r
409\r
410 //\r
411 // Find the segment that contains the Seq.\r
412 //\r
d1050b9d 413 Head = &Tcb->SndQue;\r
a3bcde70 414\r
d1050b9d
MK
415 Node = NULL;\r
416 Seg = NULL;\r
a3bcde70
HT
417\r
418 NET_LIST_FOR_EACH (Cur, Head) {\r
d1050b9d
MK
419 Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
420 Seg = TCPSEG_NETBUF (Node);\r
a3bcde70
HT
421\r
422 if (TCP_SEQ_LT (Seq, Seg->End) && TCP_SEQ_LEQ (Seg->Seq, Seq)) {\r
a3bcde70
HT
423 break;\r
424 }\r
425 }\r
426\r
427 if ((Cur == Head) || (Seg == NULL) || (Node == NULL)) {\r
428 return NULL;\r
429 }\r
430\r
431 //\r
432 // Return the buffer if it can be returned without\r
433 // adjustment:\r
434 //\r
435 if ((Seg->Seq == Seq) &&\r
436 TCP_SEQ_LEQ (Seg->End, Seg->Seq + Len) &&\r
437 !NET_BUF_SHARED (Node)\r
d1050b9d
MK
438 )\r
439 {\r
a3bcde70
HT
440 NET_GET_REF (Node);\r
441 return Node;\r
442 }\r
443\r
444 //\r
445 // Create a new buffer and copy data there.\r
446 //\r
447 Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD);\r
448\r
449 if (Nbuf == NULL) {\r
450 return NULL;\r
451 }\r
452\r
453 NetbufReserve (Nbuf, TCP_MAX_HEAD);\r
454\r
d1050b9d
MK
455 Flag = Seg->Flag;\r
456 End = Seg->End;\r
a3bcde70
HT
457\r
458 if (TCP_SEQ_LT (Seq + Len, Seg->End)) {\r
459 End = Seq + Len;\r
460 }\r
461\r
462 CopyLen = TCP_SUB_SEQ (End, Seq);\r
463 Offset = TCP_SUB_SEQ (Seq, Seg->Seq);\r
464\r
465 //\r
466 // If SYN is set and out of the range, clear the flag.\r
81c6f176 467 // Because the sequence of the first byte is SEG.SEQ+1,\r
a3bcde70
HT
468 // adjust Offset by -1. If SYN is in the range, copy\r
469 // one byte less.\r
470 //\r
471 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
a3bcde70 472 if (TCP_SEQ_LT (Seg->Seq, Seq)) {\r
a3bcde70
HT
473 TCP_CLEAR_FLG (Flag, TCP_FLG_SYN);\r
474 Offset--;\r
475 } else {\r
a3bcde70
HT
476 CopyLen--;\r
477 }\r
478 }\r
479\r
480 //\r
481 // If FIN is set and in the range, copy one byte less,\r
482 // and if it is out of the range, clear the flag.\r
483 //\r
484 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
a3bcde70 485 if (Seg->End == End) {\r
a3bcde70
HT
486 CopyLen--;\r
487 } else {\r
a3bcde70
HT
488 TCP_CLEAR_FLG (Flag, TCP_FLG_FIN);\r
489 }\r
490 }\r
491\r
492 ASSERT (CopyLen >= 0);\r
493\r
494 //\r
495 // Copy data to the segment\r
496 //\r
497 if (CopyLen != 0) {\r
498 Data = NetbufAllocSpace (Nbuf, CopyLen, NET_BUF_TAIL);\r
499 ASSERT (Data != NULL);\r
500\r
d1050b9d 501 if ((INT32)NetbufCopy (Node, Offset, CopyLen, Data) != CopyLen) {\r
a3bcde70
HT
502 goto OnError;\r
503 }\r
504 }\r
505\r
506 CopyMem (TCPSEG_NETBUF (Nbuf), Seg, sizeof (TCP_SEG));\r
507\r
d1050b9d
MK
508 TCPSEG_NETBUF (Nbuf)->Seq = Seq;\r
509 TCPSEG_NETBUF (Nbuf)->End = End;\r
510 TCPSEG_NETBUF (Nbuf)->Flag = Flag;\r
a3bcde70
HT
511\r
512 return Nbuf;\r
513\r
514OnError:\r
515 NetbufFree (Nbuf);\r
516 return NULL;\r
517}\r
518\r
519/**\r
520 Get a segment from the Tcb's socket buffer.\r
521\r
522 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
523 @param[in] Seq The sequence number of the segment.\r
524 @param[in] Len The maximum length of the segment.\r
525\r
526 @return Pointer to the segment. If NULL, some error occurred.\r
527\r
528**/\r
529NET_BUF *\r
530TcpGetSegmentSock (\r
d1050b9d
MK
531 IN TCP_CB *Tcb,\r
532 IN TCP_SEQNO Seq,\r
533 IN UINT32 Len\r
a3bcde70
HT
534 )\r
535{\r
d1050b9d
MK
536 NET_BUF *Nbuf;\r
537 UINT8 *Data;\r
538 UINT32 DataGet;\r
a3bcde70
HT
539\r
540 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));\r
541\r
542 Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD);\r
543\r
544 if (Nbuf == NULL) {\r
545 DEBUG (\r
c49ca4a2 546 (DEBUG_ERROR,\r
d1050b9d
MK
547 "TcpGetSegmentSock: failed to allocate a netbuf for TCB %p\n",\r
548 Tcb)\r
a3bcde70
HT
549 );\r
550\r
551 return NULL;\r
552 }\r
553\r
554 NetbufReserve (Nbuf, TCP_MAX_HEAD);\r
555\r
556 DataGet = 0;\r
557\r
558 if (Len != 0) {\r
559 //\r
560 // copy data to the segment.\r
561 //\r
562 Data = NetbufAllocSpace (Nbuf, Len, NET_BUF_TAIL);\r
563 ASSERT (Data != NULL);\r
564\r
565 DataGet = SockGetDataToSend (Tcb->Sk, 0, Len, Data);\r
566 }\r
567\r
568 NET_GET_REF (Nbuf);\r
569\r
570 TCPSEG_NETBUF (Nbuf)->Seq = Seq;\r
571 TCPSEG_NETBUF (Nbuf)->End = Seq + Len;\r
572\r
573 InsertTailList (&(Tcb->SndQue), &(Nbuf->List));\r
574\r
575 if (DataGet != 0) {\r
a3bcde70
HT
576 SockDataSent (Tcb->Sk, DataGet);\r
577 }\r
578\r
579 return Nbuf;\r
580}\r
581\r
582/**\r
583 Get a segment starting from sequence Seq of a maximum\r
584 length of Len.\r
585\r
586 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
587 @param[in] Seq The sequence number of the segment.\r
588 @param[in] Len The maximum length of the segment.\r
589\r
590 @return Pointer to the segment. If NULL, some error occurred.\r
591\r
592**/\r
593NET_BUF *\r
594TcpGetSegment (\r
d1050b9d
MK
595 IN TCP_CB *Tcb,\r
596 IN TCP_SEQNO Seq,\r
597 IN UINT32 Len\r
a3bcde70
HT
598 )\r
599{\r
d1050b9d 600 NET_BUF *Nbuf;\r
a3bcde70
HT
601\r
602 ASSERT (Tcb != NULL);\r
603\r
604 //\r
605 // Compare the SndNxt with the max sequence number sent.\r
606 //\r
607 if ((Len != 0) && TCP_SEQ_LT (Seq, TcpGetMaxSndNxt (Tcb))) {\r
a3bcde70
HT
608 Nbuf = TcpGetSegmentSndQue (Tcb, Seq, Len);\r
609 } else {\r
a3bcde70
HT
610 Nbuf = TcpGetSegmentSock (Tcb, Seq, Len);\r
611 }\r
612\r
786a4d19
JW
613 if (TcpVerifySegment (Nbuf) == 0) {\r
614 NetbufFree (Nbuf);\r
615 return NULL;\r
616 }\r
f75a7f56 617\r
a3bcde70
HT
618 return Nbuf;\r
619}\r
620\r
621/**\r
622 Retransmit the segment from sequence Seq.\r
623\r
624 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
625 @param[in] Seq The sequence number of the segment to be retransmitted.\r
626\r
627 @retval 0 Retransmission succeeded.\r
628 @retval -1 Error condition occurred.\r
629\r
630**/\r
631INTN\r
632TcpRetransmit (\r
d1050b9d
MK
633 IN TCP_CB *Tcb,\r
634 IN TCP_SEQNO Seq\r
a3bcde70
HT
635 )\r
636{\r
d1050b9d
MK
637 NET_BUF *Nbuf;\r
638 UINT32 Len;\r
a3bcde70
HT
639\r
640 //\r
81c6f176 641 // Compute the maximum length of retransmission. It is\r
a3bcde70
HT
642 // limited by three factors:\r
643 // 1. Less than SndMss\r
644 // 2. Must in the current send window\r
645 // 3. Will not change the boundaries of queued segments.\r
646 //\r
3696ceae
FS
647\r
648 //\r
649 // Handle the Window Retraction if TCP window scale is enabled according to RFC7323:\r
650 // On first retransmission, or if the sequence number is out of\r
651 // window by less than 2^Rcv.Wind.Shift, then do normal\r
652 // retransmission(s) without regard to the receiver window as long\r
653 // as the original segment was in window when it was sent.\r
654 //\r
655 if ((Tcb->SndWndScale != 0) &&\r
d1050b9d
MK
656 (TCP_SEQ_GT (Seq, Tcb->RetxmitSeqMax) || TCP_SEQ_BETWEEN (Tcb->SndWl2 + Tcb->SndWnd, Seq, Tcb->SndWl2 + Tcb->SndWnd + (1 << Tcb->SndWndScale))))\r
657 {\r
3696ceae
FS
658 Len = TCP_SUB_SEQ (Tcb->SndNxt, Seq);\r
659 DEBUG (\r
c49ca4a2 660 (DEBUG_WARN,\r
d1050b9d
MK
661 "TcpRetransmit: retransmission without regard to the receiver window for TCB %p\n",\r
662 Tcb)\r
3696ceae 663 );\r
3696ceae
FS
664 } else if (TCP_SEQ_GEQ (Tcb->SndWl2 + Tcb->SndWnd, Seq)) {\r
665 Len = TCP_SUB_SEQ (Tcb->SndWl2 + Tcb->SndWnd, Seq);\r
3696ceae 666 } else {\r
a3bcde70 667 DEBUG (\r
c49ca4a2 668 (DEBUG_WARN,\r
d1050b9d
MK
669 "TcpRetransmit: retransmission cancelled because send window too small for TCB %p\n",\r
670 Tcb)\r
a3bcde70
HT
671 );\r
672\r
673 return 0;\r
674 }\r
675\r
3696ceae 676 Len = MIN (Len, Tcb->SndMss);\r
a3bcde70 677\r
3696ceae 678 Nbuf = TcpGetSegmentSndQue (Tcb, Seq, Len);\r
a3bcde70
HT
679 if (Nbuf == NULL) {\r
680 return -1;\r
681 }\r
682\r
786a4d19
JW
683 if (TcpVerifySegment (Nbuf) == 0) {\r
684 goto OnError;\r
685 }\r
a3bcde70
HT
686\r
687 if (TcpTransmitSegment (Tcb, Nbuf) != 0) {\r
688 goto OnError;\r
689 }\r
690\r
3696ceae
FS
691 if (TCP_SEQ_GT (Seq, Tcb->RetxmitSeqMax)) {\r
692 Tcb->RetxmitSeqMax = Seq;\r
693 }\r
694\r
a3bcde70
HT
695 //\r
696 // The retransmitted buffer may be on the SndQue,\r
697 // trim TCP head because all the buffers on SndQue\r
698 // are headless.\r
699 //\r
700 ASSERT (Nbuf->Tcp != NULL);\r
701 NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);\r
702 Nbuf->Tcp = NULL;\r
703\r
704 NetbufFree (Nbuf);\r
705 return 0;\r
706\r
707OnError:\r
708 if (Nbuf != NULL) {\r
709 NetbufFree (Nbuf);\r
710 }\r
711\r
712 return -1;\r
713}\r
714\r
715/**\r
716 Verify that all the segments in SndQue are in good shape.\r
717\r
718 @param[in] Head Pointer to the head node of the SndQue.\r
719\r
720 @retval 0 At least one segment is broken.\r
721 @retval 1 All segments in the specific queue are in good shape.\r
722\r
723**/\r
724INTN\r
725TcpCheckSndQue (\r
d1050b9d 726 IN LIST_ENTRY *Head\r
a3bcde70
HT
727 )\r
728{\r
d1050b9d
MK
729 LIST_ENTRY *Entry;\r
730 NET_BUF *Nbuf;\r
731 TCP_SEQNO Seq;\r
a3bcde70
HT
732\r
733 if (IsListEmpty (Head)) {\r
734 return 1;\r
735 }\r
d1050b9d 736\r
a3bcde70
HT
737 //\r
738 // Initialize the Seq.\r
739 //\r
740 Entry = Head->ForwardLink;\r
741 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
742 Seq = TCPSEG_NETBUF (Nbuf)->Seq;\r
743\r
744 NET_LIST_FOR_EACH (Entry, Head) {\r
745 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
746\r
747 if (TcpVerifySegment (Nbuf) == 0) {\r
748 return 0;\r
749 }\r
750\r
751 //\r
752 // All the node in the SndQue should has:\r
753 // SEG.SEQ = LAST_SEG.END\r
754 //\r
755 if (Seq != TCPSEG_NETBUF (Nbuf)->Seq) {\r
756 return 0;\r
757 }\r
758\r
759 Seq = TCPSEG_NETBUF (Nbuf)->End;\r
760 }\r
761\r
762 return 1;\r
763}\r
764\r
765/**\r
766 Check whether to send data/SYN/FIN and piggyback an ACK.\r
767\r
768 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
769 @param[in] Force If TRUE, ignore the sender's SWS avoidance algorithm\r
770 and send out data by force.\r
771\r
772 @return The number of bytes sent.\r
773\r
774**/\r
775INTN\r
776TcpToSendData (\r
d1050b9d
MK
777 IN OUT TCP_CB *Tcb,\r
778 IN INTN Force\r
a3bcde70
HT
779 )\r
780{\r
d1050b9d
MK
781 UINT32 Len;\r
782 INTN Sent;\r
783 UINT8 Flag;\r
784 NET_BUF *Nbuf;\r
785 TCP_SEG *Seg;\r
786 TCP_SEQNO Seq;\r
787 TCP_SEQNO End;\r
a3bcde70
HT
788\r
789 ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL) && (Tcb->State != TCP_LISTEN));\r
790\r
791 Sent = 0;\r
792\r
793 if ((Tcb->State == TCP_CLOSED) || TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT)) {\r
a3bcde70
HT
794 return 0;\r
795 }\r
796\r
797 do {\r
798 //\r
799 // Compute how much data can be sent\r
800 //\r
d1050b9d
MK
801 Len = TcpDataToSend (Tcb, Force);\r
802 Seq = Tcb->SndNxt;\r
a3bcde70 803\r
e72b4097 804 ASSERT ((Tcb->State) < (ARRAY_SIZE (mTcpOutFlag)));\r
d1050b9d 805 Flag = mTcpOutFlag[Tcb->State];\r
a3bcde70
HT
806\r
807 if ((Flag & TCP_FLG_SYN) != 0) {\r
a3bcde70
HT
808 Seq = Tcb->Iss;\r
809 Len = 0;\r
810 }\r
811\r
812 //\r
813 // Only send a segment without data if SYN or\r
814 // FIN is set.\r
815 //\r
816 if ((Len == 0) && ((Flag & (TCP_FLG_SYN | TCP_FLG_FIN)) == 0)) {\r
817 return Sent;\r
818 }\r
819\r
820 Nbuf = TcpGetSegment (Tcb, Seq, Len);\r
821\r
822 if (Nbuf == NULL) {\r
823 DEBUG (\r
c49ca4a2 824 (DEBUG_ERROR,\r
d1050b9d
MK
825 "TcpToSendData: failed to get a segment for TCB %p\n",\r
826 Tcb)\r
a3bcde70
HT
827 );\r
828\r
829 goto OnError;\r
830 }\r
831\r
832 Seg = TCPSEG_NETBUF (Nbuf);\r
833\r
834 //\r
835 // Set the TcpSeg in Nbuf.\r
836 //\r
837 Len = Nbuf->TotalSize;\r
838 End = Seq + Len;\r
839 if (TCP_FLG_ON (Flag, TCP_FLG_SYN)) {\r
840 End++;\r
841 }\r
842\r
843 if ((Flag & TCP_FLG_FIN) != 0) {\r
844 //\r
845 // Send FIN if all data is sent, and FIN is\r
846 // in the window\r
847 //\r
848 if ((TcpGetMaxSndNxt (Tcb) == Tcb->SndNxt) &&\r
849 (GET_SND_DATASIZE (Tcb->Sk) == 0) &&\r
850 TCP_SEQ_LT (End + 1, Tcb->SndWnd + Tcb->SndWl2)\r
d1050b9d
MK
851 )\r
852 {\r
a3bcde70 853 DEBUG (\r
c49ca4a2 854 (DEBUG_NET,\r
d1050b9d
MK
855 "TcpToSendData: send FIN to peer for TCB %p in state %s\n",\r
856 Tcb,\r
857 mTcpStateName[Tcb->State])\r
a3bcde70
HT
858 );\r
859\r
860 End++;\r
861 } else {\r
862 TCP_CLEAR_FLG (Flag, TCP_FLG_FIN);\r
863 }\r
864 }\r
865\r
866 Seg->Seq = Seq;\r
867 Seg->End = End;\r
868 Seg->Flag = Flag;\r
869\r
d1050b9d 870 if ((TcpVerifySegment (Nbuf) == 0) || (TcpCheckSndQue (&Tcb->SndQue) == 0)) {\r
786a4d19 871 DEBUG (\r
c49ca4a2 872 (DEBUG_ERROR,\r
d1050b9d
MK
873 "TcpToSendData: discard a broken segment for TCB %p\n",\r
874 Tcb)\r
786a4d19
JW
875 );\r
876 goto OnError;\r
877 }\r
a3bcde70
HT
878\r
879 //\r
880 // Don't send an empty segment here.\r
881 //\r
882 if (Seg->End == Seg->Seq) {\r
883 DEBUG (\r
c49ca4a2 884 (DEBUG_WARN,\r
d1050b9d
MK
885 "TcpToSendData: created a empty segment for TCB %p, free it now\n",\r
886 Tcb)\r
a3bcde70
HT
887 );\r
888\r
786a4d19 889 goto OnError;\r
a3bcde70
HT
890 }\r
891\r
892 if (TcpTransmitSegment (Tcb, Nbuf) != 0) {\r
893 NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);\r
894 Nbuf->Tcp = NULL;\r
895\r
d1050b9d 896 if ((Flag & TCP_FLG_FIN) != 0) {\r
a3bcde70
HT
897 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);\r
898 }\r
899\r
900 goto OnError;\r
901 }\r
902\r
903 Sent += TCP_SUB_SEQ (End, Seq);\r
904\r
905 //\r
906 // All the buffers in the SndQue are headless.\r
907 //\r
908 ASSERT (Nbuf->Tcp != NULL);\r
909\r
910 NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);\r
911 Nbuf->Tcp = NULL;\r
912\r
913 NetbufFree (Nbuf);\r
914\r
915 //\r
916 // Update the status in TCB.\r
917 //\r
918 Tcb->DelayedAck = 0;\r
919\r
920 if ((Flag & TCP_FLG_FIN) != 0) {\r
921 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);\r
922 }\r
923\r
924 if (TCP_SEQ_GT (End, Tcb->SndNxt)) {\r
925 Tcb->SndNxt = End;\r
926 }\r
927\r
928 if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) {\r
929 TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);\r
930 }\r
931\r
932 //\r
933 // Enable RTT measurement only if not in retransmit.\r
934 // Karn's algorithm requires not to update RTT when in loss.\r
935 //\r
936 if ((Tcb->CongestState == TCP_CONGEST_OPEN) && !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {\r
a3bcde70 937 DEBUG (\r
c49ca4a2 938 (DEBUG_NET,\r
d1050b9d
MK
939 "TcpToSendData: set RTT measure sequence %d for TCB %p\n",\r
940 Seq,\r
941 Tcb)\r
a3bcde70
HT
942 );\r
943\r
944 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);\r
945 Tcb->RttSeq = Seq;\r
946 Tcb->RttMeasure = 0;\r
947 }\r
a3bcde70
HT
948 } while (Len == Tcb->SndMss);\r
949\r
950 return Sent;\r
951\r
952OnError:\r
953 if (Nbuf != NULL) {\r
954 NetbufFree (Nbuf);\r
955 }\r
956\r
957 return Sent;\r
958}\r
959\r
960/**\r
961 Send an ACK immediately.\r
962\r
963 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
964\r
965**/\r
966VOID\r
967TcpSendAck (\r
d1050b9d 968 IN OUT TCP_CB *Tcb\r
a3bcde70
HT
969 )\r
970{\r
d1050b9d
MK
971 NET_BUF *Nbuf;\r
972 TCP_SEG *Seg;\r
a3bcde70
HT
973\r
974 Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
975\r
976 if (Nbuf == NULL) {\r
977 return;\r
978 }\r
979\r
980 NetbufReserve (Nbuf, TCP_MAX_HEAD);\r
981\r
982 Seg = TCPSEG_NETBUF (Nbuf);\r
983 Seg->Seq = Tcb->SndNxt;\r
984 Seg->End = Tcb->SndNxt;\r
985 Seg->Flag = TCP_FLG_ACK;\r
986\r
987 if (TcpTransmitSegment (Tcb, Nbuf) == 0) {\r
988 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);\r
989 Tcb->DelayedAck = 0;\r
990 }\r
991\r
992 NetbufFree (Nbuf);\r
993}\r
994\r
995/**\r
996 Send a zero probe segment. It can be used by keepalive and zero window probe.\r
997\r
998 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
999\r
1000 @retval 0 The zero probe segment was sent out successfully.\r
1001 @retval other An error condition occurred.\r
1002\r
1003**/\r
1004INTN\r
1005TcpSendZeroProbe (\r
d1050b9d 1006 IN OUT TCP_CB *Tcb\r
a3bcde70
HT
1007 )\r
1008{\r
d1050b9d
MK
1009 NET_BUF *Nbuf;\r
1010 TCP_SEG *Seg;\r
a3bcde70
HT
1011 INTN Result;\r
1012\r
1013 Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
1014\r
1015 if (Nbuf == NULL) {\r
1016 return -1;\r
1017 }\r
1018\r
1019 NetbufReserve (Nbuf, TCP_MAX_HEAD);\r
1020\r
1021 //\r
1022 // SndNxt-1 is out of window. The peer should respond\r
1023 // with an ACK.\r
1024 //\r
1025 Seg = TCPSEG_NETBUF (Nbuf);\r
1026 Seg->Seq = Tcb->SndNxt - 1;\r
1027 Seg->End = Tcb->SndNxt - 1;\r
1028 Seg->Flag = TCP_FLG_ACK;\r
1029\r
d1050b9d 1030 Result = TcpTransmitSegment (Tcb, Nbuf);\r
a3bcde70
HT
1031 NetbufFree (Nbuf);\r
1032\r
1033 return Result;\r
1034}\r
1035\r
1036/**\r
1037 Check whether to send an ACK or delayed ACK.\r
1038\r
1039 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
1040\r
1041**/\r
1042VOID\r
1043TcpToSendAck (\r
d1050b9d 1044 IN OUT TCP_CB *Tcb\r
a3bcde70
HT
1045 )\r
1046{\r
d1050b9d 1047 UINT32 TcpNow;\r
a3bcde70
HT
1048\r
1049 //\r
1050 // Generally, TCP should send a delayed ACK unless:\r
1051 // 1. ACK at least every other FULL sized segment received.\r
1052 // 2. Packets received out of order.\r
1053 // 3. Receiving window is open.\r
1054 //\r
1055 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) || (Tcb->DelayedAck >= 1)) {\r
1056 TcpSendAck (Tcb);\r
1057 return;\r
1058 }\r
1059\r
1060 TcpNow = TcpRcvWinNow (Tcb);\r
1061\r
1062 if (TcpNow > TcpRcvWinOld (Tcb)) {\r
1063 TcpSendAck (Tcb);\r
1064 return;\r
1065 }\r
1066\r
1067 DEBUG (\r
c49ca4a2 1068 (DEBUG_NET,\r
d1050b9d
MK
1069 "TcpToSendAck: scheduled a delayed ACK for TCB %p\n",\r
1070 Tcb)\r
a3bcde70
HT
1071 );\r
1072\r
1073 //\r
1074 // Schedule a delayed ACK.\r
1075 //\r
1076 Tcb->DelayedAck++;\r
1077}\r
1078\r
1079/**\r
1080 Send a RESET segment in response to the segment received.\r
1081\r
1082 @param[in] Tcb Pointer to the TCP_CB of this TCP instance. May be NULL.\r
1083 @param[in] Head TCP header of the segment that triggers the reset.\r
1084 @param[in] Len Length of the segment that triggers the reset.\r
1085 @param[in] Local Local IP address.\r
1086 @param[in] Remote Remote peer's IP address.\r
1087 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack,\r
1088 IP_VERSION_6 indicates TCP is running on IP6 stack.\r
1089\r
1090 @retval 0 A reset was sent or there is no need to send it.\r
1091 @retval -1 No reset is sent.\r
1092\r
1093**/\r
1094INTN\r
1095TcpSendReset (\r
1096 IN TCP_CB *Tcb,\r
1097 IN TCP_HEAD *Head,\r
1098 IN INT32 Len,\r
1099 IN EFI_IP_ADDRESS *Local,\r
1100 IN EFI_IP_ADDRESS *Remote,\r
1101 IN UINT8 Version\r
1102 )\r
1103{\r
1104 NET_BUF *Nbuf;\r
1105 TCP_HEAD *Nhead;\r
1106 UINT16 HeadSum;\r
1107\r
1108 //\r
1109 // Don't respond to a Reset with reset.\r
1110 //\r
1111 if ((Head->Flag & TCP_FLG_RST) != 0) {\r
1112 return 0;\r
1113 }\r
1114\r
1115 Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
1116\r
1117 if (Nbuf == NULL) {\r
1118 return -1;\r
1119 }\r
1120\r
d1050b9d 1121 Nhead = (TCP_HEAD *)NetbufAllocSpace (\r
a3bcde70
HT
1122 Nbuf,\r
1123 sizeof (TCP_HEAD),\r
1124 NET_BUF_TAIL\r
1125 );\r
1126\r
1127 ASSERT (Nhead != NULL);\r
1128\r
1129 Nbuf->Tcp = Nhead;\r
1130 Nhead->Flag = TCP_FLG_RST;\r
1131\r
1132 //\r
1133 // Derive Seq/ACK from the segment if no TCB\r
1134 // is associated with it, otherwise derive from the Tcb.\r
1135 //\r
1136 if (Tcb == NULL) {\r
a3bcde70 1137 if (TCP_FLG_ON (Head->Flag, TCP_FLG_ACK)) {\r
d1050b9d
MK
1138 Nhead->Seq = Head->Ack;\r
1139 Nhead->Ack = 0;\r
a3bcde70
HT
1140 } else {\r
1141 Nhead->Seq = 0;\r
1142 TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);\r
1143 Nhead->Ack = HTONL (NTOHL (Head->Seq) + Len);\r
1144 }\r
1145 } else {\r
d1050b9d
MK
1146 Nhead->Seq = HTONL (Tcb->SndNxt);\r
1147 Nhead->Ack = HTONL (Tcb->RcvNxt);\r
a3bcde70
HT
1148 TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);\r
1149 }\r
1150\r
1151 Nhead->SrcPort = Head->DstPort;\r
1152 Nhead->DstPort = Head->SrcPort;\r
d1050b9d 1153 Nhead->HeadLen = (UINT8)(sizeof (TCP_HEAD) >> 2);\r
a3bcde70
HT
1154 Nhead->Res = 0;\r
1155 Nhead->Wnd = HTONS (0xFFFF);\r
1156 Nhead->Checksum = 0;\r
1157 Nhead->Urg = 0;\r
1158\r
1159 if (Version == IP_VERSION_4) {\r
1160 HeadSum = NetPseudoHeadChecksum (Local->Addr[0], Remote->Addr[0], 6, 0);\r
1161 } else {\r
1162 HeadSum = NetIp6PseudoHeadChecksum (&Local->v6, &Remote->v6, 6, 0);\r
1163 }\r
1164\r
1165 Nhead->Checksum = TcpChecksum (Nbuf, HeadSum);\r
1166\r
1167 TcpSendIpPacket (Tcb, Nbuf, Local, Remote, Version);\r
1168\r
1169 NetbufFree (Nbuf);\r
1170\r
1171 return 0;\r
1172}\r
1173\r
1174/**\r
1175 Verify that the segment is in good shape.\r
1176\r
1177 @param[in] Nbuf The buffer that contains the segment to be checked.\r
1178\r
1179 @retval 0 The segment is broken.\r
1180 @retval 1 The segment is in good shape.\r
1181\r
1182**/\r
1183INTN\r
1184TcpVerifySegment (\r
d1050b9d 1185 IN NET_BUF *Nbuf\r
a3bcde70
HT
1186 )\r
1187{\r
1188 TCP_HEAD *Head;\r
1189 TCP_SEG *Seg;\r
1190 UINT32 Len;\r
1191\r
1192 if (Nbuf == NULL) {\r
1193 return 1;\r
1194 }\r
1195\r
1196 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);\r
1197\r
d1050b9d
MK
1198 Seg = TCPSEG_NETBUF (Nbuf);\r
1199 Len = Nbuf->TotalSize;\r
1200 Head = Nbuf->Tcp;\r
a3bcde70
HT
1201\r
1202 if (Head != NULL) {\r
1203 if (Head->Flag != Seg->Flag) {\r
1204 return 0;\r
1205 }\r
1206\r
1207 Len -= (Head->HeadLen << 2);\r
1208 }\r
1209\r
1210 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
1211 Len++;\r
1212 }\r
1213\r
1214 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
1215 Len++;\r
1216 }\r
1217\r
1218 if (Seg->Seq + Len != Seg->End) {\r
1219 return 0;\r
1220 }\r
1221\r
1222 return 1;\r
1223}\r