]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/TcpDxe/TcpMisc.c
CorebootPayloadPkg: Use extra braces to prevent gcc compile fail
[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
d551cc64 5 Copyright (c) 2009 - 2014, 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
164 //\r
165 // Compute the effective SndMss per RFC1122\r
166 // section 4.2.2.6. If timestamp option is\r
167 // enabled, it will always occupy 12 bytes.\r
168 //\r
169 Tcb->SndMss -= TCP_OPTION_TS_ALIGNED_LEN;\r
170 }\r
171}\r
172\r
173/**\r
174 Check whether one IP address equals the other.\r
175\r
176 @param[in] Ip1 Pointer to IP address to be checked.\r
177 @param[in] Ip2 Pointer to IP address to be checked.\r
178 @param[in] Version IP_VERSION_4 indicates the IP address is an IPv4 address,\r
179 IP_VERSION_6 indicates the IP address is an IPv6 address.\r
180\r
181 @retval TRUE Ip1 equals Ip2.\r
182 @retval FALSE Ip1 does not equal Ip2.\r
183\r
184**/\r
185BOOLEAN\r
186TcpIsIpEqual (\r
187 IN EFI_IP_ADDRESS *Ip1,\r
188 IN EFI_IP_ADDRESS *Ip2,\r
189 IN UINT8 Version\r
190 )\r
191{\r
192 ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));\r
193\r
194 if (Version == IP_VERSION_4) {\r
195 return (BOOLEAN) (Ip1->Addr[0] == Ip2->Addr[0]);\r
196 } else {\r
197 return (BOOLEAN) EFI_IP6_EQUAL (&Ip1->v6, &Ip2->v6);\r
198 }\r
199}\r
200\r
201/**\r
202 Check whether one IP address is filled with ZERO.\r
203\r
204 @param[in] Ip Pointer to the IP address to be checked.\r
205 @param[in] Version IP_VERSION_4 indicates the IP address is an IPv4 address,\r
206 IP_VERSION_6 indicates the IP address is an IPv6 address.\r
207\r
208 @retval TRUE Ip is all zero address.\r
209 @retval FALSE Ip is not all zero address.\r
210\r
211**/\r
212BOOLEAN\r
213TcpIsIpZero (\r
214 IN EFI_IP_ADDRESS *Ip,\r
215 IN UINT8 Version\r
216 )\r
217{\r
218 ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6));\r
219\r
220 if (Version == IP_VERSION_4) {\r
221 return (BOOLEAN) (Ip->Addr[0] == 0);\r
222 } else {\r
223 return (BOOLEAN) ((Ip->Addr[0] == 0) && (Ip->Addr[1] == 0) &&\r
224 (Ip->Addr[2] == 0) && (Ip->Addr[3] == 0));\r
225 }\r
226}\r
227\r
228/**\r
229 Locate a listen TCB that matchs the Local and Remote.\r
230\r
231 @param[in] Local Pointer to the local (IP, Port).\r
232 @param[in] Remote Pointer to the remote (IP, Port).\r
233 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack,\r
234 IP_VERSION_6 indicates TCP is running on IP6 stack.\r
235\r
236 @return Pointer to the TCP_CB with the least number of wildcards,\r
237 if NULL no match is found.\r
238\r
239**/\r
240TCP_CB *\r
241TcpLocateListenTcb (\r
242 IN TCP_PEER *Local,\r
243 IN TCP_PEER *Remote,\r
244 IN UINT8 Version\r
245 )\r
246{\r
247 LIST_ENTRY *Entry;\r
248 TCP_CB *Node;\r
249 TCP_CB *Match;\r
250 INTN Last;\r
251 INTN Cur;\r
252\r
253 Last = 4;\r
254 Match = NULL;\r
255\r
256 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
257 Node = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
258\r
259 if ((Version != Node->Sk->IpVersion) ||\r
260 (Local->Port != Node->LocalEnd.Port) ||\r
261 !TCP_PEER_MATCH (Remote, &Node->RemoteEnd, Version) ||\r
262 !TCP_PEER_MATCH (Local, &Node->LocalEnd, Version)\r
263 ) {\r
264\r
265 continue;\r
266 }\r
267\r
268 //\r
269 // Compute the number of wildcard\r
270 //\r
271 Cur = 0;\r
272 if (TcpIsIpZero (&Node->RemoteEnd.Ip, Version)) {\r
273 Cur++;\r
274 }\r
275\r
276 if (Node->RemoteEnd.Port == 0) {\r
277 Cur++;\r
278 }\r
279\r
280 if (TcpIsIpZero (&Node->LocalEnd.Ip, Version)) {\r
281 Cur++;\r
282 }\r
283\r
284 if (Cur < Last) {\r
285 if (Cur == 0) {\r
286 return Node;\r
287 }\r
288\r
289 Last = Cur;\r
290 Match = Node;\r
291 }\r
292 }\r
293\r
294 return Match;\r
295}\r
296\r
297/**\r
298 Try to find one Tcb whose <Ip, Port> equals to <IN Addr, IN Port>.\r
299\r
300 @param[in] Addr Pointer to the IP address needs to match.\r
301 @param[in] Port The port number needs to match.\r
302 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack,\r
303 IP_VERSION_6 indicates TCP is running on IP6 stack.\r
304\r
305\r
306 @retval TRUE The Tcb which matches the <Addr Port> pair exists.\r
307 @retval FALSE Otherwise\r
308\r
309**/\r
310BOOLEAN\r
311TcpFindTcbByPeer (\r
312 IN EFI_IP_ADDRESS *Addr,\r
313 IN TCP_PORTNO Port,\r
314 IN UINT8 Version\r
315 )\r
316{\r
317 TCP_PORTNO LocalPort;\r
318 LIST_ENTRY *Entry;\r
319 TCP_CB *Tcb;\r
320\r
321 ASSERT ((Addr != NULL) && (Port != 0));\r
322\r
323 LocalPort = HTONS (Port);\r
324\r
325 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
326 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
327\r
328 if ((Version == Tcb->Sk->IpVersion) &&\r
329 TcpIsIpEqual (Addr, &Tcb->LocalEnd.Ip, Version) &&\r
330 (LocalPort == Tcb->LocalEnd.Port)\r
331 ) {\r
332\r
333 return TRUE;\r
334 }\r
335 }\r
336\r
337 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
338 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
339\r
340 if ((Version == Tcb->Sk->IpVersion) &&\r
341 TcpIsIpEqual (Addr, &Tcb->LocalEnd.Ip, Version) &&\r
342 (LocalPort == Tcb->LocalEnd.Port)\r
343 ) {\r
344\r
345 return TRUE;\r
346 }\r
347 }\r
348\r
349 return FALSE;\r
350}\r
351\r
352/**\r
353 Locate the TCP_CB related to the socket pair.\r
354\r
355 @param[in] LocalPort The local port number.\r
356 @param[in] LocalIp The local IP address.\r
357 @param[in] RemotePort The remote port number.\r
358 @param[in] RemoteIp The remote IP address.\r
359 @param[in] Version IP_VERSION_4 indicates TCP is running on IP4 stack,\r
360 IP_VERSION_6 indicates TCP is running on IP6 stack.\r
361 @param[in] Syn If TRUE, the listen sockets are searched.\r
362\r
363 @return Pointer to the related TCP_CB. If NULL, no match is found.\r
364\r
365**/\r
366TCP_CB *\r
367TcpLocateTcb (\r
368 IN TCP_PORTNO LocalPort,\r
369 IN EFI_IP_ADDRESS *LocalIp,\r
370 IN TCP_PORTNO RemotePort,\r
371 IN EFI_IP_ADDRESS *RemoteIp,\r
372 IN UINT8 Version,\r
373 IN BOOLEAN Syn\r
374 )\r
375{\r
376 TCP_PEER Local;\r
377 TCP_PEER Remote;\r
378 LIST_ENTRY *Entry;\r
379 TCP_CB *Tcb;\r
380\r
381 Local.Port = LocalPort;\r
382 Remote.Port = RemotePort;\r
383\r
384 CopyMem (&Local.Ip, LocalIp, sizeof (EFI_IP_ADDRESS));\r
385 CopyMem (&Remote.Ip, RemoteIp, sizeof (EFI_IP_ADDRESS));\r
386\r
387 //\r
388 // First check for exact match.\r
389 //\r
390 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
391 Tcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
392\r
393 if ((Version == Tcb->Sk->IpVersion) &&\r
394 TCP_PEER_EQUAL (&Remote, &Tcb->RemoteEnd, Version) &&\r
395 TCP_PEER_EQUAL (&Local, &Tcb->LocalEnd, Version)\r
396 ) {\r
397\r
398 RemoveEntryList (&Tcb->List);\r
399 InsertHeadList (&mTcpRunQue, &Tcb->List);\r
400\r
401 return Tcb;\r
402 }\r
403 }\r
404\r
405 //\r
406 // Only check the listen queue when the SYN flag is on.\r
407 //\r
408 if (Syn) {\r
409 return TcpLocateListenTcb (&Local, &Remote, Version);\r
410 }\r
411\r
412 return NULL;\r
413}\r
414\r
415/**\r
416 Insert a Tcb into the proper queue.\r
417\r
418 @param[in] Tcb Pointer to the TCP_CB to be inserted.\r
419\r
420 @retval 0 The Tcb was inserted successfully.\r
421 @retval -1 Error condition occurred.\r
422\r
423**/\r
424INTN\r
425TcpInsertTcb (\r
426 IN TCP_CB *Tcb\r
427 )\r
428{\r
429 LIST_ENTRY *Entry;\r
430 LIST_ENTRY *Head;\r
431 TCP_CB *Node;\r
a3bcde70
HT
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
a3bcde70
HT
469\r
470 return 0;\r
471}\r
472\r
473/**\r
474 Clone a TCP_CB from Tcb.\r
475\r
476 @param[in] Tcb Pointer to the TCP_CB to be cloned.\r
477\r
478 @return Pointer to the new cloned TCP_CB; if NULL, error condition occurred.\r
479\r
480**/\r
481TCP_CB *\r
482TcpCloneTcb (\r
483 IN TCP_CB *Tcb\r
484 )\r
485{\r
486 TCP_CB *Clone;\r
487\r
488 Clone = AllocateZeroPool (sizeof (TCP_CB));\r
489\r
490 if (Clone == NULL) {\r
491 return NULL;\r
492 }\r
493\r
494 CopyMem (Clone, Tcb, sizeof (TCP_CB));\r
495\r
496 //\r
497 // Increase the reference count of the shared IpInfo.\r
498 //\r
499 NET_GET_REF (Tcb->IpInfo);\r
500\r
501 InitializeListHead (&Clone->List);\r
502 InitializeListHead (&Clone->SndQue);\r
503 InitializeListHead (&Clone->RcvQue);\r
504\r
505 Clone->Sk = SockClone (Tcb->Sk);\r
506 if (Clone->Sk == NULL) {\r
507 DEBUG ((EFI_D_ERROR, "TcpCloneTcb: failed to clone a sock\n"));\r
508 FreePool (Clone);\r
509 return NULL;\r
510 }\r
511\r
512 ((TCP_PROTO_DATA *) (Clone->Sk->ProtoReserved))->TcpPcb = Clone;\r
513\r
514 return Clone;\r
515}\r
516\r
517/**\r
518 Compute an ISS to be used by a new connection.\r
519\r
520 @return The resulting ISS.\r
521\r
522**/\r
523TCP_SEQNO\r
524TcpGetIss (\r
525 VOID\r
526 )\r
527{\r
528 mTcpGlobalIss += TCP_ISS_INCREMENT_1;\r
529 return mTcpGlobalIss;\r
530}\r
531\r
532/**\r
533 Get the local mss.\r
534\r
535 @param[in] Sock Pointer to the socket to get mss.\r
536\r
537 @return The mss size.\r
538\r
539**/\r
540UINT16\r
541TcpGetRcvMss (\r
542 IN SOCKET *Sock\r
543 )\r
544{\r
545 EFI_IP4_MODE_DATA Ip4Mode;\r
546 EFI_IP6_MODE_DATA Ip6Mode;\r
547 EFI_IP4_PROTOCOL *Ip4;\r
548 EFI_IP6_PROTOCOL *Ip6;\r
549 TCP_PROTO_DATA *TcpProto;\r
550\r
551 ASSERT (Sock != NULL);\r
552\r
553 ZeroMem (&Ip4Mode, sizeof (EFI_IP4_MODE_DATA));\r
554 ZeroMem (&Ip6Mode, sizeof (EFI_IP6_MODE_DATA));\r
555\r
556 TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved;\r
557\r
558 if (Sock->IpVersion == IP_VERSION_4) {\r
559 Ip4 = TcpProto->TcpService->IpIo->Ip.Ip4;\r
560 ASSERT (Ip4 != NULL);\r
561 Ip4->GetModeData (Ip4, &Ip4Mode, NULL, NULL);\r
562\r
563 return (UINT16) (Ip4Mode.MaxPacketSize - sizeof (TCP_HEAD));\r
564 } else {\r
565 Ip6 = TcpProto->TcpService->IpIo->Ip.Ip6;\r
566 ASSERT (Ip6 != NULL);\r
567 Ip6->GetModeData (Ip6, &Ip6Mode, NULL, NULL);\r
568\r
569 return (UINT16) (Ip6Mode.MaxPacketSize - sizeof (TCP_HEAD));\r
570 }\r
571}\r
572\r
573/**\r
574 Set the Tcb's state.\r
575\r
576 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
577 @param[in] State The state to be set.\r
578\r
579**/\r
580VOID\r
581TcpSetState (\r
582 IN TCP_CB *Tcb,\r
583 IN UINT8 State\r
584 )\r
585{\r
586 ASSERT (Tcb->State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));\r
587 ASSERT (State < (sizeof (mTcpStateName) / sizeof (CHAR16 *)));\r
588\r
589 DEBUG (\r
590 (EFI_D_INFO,\r
591 "Tcb (%p) state %s --> %s\n",\r
592 Tcb,\r
593 mTcpStateName[Tcb->State],\r
594 mTcpStateName[State])\r
595 );\r
596\r
597 Tcb->State = State;\r
598\r
599 switch (State) {\r
600 case TCP_ESTABLISHED:\r
601\r
602 SockConnEstablished (Tcb->Sk);\r
603\r
604 if (Tcb->Parent != NULL) {\r
605 //\r
606 // A new connection is accepted by a listening socket. Install\r
607 // the device path.\r
608 //\r
609 TcpInstallDevicePath (Tcb->Sk);\r
610 }\r
611\r
612 break;\r
613\r
614 case TCP_CLOSED:\r
615\r
616 SockConnClosed (Tcb->Sk);\r
617\r
618 break;\r
619 default:\r
620 break;\r
621 }\r
622}\r
623\r
624/**\r
625 Compute the TCP segment's checksum.\r
626\r
627 @param[in] Nbuf Pointer to the buffer that contains the TCP segment.\r
628 @param[in] HeadSum The checksum value of the fixed part of pseudo header.\r
629\r
630 @return The checksum value.\r
631\r
632**/\r
633UINT16\r
634TcpChecksum (\r
635 IN NET_BUF *Nbuf,\r
636 IN UINT16 HeadSum\r
637 )\r
638{\r
639 UINT16 Checksum;\r
640\r
641 Checksum = NetbufChecksum (Nbuf);\r
642 Checksum = NetAddChecksum (Checksum, HeadSum);\r
643\r
644 Checksum = NetAddChecksum (\r
645 Checksum,\r
646 HTONS ((UINT16) Nbuf->TotalSize)\r
647 );\r
648\r
649 return (UINT16) (~Checksum);\r
650}\r
651\r
652/**\r
653 Translate the information from the head of the received TCP\r
654 segment Nbuf contents and fill it into a TCP_SEG structure.\r
655\r
656 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
657 @param[in, out] Nbuf Pointer to the buffer contains the TCP segment.\r
658\r
659 @return Pointer to the TCP_SEG that contains the translated TCP head information.\r
660\r
661**/\r
662TCP_SEG *\r
663TcpFormatNetbuf (\r
664 IN TCP_CB *Tcb,\r
665 IN OUT NET_BUF *Nbuf\r
666 )\r
667{\r
668 TCP_SEG *Seg;\r
669 TCP_HEAD *Head;\r
670\r
671 Seg = TCPSEG_NETBUF (Nbuf);\r
672 Head = (TCP_HEAD *) NetbufGetByte (Nbuf, 0, NULL);\r
673 ASSERT (Head != NULL);\r
674\r
675 Nbuf->Tcp = Head;\r
676\r
677 Seg->Seq = NTOHL (Head->Seq);\r
678 Seg->Ack = NTOHL (Head->Ack);\r
679 Seg->End = Seg->Seq + (Nbuf->TotalSize - (Head->HeadLen << 2));\r
680\r
681 Seg->Urg = NTOHS (Head->Urg);\r
682 Seg->Wnd = (NTOHS (Head->Wnd) << Tcb->SndWndScale);\r
683 Seg->Flag = Head->Flag;\r
684\r
685 //\r
686 // SYN and FIN flag occupy one sequence space each.\r
687 //\r
688 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {\r
689 //\r
690 // RFC requires that the initial window not be scaled.\r
691 //\r
692 Seg->Wnd = NTOHS (Head->Wnd);\r
693 Seg->End++;\r
694 }\r
695\r
696 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {\r
697 Seg->End++;\r
698 }\r
699\r
700 return Seg;\r
701}\r
702\r
703/**\r
704 Initialize an active connection.\r
705\r
706 @param[in, out] Tcb Pointer to the TCP_CB that wants to initiate a\r
707 connection.\r
708\r
709**/\r
710VOID\r
711TcpOnAppConnect (\r
712 IN OUT TCP_CB *Tcb\r
713 )\r
714{\r
715 TcpInitTcbLocal (Tcb);\r
716 TcpSetState (Tcb, TCP_SYN_SENT);\r
717\r
718 TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout);\r
719 TcpToSendData (Tcb, 1);\r
720}\r
721\r
722/**\r
723 Initiate the connection close procedure, called when\r
724 applications want to close the connection.\r
725\r
726 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
727\r
728**/\r
729VOID\r
730TcpOnAppClose (\r
731 IN OUT TCP_CB *Tcb\r
732 )\r
733{\r
734 ASSERT (Tcb != NULL);\r
735\r
736 if (!IsListEmpty (&Tcb->RcvQue) || GET_RCV_DATASIZE (Tcb->Sk) != 0) {\r
737\r
738 DEBUG (\r
739 (EFI_D_WARN,\r
740 "TcpOnAppClose: connection reset because data is lost for TCB %p\n",\r
741 Tcb)\r
742 );\r
743\r
744 TcpResetConnection (Tcb);\r
745 TcpClose (Tcb);\r
746 return;\r
747 }\r
748\r
749 switch (Tcb->State) {\r
750 case TCP_CLOSED:\r
751 case TCP_LISTEN:\r
752 case TCP_SYN_SENT:\r
753 TcpSetState (Tcb, TCP_CLOSED);\r
754 break;\r
755\r
756 case TCP_SYN_RCVD:\r
757 case TCP_ESTABLISHED:\r
758 TcpSetState (Tcb, TCP_FIN_WAIT_1);\r
759 break;\r
760\r
761 case TCP_CLOSE_WAIT:\r
762 TcpSetState (Tcb, TCP_LAST_ACK);\r
763 break;\r
764 default:\r
765 break;\r
766 }\r
767\r
768 TcpToSendData (Tcb, 1);\r
769}\r
770\r
771/**\r
772 Check whether the application's newly delivered data can be sent out.\r
773\r
774 @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance.\r
775\r
776 @retval 0 The data has been sent out successfully.\r
777 @retval -1 The Tcb is not in a state that data is permitted to\r
778 be sent out.\r
779\r
780**/\r
781INTN\r
782TcpOnAppSend (\r
783 IN OUT TCP_CB *Tcb\r
784 )\r
785{\r
786\r
787 switch (Tcb->State) {\r
788 case TCP_CLOSED:\r
789 return -1;\r
790\r
791 case TCP_LISTEN:\r
792 return -1;\r
793\r
794 case TCP_SYN_SENT:\r
795 case TCP_SYN_RCVD:\r
796 return 0;\r
797\r
798 case TCP_ESTABLISHED:\r
799 case TCP_CLOSE_WAIT:\r
800 TcpToSendData (Tcb, 0);\r
801 return 0;\r
802\r
803 case TCP_FIN_WAIT_1:\r
804 case TCP_FIN_WAIT_2:\r
805 case TCP_CLOSING:\r
806 case TCP_LAST_ACK:\r
807 case TCP_TIME_WAIT:\r
808 return -1;\r
809\r
810 default:\r
811 break;\r
812 }\r
813\r
814 return 0;\r
815}\r
816\r
817/**\r
818 Application has consumed some data. Check whether\r
819 to send a window update ack or a delayed ack.\r
820\r
821 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.\r
822\r
823**/\r
824VOID\r
825TcpOnAppConsume (\r
826 IN TCP_CB *Tcb\r
827 )\r
828{\r
829 UINT32 TcpOld;\r
830\r
831 switch (Tcb->State) {\r
832 case TCP_ESTABLISHED:\r
833 TcpOld = TcpRcvWinOld (Tcb);\r
834 if (TcpRcvWinNow (Tcb) > TcpOld) {\r
835\r
836 if (TcpOld < Tcb->RcvMss) {\r
837\r
838 DEBUG (\r
839 (EFI_D_INFO,\r
840 "TcpOnAppConsume: send a window update for a window closed Tcb %p\n",\r
841 Tcb)\r
842 );\r
843\r
844 TcpSendAck (Tcb);\r
845 } else if (Tcb->DelayedAck == 0) {\r
846\r
847 DEBUG (\r
848 (EFI_D_INFO,\r
849 "TcpOnAppConsume: scheduled a delayed ACK to update window for Tcb %p\n",\r
850 Tcb)\r
851 );\r
852\r
853 Tcb->DelayedAck = 1;\r
854 }\r
855 }\r
856\r
857 break;\r
858\r
859 default:\r
860 break;\r
861 }\r
862}\r
863\r
864/**\r
865 Abort the connection by sending a reset segment. Called\r
866 when the application wants to abort the connection.\r
867\r
868 @param[in] Tcb Pointer to the TCP_CB of the TCP instance.\r
869\r
870**/\r
871VOID\r
872TcpOnAppAbort (\r
873 IN TCP_CB *Tcb\r
874 )\r
875{\r
876 DEBUG (\r
877 (EFI_D_WARN,\r
878 "TcpOnAppAbort: connection reset issued by application for TCB %p\n",\r
879 Tcb)\r
880 );\r
881\r
882 switch (Tcb->State) {\r
883 case TCP_SYN_RCVD:\r
884 case TCP_ESTABLISHED:\r
885 case TCP_FIN_WAIT_1:\r
886 case TCP_FIN_WAIT_2:\r
887 case TCP_CLOSE_WAIT:\r
888 TcpResetConnection (Tcb);\r
889 break;\r
890 default:\r
891 break;\r
892 }\r
893\r
894 TcpSetState (Tcb, TCP_CLOSED);\r
895}\r
896\r
897/**\r
898 Reset the connection related with Tcb.\r
899\r
900 @param[in] Tcb Pointer to the TCP_CB of the connection to be reset.\r
901\r
902**/\r
903VOID\r
904TcpResetConnection (\r
905 IN TCP_CB *Tcb\r
906 )\r
907{\r
908 NET_BUF *Nbuf;\r
909 TCP_HEAD *Nhead;\r
910\r
911 Nbuf = NetbufAlloc (TCP_MAX_HEAD);\r
912\r
913 if (Nbuf == NULL) {\r
914 return ;\r
915 }\r
916\r
917 Nhead = (TCP_HEAD *) NetbufAllocSpace (\r
918 Nbuf,\r
919 sizeof (TCP_HEAD),\r
920 NET_BUF_TAIL\r
921 );\r
922\r
923 ASSERT (Nhead != NULL);\r
924\r
925 Nbuf->Tcp = Nhead;\r
926\r
927 Nhead->Flag = TCP_FLG_RST;\r
928 Nhead->Seq = HTONL (Tcb->SndNxt);\r
929 Nhead->Ack = HTONL (Tcb->RcvNxt);\r
930 Nhead->SrcPort = Tcb->LocalEnd.Port;\r
931 Nhead->DstPort = Tcb->RemoteEnd.Port;\r
932 Nhead->HeadLen = (UINT8) (sizeof (TCP_HEAD) >> 2);\r
933 Nhead->Res = 0;\r
934 Nhead->Wnd = HTONS (0xFFFF);\r
935 Nhead->Checksum = 0;\r
936 Nhead->Urg = 0;\r
937 Nhead->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);\r
938\r
939 TcpSendIpPacket (Tcb, Nbuf, &Tcb->LocalEnd.Ip, &Tcb->RemoteEnd.Ip, Tcb->Sk->IpVersion);\r
940\r
941 NetbufFree (Nbuf);\r
942}\r
943\r
a3bcde70
HT
944/**\r
945 Install the device path protocol on the TCP instance.\r
946\r
947 @param[in] Sock Pointer to the socket representing the TCP instance.\r
948\r
949 @retval EFI_SUCCESS The device path protocol was installed.\r
950 @retval other Failed to install the device path protocol.\r
951\r
952**/\r
953EFI_STATUS\r
954TcpInstallDevicePath (\r
955 IN SOCKET *Sock\r
956 )\r
957{\r
958 TCP_PROTO_DATA *TcpProto;\r
959 TCP_SERVICE_DATA *TcpService;\r
960 TCP_CB *Tcb;\r
961 IPv4_DEVICE_PATH Ip4DPathNode;\r
962 IPv6_DEVICE_PATH Ip6DPathNode;\r
963 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
964 EFI_STATUS Status;\r
965 TCP_PORTNO LocalPort;\r
966 TCP_PORTNO RemotePort;\r
967\r
968 TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved;\r
969 TcpService = TcpProto->TcpService;\r
970 Tcb = TcpProto->TcpPcb;\r
971\r
972 LocalPort = NTOHS (Tcb->LocalEnd.Port);\r
973 RemotePort = NTOHS (Tcb->RemoteEnd.Port);\r
974 if (Sock->IpVersion == IP_VERSION_4) {\r
975 NetLibCreateIPv4DPathNode (\r
976 &Ip4DPathNode,\r
977 TcpService->ControllerHandle,\r
978 Tcb->LocalEnd.Ip.Addr[0],\r
979 LocalPort,\r
980 Tcb->RemoteEnd.Ip.Addr[0],\r
981 RemotePort,\r
982 EFI_IP_PROTO_TCP,\r
983 Tcb->UseDefaultAddr\r
984 );\r
985\r
501793fa
RN
986 IP4_COPY_ADDRESS (&Ip4DPathNode.SubnetMask, &Tcb->SubnetMask);\r
987\r
a3bcde70
HT
988 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode;\r
989 } else {\r
990 NetLibCreateIPv6DPathNode (\r
991 &Ip6DPathNode,\r
992 TcpService->ControllerHandle,\r
993 &Tcb->LocalEnd.Ip.v6,\r
994 LocalPort,\r
995 &Tcb->RemoteEnd.Ip.v6,\r
996 RemotePort,\r
997 EFI_IP_PROTO_TCP\r
998 );\r
999\r
1000 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip6DPathNode;\r
1001 }\r
1002\r
1003 Sock->DevicePath = AppendDevicePathNode (Sock->ParentDevicePath, DevicePath);\r
1004 if (Sock->DevicePath == NULL) {\r
1005 return EFI_OUT_OF_RESOURCES;\r
1006 }\r
1007\r
1008 Status = gBS->InstallProtocolInterface (\r
1009 &Sock->SockHandle,\r
1010 &gEfiDevicePathProtocolGuid,\r
1011 EFI_NATIVE_INTERFACE,\r
1012 Sock->DevicePath\r
1013 );\r
1014 if (EFI_ERROR (Status)) {\r
1015 FreePool (Sock->DevicePath);\r
1016 Sock->DevicePath = NULL;\r
1017 }\r
1018\r
1019 return Status;\r
1020}\r
1021\r