]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/TcpDxe/TcpMisc.c
SecurityPkg: Add TPM PTP support in TCG2 SMM.
[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
185395a4 5 Copyright (c) 2009 - 2015, 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
569 Ip6->GetModeData (Ip6, &Ip6Mode, NULL, NULL);\r
570\r
571 return (UINT16) (Ip6Mode.MaxPacketSize - sizeof (TCP_HEAD));\r
572 }\r
573}\r
574\r
575/**\r
576 Set the Tcb's state.\r
577\r
578 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
579 @param[in] State The state to be set.\r
580\r
581**/\r
582VOID\r
583TcpSetState (\r
584 IN TCP_CB *Tcb,\r
585 IN UINT8 State\r
586 )\r
587{\r
588 ASSERT (Tcb->State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));\r
589 ASSERT (State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));\r
590\r
591 DEBUG (\r
592 (EFI_D_INFO,\r
593 "Tcb (%p) state %s --> %s\n",\r
594 Tcb,\r
595 mTcpStateName[Tcb->State],\r
596 mTcpStateName[State])\r
597 );\r
598\r
599 Tcb->State = State;\r
600\r
601 switch (State) {\r
602 case TCP_ESTABLISHED:\r
603\r
604 SockConnEstablished (Tcb->Sk);\r
605\r
606 if (Tcb->Parent != NULL) {\r
607 //\r
608 // A new connection is accepted by a listening socket. Install\r
609 // the device path.\r
610 //\r
611 TcpInstallDevicePath (Tcb->Sk);\r
612 }\r
613\r
614 break;\r
615\r
616 case TCP_CLOSED:\r
617\r
618 SockConnClosed (Tcb->Sk);\r
619\r
620 break;\r
621 default:\r
622 break;\r
623 }\r
624}\r
625\r
626/**\r
627 Compute the TCP segment's checksum.\r
628\r
629 @param[in] Nbuf Pointer to the buffer that contains the TCP segment.\r
630 @param[in] HeadSum The checksum value of the fixed part of pseudo header.\r
631\r
632 @return The checksum value.\r
633\r
634**/\r
635UINT16\r
636TcpChecksum (\r
637 IN NET_BUF *Nbuf,\r
638 IN UINT16 HeadSum\r
639 )\r
640{\r
641 UINT16 Checksum;\r
642\r
643 Checksum = NetbufChecksum (Nbuf);\r
644 Checksum = NetAddChecksum (Checksum, HeadSum);\r
645\r
646 Checksum = NetAddChecksum (\r
647 Checksum,\r
648 HTONS ((UINT16) Nbuf->TotalSize)\r
649 );\r
650\r
651 return (UINT16) (~Checksum);\r
652}\r
653\r
654/**\r
655 Translate the information from the head of the received TCP\r
656 segment Nbuf contents and fill it into a TCP_SEG structure.\r
657\r
658 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
659 @param[in, out] Nbuf Pointer to the buffer contains the TCP segment.\r
660\r
661 @return Pointer to the TCP_SEG that contains the translated TCP head information.\r
662\r
663**/\r
664TCP_SEG *\r
665TcpFormatNetbuf (\r
666 IN TCP_CB *Tcb,\r
667 IN OUT NET_BUF *Nbuf\r
668 )\r
669{\r
670 TCP_SEG *Seg;\r
671 TCP_HEAD *Head;\r
672\r
673 Seg = TCPSEG_NETBUF (Nbuf);\r
674 Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
675 ASSERT (Head != NULL);\r
676\r
677 Nbuf->Tcp = Head;\r
678\r
679 Seg->Seq = NTOHL (Head->Seq);\r
680 Seg->Ack = NTOHL (Head->Ack);\r
681 Seg->End = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2));\r
682\r
683 Seg->Urg = NTOHS (Head->Urg);\r
684 Seg->Wnd = (NTOHS (Head->Wnd) << Tcb->SndWndScale);\r
685 Seg->Flag = Head->Flag;\r
686\r
687 //\r
688 // SYN and FIN flag occupy one sequence space each.\r
689 //\r
690 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
691 //\r
692 // RFC requires that the initial window not be scaled.\r
693 //\r
694 Seg->Wnd = NTOHS (Head->Wnd);\r
695 Seg->End++;\r
696 }\r
697\r
698 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
699 Seg->End++;\r
700 }\r
701\r
702 return Seg;\r
703}\r
704\r
705/**\r
706 Initialize an active connection.\r
707\r
708 @param[in, out] Tcb Pointer to the TCP_CB that wants to initiate a\r
709 connection.\r
710\r
711**/\r
712VOID\r
713TcpOnAppConnect (\r
714 IN OUT TCP_CB *Tcb\r
715 )\r
716{\r
717 TcpInitTcbLocal (Tcb);\r
718 TcpSetState (Tcb, TCP_SYN_SENT);\r
719\r
720 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
721 TcpToSendData (Tcb, 1);\r
722}\r
723\r
724/**\r
725 Initiate the connection close procedure, called when\r
726 applications want to close the connection.\r
727\r
728 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
729\r
730**/\r
731VOID\r
732TcpOnAppClose (\r
733 IN OUT TCP_CB *Tcb\r
734 )\r
735{\r
736 ASSERT (Tcb != NULL);\r
737\r
738 if (!IsListEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk) != 0) {\r
739\r
740 DEBUG (\r
741 (EFI_D_WARN,\r
742 "TcpOnAppClose: connection reset because data is lost for TCB %p\n",\r
743 Tcb)\r
744 );\r
745\r
746 TcpResetConnection (Tcb);\r
747 TcpClose (Tcb);\r
748 return;\r
749 }\r
750\r
751 switch (Tcb->State) {\r
752 case TCP_CLOSED:\r
753 case TCP_LISTEN:\r
754 case TCP_SYN_SENT:\r
755 TcpSetState (Tcb, TCP_CLOSED);\r
756 break;\r
757\r
758 case TCP_SYN_RCVD:\r
759 case TCP_ESTABLISHED:\r
760 TcpSetState (Tcb, TCP_FIN_WAIT_1);\r
761 break;\r
762\r
763 case TCP_CLOSE_WAIT:\r
764 TcpSetState (Tcb, TCP_LAST_ACK);\r
765 break;\r
766 default:\r
767 break;\r
768 }\r
769\r
770 TcpToSendData (Tcb, 1);\r
771}\r
772\r
773/**\r
774 Check whether the application's newly delivered data can be sent out.\r
775\r
776 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
777\r
778 @retval 0 The data has been sent out successfully.\r
779 @retval -1 The Tcb is not in a state that data is permitted to\r
780 be sent out.\r
781\r
782**/\r
783INTN\r
784TcpOnAppSend (\r
785 IN OUT TCP_CB *Tcb\r
786 )\r
787{\r
788\r
789 switch (Tcb->State) {\r
790 case TCP_CLOSED:\r
791 return -1;\r
792\r
793 case TCP_LISTEN:\r
794 return -1;\r
795\r
796 case TCP_SYN_SENT:\r
797 case TCP_SYN_RCVD:\r
798 return 0;\r
799\r
800 case TCP_ESTABLISHED:\r
801 case TCP_CLOSE_WAIT:\r
802 TcpToSendData (Tcb, 0);\r
803 return 0;\r
804\r
805 case TCP_FIN_WAIT_1:\r
806 case TCP_FIN_WAIT_2:\r
807 case TCP_CLOSING:\r
808 case TCP_LAST_ACK:\r
809 case TCP_TIME_WAIT:\r
810 return -1;\r
811\r
812 default:\r
813 break;\r
814 }\r
815\r
816 return 0;\r
817}\r
818\r
819/**\r
820 Application has consumed some data. Check whether\r
821 to send a window update ack or a delayed ack.\r
822\r
823 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
824\r
825**/\r
826VOID\r
827TcpOnAppConsume (\r
828 IN TCP_CB *Tcb\r
829 )\r
830{\r
831 UINT32 TcpOld;\r
832\r
833 switch (Tcb->State) {\r
834 case TCP_ESTABLISHED:\r
835 TcpOld = TcpRcvWinOld (Tcb);\r
836 if (TcpRcvWinNow (Tcb) > TcpOld) {\r
837\r
838 if (TcpOld < Tcb->RcvMss) {\r
839\r
840 DEBUG (\r
841 (EFI_D_INFO,\r
842 "TcpOnAppConsume: send a window update for a window closed Tcb %p\n",\r
843 Tcb)\r
844 );\r
845\r
846 TcpSendAck (Tcb);\r
847 } else if (Tcb->DelayedAck == 0) {\r
848\r
849 DEBUG (\r
850 (EFI_D_INFO,\r
851 "TcpOnAppConsume: scheduled a delayed ACK to update window for Tcb %p\n",\r
852 Tcb)\r
853 );\r
854\r
855 Tcb->DelayedAck = 1;\r
856 }\r
857 }\r
858\r
859 break;\r
860\r
861 default:\r
862 break;\r
863 }\r
864}\r
865\r
866/**\r
867 Abort the connection by sending a reset segment. Called\r
868 when the application wants to abort the connection.\r
869\r
870 @param[in] Tcb Pointer to the TCP_CB of the TCP instance.\r
871\r
872**/\r
873VOID\r
874TcpOnAppAbort (\r
875 IN TCP_CB *Tcb\r
876 )\r
877{\r
878 DEBUG (\r
879 (EFI_D_WARN,\r
880 "TcpOnAppAbort: connection reset issued by application for TCB %p\n",\r
881 Tcb)\r
882 );\r
883\r
884 switch (Tcb->State) {\r
885 case TCP_SYN_RCVD:\r
886 case TCP_ESTABLISHED:\r
887 case TCP_FIN_WAIT_1:\r
888 case TCP_FIN_WAIT_2:\r
889 case TCP_CLOSE_WAIT:\r
890 TcpResetConnection (Tcb);\r
891 break;\r
892 default:\r
893 break;\r
894 }\r
895\r
896 TcpSetState (Tcb, TCP_CLOSED);\r
897}\r
898\r
899/**\r
900 Reset the connection related with Tcb.\r
901\r
902 @param[in] Tcb Pointer to the TCP_CB of the connection to be reset.\r
903\r
904**/\r
905VOID\r
906TcpResetConnection (\r
907 IN TCP_CB *Tcb\r
908 )\r
909{\r
910 NET_BUF *Nbuf;\r
911 TCP_HEAD *Nhead;\r
912\r
913 Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
914\r
915 if (Nbuf == NULL) {\r
916 return ;\r
917 }\r
918\r
919 Nhead = (TCP_HEAD *) NetbufAllocSpace (\r
920 Nbuf,\r
921 sizeof (TCP_HEAD),\r
922 NET_BUF_TAIL\r
923 );\r
924\r
925 ASSERT (Nhead != NULL);\r
926\r
927 Nbuf->Tcp = Nhead;\r
928\r
929 Nhead->Flag = TCP_FLG_RST;\r
930 Nhead->Seq = HTONL (Tcb->SndNxt);\r
931 Nhead->Ack = HTONL (Tcb->RcvNxt);\r
932 Nhead->SrcPort = Tcb->LocalEnd.Port;\r
933 Nhead->DstPort = Tcb->RemoteEnd.Port;\r
934 Nhead->HeadLen = (UINT8) (sizeof (TCP_HEAD) >> 2);\r
935 Nhead->Res = 0;\r
936 Nhead->Wnd = HTONS (0xFFFF);\r
937 Nhead->Checksum = 0;\r
938 Nhead->Urg = 0;\r
939 Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);\r
940\r
941 TcpSendIpPacket (Tcb, Nbuf, &Tcb->LocalEnd.Ip, &Tcb->RemoteEnd.Ip, Tcb->Sk->IpVersion);\r
942\r
943 NetbufFree (Nbuf);\r
944}\r
945\r
a3bcde70
HT
946/**\r
947 Install the device path protocol on the TCP instance.\r
948\r
949 @param[in] Sock Pointer to the socket representing the TCP instance.\r
950\r
951 @retval EFI_SUCCESS The device path protocol was installed.\r
952 @retval other Failed to install the device path protocol.\r
953\r
954**/\r
955EFI_STATUS\r
956TcpInstallDevicePath (\r
957 IN SOCKET *Sock\r
958 )\r
959{\r
960 TCP_PROTO_DATA *TcpProto;\r
961 TCP_SERVICE_DATA *TcpService;\r
962 TCP_CB *Tcb;\r
963 IPv4_DEVICE_PATH Ip4DPathNode;\r
964 IPv6_DEVICE_PATH Ip6DPathNode;\r
965 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
966 EFI_STATUS Status;\r
967 TCP_PORTNO LocalPort;\r
968 TCP_PORTNO RemotePort;\r
969\r
970 TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved;\r
971 TcpService = TcpProto->TcpService;\r
972 Tcb = TcpProto->TcpPcb;\r
973\r
974 LocalPort = NTOHS (Tcb->LocalEnd.Port);\r
975 RemotePort = NTOHS (Tcb->RemoteEnd.Port);\r
976 if (Sock->IpVersion == IP_VERSION_4) {\r
977 NetLibCreateIPv4DPathNode (\r
978 &Ip4DPathNode,\r
979 TcpService->ControllerHandle,\r
980 Tcb->LocalEnd.Ip.Addr[0],\r
981 LocalPort,\r
982 Tcb->RemoteEnd.Ip.Addr[0],\r
983 RemotePort,\r
984 EFI_IP_PROTO_TCP,\r
985 Tcb->UseDefaultAddr\r
986 );\r
987\r
501793fa
RN
988 IP4_COPY_ADDRESS (&Ip4DPathNode.SubnetMask, &Tcb->SubnetMask);\r
989\r
a3bcde70
HT
990 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode;\r
991 } else {\r
992 NetLibCreateIPv6DPathNode (\r
993 &Ip6DPathNode,\r
994 TcpService->ControllerHandle,\r
995 &Tcb->LocalEnd.Ip.v6,\r
996 LocalPort,\r
997 &Tcb->RemoteEnd.Ip.v6,\r
998 RemotePort,\r
999 EFI_IP_PROTO_TCP\r
1000 );\r
1001\r
1002 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip6DPathNode;\r
1003 }\r
1004\r
1005 Sock->DevicePath = AppendDevicePathNode (Sock->ParentDevicePath, DevicePath);\r
1006 if (Sock->DevicePath == NULL) {\r
1007 return EFI_OUT_OF_RESOURCES;\r
1008 }\r
1009\r
1010 Status = gBS->InstallProtocolInterface (\r
1011 &Sock->SockHandle,\r
1012 &gEfiDevicePathProtocolGuid,\r
1013 EFI_NATIVE_INTERFACE,\r
1014 Sock->DevicePath\r
1015 );\r
1016 if (EFI_ERROR (Status)) {\r
1017 FreePool (Sock->DevicePath);\r
1018 Sock->DevicePath = NULL;\r
1019 }\r
1020\r
1021 return Status;\r
1022}\r
1023\r