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