]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/TcpDxe/TcpMisc.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / TcpDxe / TcpMisc.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 Misc support routines for TCP driver.\r
3\r
8f586b85 4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
3696ceae 5 Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>\r
a3bcde70 6\r
ecf98fbc 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a3bcde70
HT
8\r
9**/\r
10\r
11#include "TcpMain.h"\r
12\r
d1050b9d 13LIST_ENTRY mTcpRunQue = {\r
a3bcde70
HT
14 &mTcpRunQue,\r
15 &mTcpRunQue\r
16};\r
17\r
d1050b9d 18LIST_ENTRY mTcpListenQue = {\r
a3bcde70
HT
19 &mTcpListenQue,\r
20 &mTcpListenQue\r
21};\r
22\r
d1050b9d 23TCP_SEQNO mTcpGlobalIss = TCP_BASE_ISS;\r
a3bcde70 24\r
d1050b9d 25CHAR16 *mTcpStateName[] = {\r
a3bcde70
HT
26 L"TCP_CLOSED",\r
27 L"TCP_LISTEN",\r
28 L"TCP_SYN_SENT",\r
29 L"TCP_SYN_RCVD",\r
30 L"TCP_ESTABLISHED",\r
31 L"TCP_FIN_WAIT_1",\r
32 L"TCP_FIN_WAIT_2",\r
33 L"TCP_CLOSING",\r
34 L"TCP_TIME_WAIT",\r
35 L"TCP_CLOSE_WAIT",\r
36 L"TCP_LAST_ACK"\r
37};\r
38\r
a3bcde70
HT
39/**\r
40 Initialize the Tcb local related members.\r
41\r
42 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
43\r
44**/\r
45VOID\r
46TcpInitTcbLocal (\r
d1050b9d 47 IN OUT TCP_CB *Tcb\r
a3bcde70
HT
48 )\r
49{\r
50 //\r
51 // Compute the checksum of the fixed parts of pseudo header\r
52 //\r
53 if (Tcb->Sk->IpVersion == IP_VERSION_4) {\r
54 Tcb->HeadSum = NetPseudoHeadChecksum (\r
d1050b9d
MK
55 Tcb->LocalEnd.Ip.Addr[0],\r
56 Tcb->RemoteEnd.Ip.Addr[0],\r
57 0x06,\r
58 0\r
59 );\r
a3bcde70
HT
60 } else {\r
61 Tcb->HeadSum = NetIp6PseudoHeadChecksum (\r
d1050b9d
MK
62 &Tcb->LocalEnd.Ip.v6,\r
63 &Tcb->RemoteEnd.Ip.v6,\r
64 0x06,\r
65 0\r
66 );\r
a3bcde70
HT
67 }\r
68\r
69 Tcb->Iss = TcpGetIss ();\r
70 Tcb->SndUna = Tcb->Iss;\r
71 Tcb->SndNxt = Tcb->Iss;\r
72\r
73 Tcb->SndWl2 = Tcb->Iss;\r
74 Tcb->SndWnd = 536;\r
75\r
76 Tcb->RcvWnd = GET_RCV_BUFFSIZE (Tcb->Sk);\r
77\r
78 //\r
79 // First window size is never scaled\r
80 //\r
d1050b9d 81 Tcb->RcvWndScale = 0;\r
3696ceae 82 Tcb->RetxmitSeqMax = 0;\r
a3bcde70
HT
83\r
84 Tcb->ProbeTimerOn = FALSE;\r
85}\r
86\r
87/**\r
88 Initialize the peer related members.\r
89\r
90 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
81c6f176 91 @param[in] Seg Pointer to the segment that contains the peer's initial info.\r
a3bcde70
HT
92 @param[in] Opt Pointer to the options announced by the peer.\r
93\r
94**/\r
95VOID\r
96TcpInitTcbPeer (\r
d1050b9d
MK
97 IN OUT TCP_CB *Tcb,\r
98 IN TCP_SEG *Seg,\r
99 IN TCP_OPTION *Opt\r
a3bcde70
HT
100 )\r
101{\r
102 UINT16 RcvMss;\r
103\r
104 ASSERT ((Tcb != NULL) && (Seg != NULL) && (Opt != NULL));\r
105 ASSERT (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN));\r
106\r
d1050b9d
MK
107 Tcb->SndWnd = Seg->Wnd;\r
108 Tcb->SndWndMax = Tcb->SndWnd;\r
109 Tcb->SndWl1 = Seg->Seq;\r
a3bcde70
HT
110\r
111 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_ACK)) {\r
112 Tcb->SndWl2 = Seg->Ack;\r
113 } else {\r
114 Tcb->SndWl2 = Tcb->Iss + 1;\r
115 }\r
116\r
117 if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_MSS)) {\r
d1050b9d 118 Tcb->SndMss = (UINT16)MAX (64, Opt->Mss);\r
a3bcde70 119\r
d1050b9d 120 RcvMss = TcpGetRcvMss (Tcb->Sk);\r
a3bcde70
HT
121 if (Tcb->SndMss > RcvMss) {\r
122 Tcb->SndMss = RcvMss;\r
123 }\r
a3bcde70
HT
124 } else {\r
125 //\r
126 // One end doesn't support MSS option, use default.\r
127 //\r
128 Tcb->RcvMss = 536;\r
129 }\r
130\r
d1050b9d 131 Tcb->CWnd = Tcb->SndMss;\r
a3bcde70
HT
132\r
133 Tcb->Irs = Seg->Seq;\r
134 Tcb->RcvNxt = Tcb->Irs + 1;\r
135\r
136 Tcb->RcvWl2 = Tcb->RcvNxt;\r
137\r
138 if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_WS) && !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS)) {\r
d1050b9d 139 Tcb->SndWndScale = Opt->WndScale;\r
a3bcde70 140\r
d1050b9d 141 Tcb->RcvWndScale = TcpComputeScale (Tcb);\r
a3bcde70 142 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS);\r
a3bcde70
HT
143 } else {\r
144 //\r
145 // One end doesn't support window scale option. use zero.\r
146 //\r
147 Tcb->RcvWndScale = 0;\r
148 }\r
149\r
150 if (TCP_FLG_ON (Opt->Flag, TCP_OPTION_RCVD_TS) && !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS)) {\r
a3bcde70
HT
151 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_TS);\r
152 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS);\r
153\r
185395a4
BZ
154 Tcb->TsRecent = Opt->TSVal;\r
155\r
a3bcde70
HT
156 //\r
157 // Compute the effective SndMss per RFC1122\r
158 // section 4.2.2.6. If timestamp option is\r
159 // enabled, it will always occupy 12 bytes.\r
160 //\r
161 Tcb->SndMss -= TCP_OPTION_TS_ALIGNED_LEN;\r
162 }\r
163}\r
164\r
165/**\r
166 Check whether one IP address equals the other.\r
167\r
168 @param[in] Ip1 Pointer to IP address to be checked.\r
169 @param[in] Ip2 Pointer to IP address to be checked.\r
170 @param[in] Version IP_VERSION_4 indicates the IP address is an IPv4 address,\r
171 IP_VERSION_6 indicates the IP address is an IPv6 address.\r
172\r
173 @retval TRUE Ip1 equals Ip2.\r
174 @retval FALSE Ip1 does not equal Ip2.\r
175\r
176**/\r
177BOOLEAN\r
178TcpIsIpEqual (\r
179 IN EFI_IP_ADDRESS *Ip1,\r
180 IN EFI_IP_ADDRESS *Ip2,\r
181 IN UINT8 Version\r
182 )\r
183{\r
184 ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));\r
185\r
186 if (Version == IP_VERSION_4) {\r
d1050b9d 187 return (BOOLEAN)(Ip1->Addr[0] == Ip2->Addr[0]);\r
a3bcde70 188 } else {\r
d1050b9d 189 return (BOOLEAN)EFI_IP6_EQUAL (&Ip1->v6, &Ip2->v6);\r
a3bcde70
HT
190 }\r
191}\r
192\r
193/**\r
194 Check whether one IP address is filled with ZERO.\r
195\r
196 @param[in] Ip Pointer to the IP address to be checked.\r
197 @param[in] Version IP_VERSION_4 indicates the IP address is an IPv4 address,\r
198 IP_VERSION_6 indicates the IP address is an IPv6 address.\r
199\r
200 @retval TRUE Ip is all zero address.\r
201 @retval FALSE Ip is not all zero address.\r
202\r
203**/\r
204BOOLEAN\r
205TcpIsIpZero (\r
d1050b9d
MK
206 IN EFI_IP_ADDRESS *Ip,\r
207 IN UINT8 Version\r
a3bcde70
HT
208 )\r
209{\r
210 ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));\r
211\r
212 if (Version == IP_VERSION_4) {\r
d1050b9d 213 return (BOOLEAN)(Ip->Addr[0] == 0);\r
a3bcde70 214 } else {\r
d1050b9d
MK
215 return (BOOLEAN)((Ip->Addr[0] == 0) && (Ip->Addr[1] == 0) &&\r
216 (Ip->Addr[2] == 0) && (Ip->Addr[3] == 0));\r
a3bcde70
HT
217 }\r
218}\r
219\r
220/**\r
221 Locate a listen TCB that matchs the Local and Remote.\r
222\r
223 @param[in] Local Pointer to the local (IP, Port).\r
224 @param[in] Remote Pointer to the remote (IP, Port).\r
225 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack,\r
226 IP_VERSION_6 indicates TCP is running on IP6 stack.\r
227\r
228 @return Pointer to the TCP_CB with the least number of wildcards,\r
229 if NULL no match is found.\r
230\r
231**/\r
232TCP_CB *\r
233TcpLocateListenTcb (\r
d1050b9d
MK
234 IN TCP_PEER *Local,\r
235 IN TCP_PEER *Remote,\r
236 IN UINT8 Version\r
a3bcde70
HT
237 )\r
238{\r
d1050b9d
MK
239 LIST_ENTRY *Entry;\r
240 TCP_CB *Node;\r
241 TCP_CB *Match;\r
242 INTN Last;\r
243 INTN Cur;\r
a3bcde70
HT
244\r
245 Last = 4;\r
246 Match = NULL;\r
247\r
248 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
249 Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
250\r
251 if ((Version != Node->Sk->IpVersion) ||\r
252 (Local->Port != Node->LocalEnd.Port) ||\r
253 !TCP_PEER_MATCH (Remote, &Node->RemoteEnd, Version) ||\r
254 !TCP_PEER_MATCH (Local, &Node->LocalEnd, Version)\r
d1050b9d
MK
255 )\r
256 {\r
a3bcde70
HT
257 continue;\r
258 }\r
259\r
260 //\r
261 // Compute the number of wildcard\r
262 //\r
263 Cur = 0;\r
264 if (TcpIsIpZero (&Node->RemoteEnd.Ip, Version)) {\r
265 Cur++;\r
266 }\r
267\r
268 if (Node->RemoteEnd.Port == 0) {\r
269 Cur++;\r
270 }\r
271\r
272 if (TcpIsIpZero (&Node->LocalEnd.Ip, Version)) {\r
273 Cur++;\r
274 }\r
275\r
276 if (Cur < Last) {\r
277 if (Cur == 0) {\r
278 return Node;\r
279 }\r
280\r
281 Last = Cur;\r
282 Match = Node;\r
283 }\r
284 }\r
285\r
286 return Match;\r
287}\r
288\r
289/**\r
290 Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>.\r
291\r
292 @param[in] Addr Pointer to the IP address needs to match.\r
293 @param[in] Port The port number needs to match.\r
294 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack,\r
295 IP_VERSION_6 indicates TCP is running on IP6 stack.\r
296\r
297\r
298 @retval TRUE The Tcb which matches the <Addr Port> pair exists.\r
299 @retval FALSE Otherwise\r
300\r
301**/\r
302BOOLEAN\r
303TcpFindTcbByPeer (\r
304 IN EFI_IP_ADDRESS *Addr,\r
305 IN TCP_PORTNO Port,\r
306 IN UINT8 Version\r
307 )\r
308{\r
d1050b9d
MK
309 TCP_PORTNO LocalPort;\r
310 LIST_ENTRY *Entry;\r
311 TCP_CB *Tcb;\r
a3bcde70
HT
312\r
313 ASSERT ((Addr != NULL) && (Port != 0));\r
314\r
315 LocalPort = HTONS (Port);\r
316\r
317 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
318 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
319\r
320 if ((Version == Tcb->Sk->IpVersion) &&\r
d1050b9d 321 TcpIsIpEqual (Addr, &Tcb->LocalEnd.Ip, Version) &&\r
a3bcde70 322 (LocalPort == Tcb->LocalEnd.Port)\r
d1050b9d
MK
323 )\r
324 {\r
a3bcde70
HT
325 return TRUE;\r
326 }\r
327 }\r
328\r
329 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
330 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
331\r
332 if ((Version == Tcb->Sk->IpVersion) &&\r
d1050b9d 333 TcpIsIpEqual (Addr, &Tcb->LocalEnd.Ip, Version) &&\r
a3bcde70 334 (LocalPort == Tcb->LocalEnd.Port)\r
d1050b9d
MK
335 )\r
336 {\r
a3bcde70
HT
337 return TRUE;\r
338 }\r
339 }\r
340\r
341 return FALSE;\r
342}\r
343\r
344/**\r
345 Locate the TCP_CB related to the socket pair.\r
346\r
347 @param[in] LocalPort The local port number.\r
348 @param[in] LocalIp The local IP address.\r
349 @param[in] RemotePort The remote port number.\r
350 @param[in] RemoteIp The remote IP address.\r
351 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack,\r
352 IP_VERSION_6 indicates TCP is running on IP6 stack.\r
353 @param[in] Syn If TRUE, the listen sockets are searched.\r
354\r
355 @return Pointer to the related TCP_CB. If NULL, no match is found.\r
356\r
357**/\r
358TCP_CB *\r
359TcpLocateTcb (\r
360 IN TCP_PORTNO LocalPort,\r
361 IN EFI_IP_ADDRESS *LocalIp,\r
362 IN TCP_PORTNO RemotePort,\r
363 IN EFI_IP_ADDRESS *RemoteIp,\r
364 IN UINT8 Version,\r
365 IN BOOLEAN Syn\r
366 )\r
367{\r
d1050b9d
MK
368 TCP_PEER Local;\r
369 TCP_PEER Remote;\r
370 LIST_ENTRY *Entry;\r
371 TCP_CB *Tcb;\r
a3bcde70
HT
372\r
373 Local.Port = LocalPort;\r
374 Remote.Port = RemotePort;\r
375\r
376 CopyMem (&Local.Ip, LocalIp, sizeof (EFI_IP_ADDRESS));\r
377 CopyMem (&Remote.Ip, RemoteIp, sizeof (EFI_IP_ADDRESS));\r
378\r
379 //\r
380 // First check for exact match.\r
381 //\r
382 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
383 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
384\r
385 if ((Version == Tcb->Sk->IpVersion) &&\r
386 TCP_PEER_EQUAL (&Remote, &Tcb->RemoteEnd, Version) &&\r
387 TCP_PEER_EQUAL (&Local, &Tcb->LocalEnd, Version)\r
d1050b9d
MK
388 )\r
389 {\r
a3bcde70
HT
390 RemoveEntryList (&Tcb->List);\r
391 InsertHeadList (&mTcpRunQue, &Tcb->List);\r
392\r
393 return Tcb;\r
394 }\r
395 }\r
396\r
397 //\r
398 // Only check the listen queue when the SYN flag is on.\r
399 //\r
400 if (Syn) {\r
401 return TcpLocateListenTcb (&Local, &Remote, Version);\r
402 }\r
403\r
404 return NULL;\r
405}\r
406\r
407/**\r
408 Insert a Tcb into the proper queue.\r
409\r
410 @param[in] Tcb Pointer to the TCP_CB to be inserted.\r
411\r
412 @retval 0 The Tcb was inserted successfully.\r
413 @retval -1 Error condition occurred.\r
414\r
415**/\r
416INTN\r
417TcpInsertTcb (\r
d1050b9d 418 IN TCP_CB *Tcb\r
a3bcde70
HT
419 )\r
420{\r
d1050b9d
MK
421 LIST_ENTRY *Entry;\r
422 LIST_ENTRY *Head;\r
423 TCP_CB *Node;\r
a3bcde70
HT
424\r
425 ASSERT (\r
426 (Tcb != NULL) &&\r
427 (\r
d1050b9d
MK
428 (Tcb->State == TCP_LISTEN) ||\r
429 (Tcb->State == TCP_SYN_SENT) ||\r
430 (Tcb->State == TCP_SYN_RCVD) ||\r
431 (Tcb->State == TCP_CLOSED)\r
a3bcde70
HT
432 )\r
433 );\r
434\r
435 if (Tcb->LocalEnd.Port == 0) {\r
436 return -1;\r
437 }\r
438\r
439 Head = &mTcpRunQue;\r
440\r
441 if (Tcb->State == TCP_LISTEN) {\r
442 Head = &mTcpListenQue;\r
443 }\r
444\r
445 //\r
446 // Check that the Tcb isn't already on the list.\r
447 //\r
448 NET_LIST_FOR_EACH (Entry, Head) {\r
449 Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
450\r
451 if (TCP_PEER_EQUAL (&Tcb->LocalEnd, &Node->LocalEnd, Tcb->Sk->IpVersion) &&\r
452 TCP_PEER_EQUAL (&Tcb->RemoteEnd, &Node->RemoteEnd, Tcb->Sk->IpVersion)\r
d1050b9d
MK
453 )\r
454 {\r
a3bcde70
HT
455 return -1;\r
456 }\r
457 }\r
458\r
459 InsertHeadList (Head, &Tcb->List);\r
460\r
a3bcde70
HT
461 return 0;\r
462}\r
463\r
464/**\r
465 Clone a TCP_CB from Tcb.\r
466\r
467 @param[in] Tcb Pointer to the TCP_CB to be cloned.\r
468\r
469 @return Pointer to the new cloned TCP_CB; if NULL, error condition occurred.\r
470\r
471**/\r
472TCP_CB *\r
473TcpCloneTcb (\r
d1050b9d 474 IN TCP_CB *Tcb\r
a3bcde70
HT
475 )\r
476{\r
d1050b9d 477 TCP_CB *Clone;\r
a3bcde70
HT
478\r
479 Clone = AllocateZeroPool (sizeof (TCP_CB));\r
480\r
481 if (Clone == NULL) {\r
482 return NULL;\r
483 }\r
484\r
485 CopyMem (Clone, Tcb, sizeof (TCP_CB));\r
486\r
487 //\r
488 // Increase the reference count of the shared IpInfo.\r
489 //\r
490 NET_GET_REF (Tcb->IpInfo);\r
491\r
492 InitializeListHead (&Clone->List);\r
493 InitializeListHead (&Clone->SndQue);\r
494 InitializeListHead (&Clone->RcvQue);\r
495\r
496 Clone->Sk = SockClone (Tcb->Sk);\r
497 if (Clone->Sk == NULL) {\r
c49ca4a2 498 DEBUG ((DEBUG_ERROR, "TcpCloneTcb: failed to clone a sock\n"));\r
a3bcde70
HT
499 FreePool (Clone);\r
500 return NULL;\r
501 }\r
502\r
d1050b9d 503 ((TCP_PROTO_DATA *)(Clone->Sk->ProtoReserved))->TcpPcb = Clone;\r
a3bcde70
HT
504\r
505 return Clone;\r
506}\r
507\r
508/**\r
509 Compute an ISS to be used by a new connection.\r
510\r
511 @return The resulting ISS.\r
512\r
513**/\r
514TCP_SEQNO\r
515TcpGetIss (\r
516 VOID\r
517 )\r
518{\r
519 mTcpGlobalIss += TCP_ISS_INCREMENT_1;\r
520 return mTcpGlobalIss;\r
521}\r
522\r
523/**\r
524 Get the local mss.\r
525\r
526 @param[in] Sock Pointer to the socket to get mss.\r
527\r
528 @return The mss size.\r
529\r
530**/\r
531UINT16\r
532TcpGetRcvMss (\r
533 IN SOCKET *Sock\r
534 )\r
535{\r
d1050b9d
MK
536 EFI_IP4_MODE_DATA Ip4Mode;\r
537 EFI_IP6_MODE_DATA Ip6Mode;\r
538 EFI_IP4_PROTOCOL *Ip4;\r
539 EFI_IP6_PROTOCOL *Ip6;\r
540 TCP_PROTO_DATA *TcpProto;\r
a3bcde70
HT
541\r
542 ASSERT (Sock != NULL);\r
543\r
544 ZeroMem (&Ip4Mode, sizeof (EFI_IP4_MODE_DATA));\r
545 ZeroMem (&Ip6Mode, sizeof (EFI_IP6_MODE_DATA));\r
546\r
d1050b9d 547 TcpProto = (TCP_PROTO_DATA *)Sock->ProtoReserved;\r
a3bcde70
HT
548\r
549 if (Sock->IpVersion == IP_VERSION_4) {\r
550 Ip4 = TcpProto->TcpService->IpIo->Ip.Ip4;\r
551 ASSERT (Ip4 != NULL);\r
552 Ip4->GetModeData (Ip4, &Ip4Mode, NULL, NULL);\r
553\r
d1050b9d 554 return (UINT16)(Ip4Mode.MaxPacketSize - sizeof (TCP_HEAD));\r
a3bcde70
HT
555 } else {\r
556 Ip6 = TcpProto->TcpService->IpIo->Ip.Ip6;\r
557 ASSERT (Ip6 != NULL);\r
ce22514e
ZL
558 if (!EFI_ERROR (Ip6->GetModeData (Ip6, &Ip6Mode, NULL, NULL))) {\r
559 if (Ip6Mode.AddressList != NULL) {\r
560 FreePool (Ip6Mode.AddressList);\r
561 }\r
562\r
563 if (Ip6Mode.GroupTable != NULL) {\r
564 FreePool (Ip6Mode.GroupTable);\r
565 }\r
566\r
567 if (Ip6Mode.RouteTable != NULL) {\r
568 FreePool (Ip6Mode.RouteTable);\r
569 }\r
570\r
571 if (Ip6Mode.NeighborCache != NULL) {\r
572 FreePool (Ip6Mode.NeighborCache);\r
573 }\r
574\r
575 if (Ip6Mode.PrefixTable != NULL) {\r
576 FreePool (Ip6Mode.PrefixTable);\r
577 }\r
578\r
579 if (Ip6Mode.IcmpTypeList != NULL) {\r
580 FreePool (Ip6Mode.IcmpTypeList);\r
581 }\r
582 }\r
a3bcde70 583\r
d1050b9d 584 return (UINT16)(Ip6Mode.MaxPacketSize - sizeof (TCP_HEAD));\r
a3bcde70
HT
585 }\r
586}\r
587\r
588/**\r
589 Set the Tcb's state.\r
590\r
591 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
592 @param[in] State The state to be set.\r
593\r
594**/\r
595VOID\r
596TcpSetState (\r
d1050b9d
MK
597 IN TCP_CB *Tcb,\r
598 IN UINT8 State\r
a3bcde70
HT
599 )\r
600{\r
601 ASSERT (Tcb->State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));\r
602 ASSERT (State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));\r
603\r
604 DEBUG (\r
c49ca4a2 605 (DEBUG_NET,\r
d1050b9d
MK
606 "Tcb (%p) state %s --> %s\n",\r
607 Tcb,\r
608 mTcpStateName[Tcb->State],\r
609 mTcpStateName[State])\r
a3bcde70
HT
610 );\r
611\r
612 Tcb->State = State;\r
613\r
614 switch (State) {\r
d1050b9d 615 case TCP_ESTABLISHED:\r
a3bcde70 616\r
d1050b9d 617 SockConnEstablished (Tcb->Sk);\r
a3bcde70 618\r
d1050b9d
MK
619 if (Tcb->Parent != NULL) {\r
620 //\r
621 // A new connection is accepted by a listening socket. Install\r
622 // the device path.\r
623 //\r
624 TcpInstallDevicePath (Tcb->Sk);\r
625 }\r
a3bcde70 626\r
d1050b9d 627 break;\r
a3bcde70 628\r
d1050b9d 629 case TCP_CLOSED:\r
a3bcde70 630\r
d1050b9d 631 SockConnClosed (Tcb->Sk);\r
a3bcde70 632\r
d1050b9d
MK
633 break;\r
634 default:\r
635 break;\r
a3bcde70
HT
636 }\r
637}\r
638\r
639/**\r
640 Compute the TCP segment's checksum.\r
641\r
642 @param[in] Nbuf Pointer to the buffer that contains the TCP segment.\r
643 @param[in] HeadSum The checksum value of the fixed part of pseudo header.\r
644\r
645 @return The checksum value.\r
646\r
647**/\r
648UINT16\r
649TcpChecksum (\r
d1050b9d
MK
650 IN NET_BUF *Nbuf,\r
651 IN UINT16 HeadSum\r
a3bcde70
HT
652 )\r
653{\r
654 UINT16 Checksum;\r
655\r
d1050b9d
MK
656 Checksum = NetbufChecksum (Nbuf);\r
657 Checksum = NetAddChecksum (Checksum, HeadSum);\r
a3bcde70
HT
658\r
659 Checksum = NetAddChecksum (\r
d1050b9d
MK
660 Checksum,\r
661 HTONS ((UINT16)Nbuf->TotalSize)\r
662 );\r
a3bcde70 663\r
d1050b9d 664 return (UINT16)(~Checksum);\r
a3bcde70
HT
665}\r
666\r
667/**\r
668 Translate the information from the head of the received TCP\r
669 segment Nbuf contents and fill it into a TCP_SEG structure.\r
670\r
671 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
672 @param[in, out] Nbuf Pointer to the buffer contains the TCP segment.\r
673\r
674 @return Pointer to the TCP_SEG that contains the translated TCP head information.\r
675\r
676**/\r
677TCP_SEG *\r
678TcpFormatNetbuf (\r
d1050b9d
MK
679 IN TCP_CB *Tcb,\r
680 IN OUT NET_BUF *Nbuf\r
a3bcde70
HT
681 )\r
682{\r
683 TCP_SEG *Seg;\r
684 TCP_HEAD *Head;\r
685\r
d1050b9d
MK
686 Seg = TCPSEG_NETBUF (Nbuf);\r
687 Head = (TCP_HEAD *)NetbufGetByte (Nbuf, 0, NULL);\r
a3bcde70
HT
688 ASSERT (Head != NULL);\r
689\r
690 Nbuf->Tcp = Head;\r
691\r
d1050b9d
MK
692 Seg->Seq = NTOHL (Head->Seq);\r
693 Seg->Ack = NTOHL (Head->Ack);\r
694 Seg->End = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2));\r
a3bcde70
HT
695\r
696 Seg->Urg = NTOHS (Head->Urg);\r
697 Seg->Wnd = (NTOHS (Head->Wnd) << Tcb->SndWndScale);\r
698 Seg->Flag = Head->Flag;\r
699\r
700 //\r
701 // SYN and FIN flag occupy one sequence space each.\r
702 //\r
703 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
704 //\r
705 // RFC requires that the initial window not be scaled.\r
706 //\r
707 Seg->Wnd = NTOHS (Head->Wnd);\r
708 Seg->End++;\r
709 }\r
710\r
711 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
712 Seg->End++;\r
713 }\r
714\r
715 return Seg;\r
716}\r
717\r
718/**\r
719 Initialize an active connection.\r
720\r
721 @param[in, out] Tcb Pointer to the TCP_CB that wants to initiate a\r
722 connection.\r
723\r
724**/\r
725VOID\r
726TcpOnAppConnect (\r
727 IN OUT TCP_CB *Tcb\r
728 )\r
729{\r
730 TcpInitTcbLocal (Tcb);\r
731 TcpSetState (Tcb, TCP_SYN_SENT);\r
732\r
733 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
734 TcpToSendData (Tcb, 1);\r
735}\r
736\r
737/**\r
738 Initiate the connection close procedure, called when\r
739 applications want to close the connection.\r
740\r
741 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
742\r
743**/\r
744VOID\r
745TcpOnAppClose (\r
d1050b9d 746 IN OUT TCP_CB *Tcb\r
a3bcde70
HT
747 )\r
748{\r
749 ASSERT (Tcb != NULL);\r
750\r
d1050b9d 751 if (!IsListEmpty (&Tcb->RcvQue) || (GET_RCV_DATASIZE (Tcb->Sk) != 0)) {\r
a3bcde70 752 DEBUG (\r
c49ca4a2 753 (DEBUG_WARN,\r
d1050b9d
MK
754 "TcpOnAppClose: connection reset because data is lost for TCB %p\n",\r
755 Tcb)\r
a3bcde70
HT
756 );\r
757\r
758 TcpResetConnection (Tcb);\r
759 TcpClose (Tcb);\r
760 return;\r
761 }\r
762\r
763 switch (Tcb->State) {\r
d1050b9d
MK
764 case TCP_CLOSED:\r
765 case TCP_LISTEN:\r
766 case TCP_SYN_SENT:\r
767 TcpSetState (Tcb, TCP_CLOSED);\r
768 break;\r
769\r
770 case TCP_SYN_RCVD:\r
771 case TCP_ESTABLISHED:\r
772 TcpSetState (Tcb, TCP_FIN_WAIT_1);\r
773 break;\r
774\r
775 case TCP_CLOSE_WAIT:\r
776 TcpSetState (Tcb, TCP_LAST_ACK);\r
777 break;\r
778 default:\r
779 break;\r
a3bcde70
HT
780 }\r
781\r
782 TcpToSendData (Tcb, 1);\r
783}\r
784\r
785/**\r
786 Check whether the application's newly delivered data can be sent out.\r
787\r
788 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
789\r
790 @retval 0 The data has been sent out successfully.\r
791 @retval -1 The Tcb is not in a state that data is permitted to\r
792 be sent out.\r
793\r
794**/\r
795INTN\r
796TcpOnAppSend (\r
d1050b9d 797 IN OUT TCP_CB *Tcb\r
a3bcde70
HT
798 )\r
799{\r
a3bcde70 800 switch (Tcb->State) {\r
d1050b9d
MK
801 case TCP_CLOSED:\r
802 return -1;\r
a3bcde70 803\r
d1050b9d
MK
804 case TCP_LISTEN:\r
805 return -1;\r
a3bcde70 806\r
d1050b9d
MK
807 case TCP_SYN_SENT:\r
808 case TCP_SYN_RCVD:\r
809 return 0;\r
a3bcde70 810\r
d1050b9d
MK
811 case TCP_ESTABLISHED:\r
812 case TCP_CLOSE_WAIT:\r
813 TcpToSendData (Tcb, 0);\r
814 return 0;\r
a3bcde70 815\r
d1050b9d
MK
816 case TCP_FIN_WAIT_1:\r
817 case TCP_FIN_WAIT_2:\r
818 case TCP_CLOSING:\r
819 case TCP_LAST_ACK:\r
820 case TCP_TIME_WAIT:\r
821 return -1;\r
a3bcde70 822\r
d1050b9d
MK
823 default:\r
824 break;\r
a3bcde70
HT
825 }\r
826\r
827 return 0;\r
828}\r
829\r
830/**\r
831 Application has consumed some data. Check whether\r
832 to send a window update ack or a delayed ack.\r
833\r
834 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
835\r
836**/\r
837VOID\r
838TcpOnAppConsume (\r
d1050b9d 839 IN TCP_CB *Tcb\r
a3bcde70
HT
840 )\r
841{\r
d1050b9d 842 UINT32 TcpOld;\r
a3bcde70
HT
843\r
844 switch (Tcb->State) {\r
d1050b9d
MK
845 case TCP_ESTABLISHED:\r
846 TcpOld = TcpRcvWinOld (Tcb);\r
847 if (TcpRcvWinNow (Tcb) > TcpOld) {\r
848 if (TcpOld < Tcb->RcvMss) {\r
849 DEBUG (\r
850 (DEBUG_NET,\r
851 "TcpOnAppConsume: send a window update for a window closed Tcb %p\n",\r
852 Tcb)\r
853 );\r
854\r
855 TcpSendAck (Tcb);\r
856 } else if (Tcb->DelayedAck == 0) {\r
857 DEBUG (\r
858 (DEBUG_NET,\r
859 "TcpOnAppConsume: scheduled a delayed ACK to update window for Tcb %p\n",\r
860 Tcb)\r
861 );\r
862\r
863 Tcb->DelayedAck = 1;\r
864 }\r
a3bcde70 865 }\r
a3bcde70 866\r
d1050b9d 867 break;\r
a3bcde70 868\r
d1050b9d
MK
869 default:\r
870 break;\r
a3bcde70
HT
871 }\r
872}\r
873\r
874/**\r
875 Abort the connection by sending a reset segment. Called\r
876 when the application wants to abort the connection.\r
877\r
878 @param[in] Tcb Pointer to the TCP_CB of the TCP instance.\r
879\r
880**/\r
881VOID\r
882TcpOnAppAbort (\r
d1050b9d 883 IN TCP_CB *Tcb\r
a3bcde70
HT
884 )\r
885{\r
886 DEBUG (\r
c49ca4a2 887 (DEBUG_WARN,\r
d1050b9d
MK
888 "TcpOnAppAbort: connection reset issued by application for TCB %p\n",\r
889 Tcb)\r
a3bcde70
HT
890 );\r
891\r
892 switch (Tcb->State) {\r
d1050b9d
MK
893 case TCP_SYN_RCVD:\r
894 case TCP_ESTABLISHED:\r
895 case TCP_FIN_WAIT_1:\r
896 case TCP_FIN_WAIT_2:\r
897 case TCP_CLOSE_WAIT:\r
898 TcpResetConnection (Tcb);\r
899 break;\r
900 default:\r
901 break;\r
a3bcde70
HT
902 }\r
903\r
904 TcpSetState (Tcb, TCP_CLOSED);\r
905}\r
906\r
907/**\r
908 Reset the connection related with Tcb.\r
909\r
910 @param[in] Tcb Pointer to the TCP_CB of the connection to be reset.\r
911\r
912**/\r
913VOID\r
914TcpResetConnection (\r
d1050b9d 915 IN TCP_CB *Tcb\r
a3bcde70
HT
916 )\r
917{\r
918 NET_BUF *Nbuf;\r
919 TCP_HEAD *Nhead;\r
920\r
921 Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
922\r
923 if (Nbuf == NULL) {\r
d1050b9d 924 return;\r
a3bcde70
HT
925 }\r
926\r
d1050b9d 927 Nhead = (TCP_HEAD *)NetbufAllocSpace (\r
a3bcde70
HT
928 Nbuf,\r
929 sizeof (TCP_HEAD),\r
930 NET_BUF_TAIL\r
931 );\r
932\r
933 ASSERT (Nhead != NULL);\r
934\r
d1050b9d 935 Nbuf->Tcp = Nhead;\r
a3bcde70
HT
936\r
937 Nhead->Flag = TCP_FLG_RST;\r
938 Nhead->Seq = HTONL (Tcb->SndNxt);\r
939 Nhead->Ack = HTONL (Tcb->RcvNxt);\r
940 Nhead->SrcPort = Tcb->LocalEnd.Port;\r
941 Nhead->DstPort = Tcb->RemoteEnd.Port;\r
d1050b9d 942 Nhead->HeadLen = (UINT8)(sizeof (TCP_HEAD) >> 2);\r
a3bcde70
HT
943 Nhead->Res = 0;\r
944 Nhead->Wnd = HTONS (0xFFFF);\r
945 Nhead->Checksum = 0;\r
946 Nhead->Urg = 0;\r
947 Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);\r
948\r
949 TcpSendIpPacket (Tcb, Nbuf, &Tcb->LocalEnd.Ip, &Tcb->RemoteEnd.Ip, Tcb->Sk->IpVersion);\r
950\r
951 NetbufFree (Nbuf);\r
952}\r
953\r
a3bcde70
HT
954/**\r
955 Install the device path protocol on the TCP instance.\r
956\r
957 @param[in] Sock Pointer to the socket representing the TCP instance.\r
958\r
959 @retval EFI_SUCCESS The device path protocol was installed.\r
960 @retval other Failed to install the device path protocol.\r
961\r
962**/\r
963EFI_STATUS\r
964TcpInstallDevicePath (\r
d1050b9d 965 IN SOCKET *Sock\r
a3bcde70
HT
966 )\r
967{\r
d1050b9d
MK
968 TCP_PROTO_DATA *TcpProto;\r
969 TCP_SERVICE_DATA *TcpService;\r
970 TCP_CB *Tcb;\r
971 IPv4_DEVICE_PATH Ip4DPathNode;\r
972 IPv6_DEVICE_PATH Ip6DPathNode;\r
973 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
974 EFI_STATUS Status;\r
975 TCP_PORTNO LocalPort;\r
976 TCP_PORTNO RemotePort;\r
977\r
978 TcpProto = (TCP_PROTO_DATA *)Sock->ProtoReserved;\r
a3bcde70
HT
979 TcpService = TcpProto->TcpService;\r
980 Tcb = TcpProto->TcpPcb;\r
981\r
d1050b9d 982 LocalPort = NTOHS (Tcb->LocalEnd.Port);\r
a3bcde70
HT
983 RemotePort = NTOHS (Tcb->RemoteEnd.Port);\r
984 if (Sock->IpVersion == IP_VERSION_4) {\r
985 NetLibCreateIPv4DPathNode (\r
986 &Ip4DPathNode,\r
987 TcpService->ControllerHandle,\r
988 Tcb->LocalEnd.Ip.Addr[0],\r
989 LocalPort,\r
990 Tcb->RemoteEnd.Ip.Addr[0],\r
991 RemotePort,\r
992 EFI_IP_PROTO_TCP,\r
993 Tcb->UseDefaultAddr\r
994 );\r
995\r
501793fa
RN
996 IP4_COPY_ADDRESS (&Ip4DPathNode.SubnetMask, &Tcb->SubnetMask);\r
997\r
d1050b9d 998 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&Ip4DPathNode;\r
a3bcde70
HT
999 } else {\r
1000 NetLibCreateIPv6DPathNode (\r
1001 &Ip6DPathNode,\r
1002 TcpService->ControllerHandle,\r
1003 &Tcb->LocalEnd.Ip.v6,\r
1004 LocalPort,\r
1005 &Tcb->RemoteEnd.Ip.v6,\r
1006 RemotePort,\r
1007 EFI_IP_PROTO_TCP\r
1008 );\r
1009\r
d1050b9d 1010 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&Ip6DPathNode;\r
a3bcde70
HT
1011 }\r
1012\r
1013 Sock->DevicePath = AppendDevicePathNode (Sock->ParentDevicePath, DevicePath);\r
1014 if (Sock->DevicePath == NULL) {\r
1015 return EFI_OUT_OF_RESOURCES;\r
1016 }\r
1017\r
1018 Status = gBS->InstallProtocolInterface (\r
1019 &Sock->SockHandle,\r
1020 &gEfiDevicePathProtocolGuid,\r
1021 EFI_NATIVE_INTERFACE,\r
1022 Sock->DevicePath\r
1023 );\r
1024 if (EFI_ERROR (Status)) {\r
1025 FreePool (Sock->DevicePath);\r
1026 Sock->DevicePath = NULL;\r
1027 }\r
1028\r
1029 return Status;\r
1030}\r