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