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