]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/TcpDxe/TcpMisc.c
Fix a bug about the iSCSI DHCP dependency issue.
[mirror_edk2.git] / NetworkPkg / TcpDxe / TcpMisc.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 Misc support routines for TCP driver.\r
3\r
501793fa 4 Copyright (c) 2009 - 2011, 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
470 TcpSetVariableData (TcpProto->TcpService);\r
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
946/**\r
947 Set the Tcp variable data.\r
948\r
949 @param[in] TcpService Tcp service data.\r
950\r
951 @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the variable.\r
952 @retval other Set variable failed.\r
953\r
954**/\r
955EFI_STATUS\r
956TcpSetVariableData (\r
957 IN TCP_SERVICE_DATA *TcpService\r
958 )\r
959{\r
960 EFI_GUID *ServiceBindingGuid;\r
961 UINT32 NumConfiguredInstance;\r
962 LIST_ENTRY *Entry;\r
963 TCP_CB *TcpPcb;\r
964 TCP_PROTO_DATA *TcpProto;\r
965 UINTN VariableDataSize;\r
966 EFI_TCP4_VARIABLE_DATA *Tcp4VariableData;\r
967 EFI_TCP4_SERVICE_POINT *Tcp4ServicePoint;\r
968 EFI_TCP6_VARIABLE_DATA *Tcp6VariableData;\r
969 EFI_TCP6_SERVICE_POINT *Tcp6ServicePoint;\r
970 VOID *VariableData;\r
971 CHAR16 *NewMacString;\r
972 EFI_STATUS Status;\r
973\r
974 if (TcpService->IpVersion == IP_VERSION_4) {\r
975 ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
976 } else {\r
977 ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
978 }\r
979\r
980 NumConfiguredInstance = 0;\r
981 Tcp4VariableData = NULL;\r
982 Tcp6VariableData = NULL;\r
983\r
984 //\r
985 // Go through the running queue to count the instances.\r
986 //\r
987 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
988 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
989\r
990 TcpProto = (TCP_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
991\r
992 if (TcpProto->TcpService == TcpService) {\r
993 //\r
994 // This tcp instance belongs to the TcpService.\r
995 //\r
996 NumConfiguredInstance++;\r
997 }\r
998 }\r
999\r
1000 //\r
1001 // Go through the listening queue to count the instances.\r
1002 //\r
1003 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
1004 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
1005\r
1006 TcpProto = (TCP_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
1007\r
1008 if (TcpProto->TcpService == TcpService) {\r
1009 //\r
1010 // This tcp instance belongs to the TcpService.\r
1011 //\r
1012 NumConfiguredInstance++;\r
1013 }\r
1014 }\r
1015\r
1016 Tcp4ServicePoint = NULL;\r
1017 Tcp6ServicePoint = NULL;\r
1018\r
1019 //\r
1020 // Calculate the size of the Tcp4VariableData. As there may be no Tcp4 child,\r
1021 // we should add extra buffers for the service points only if the number of configured\r
1022 // children is more than one.\r
1023 //\r
1024 if (TcpService->IpVersion == IP_VERSION_4) {\r
1025 VariableDataSize = sizeof (EFI_TCP4_VARIABLE_DATA);\r
1026\r
1027 if (NumConfiguredInstance > 1) {\r
1028 VariableDataSize += sizeof (EFI_TCP4_SERVICE_POINT) * (NumConfiguredInstance - 1);\r
1029 }\r
1030\r
1031 Tcp4VariableData = AllocateZeroPool (VariableDataSize);\r
1032 if (Tcp4VariableData == NULL) {\r
1033 return EFI_OUT_OF_RESOURCES;\r
1034 }\r
1035\r
1036 Tcp4VariableData->DriverHandle = TcpService->DriverBindingHandle;\r
1037 Tcp4VariableData->ServiceCount = NumConfiguredInstance;\r
1038\r
1039 Tcp4ServicePoint = &Tcp4VariableData->Services[0];\r
1040 VariableData = Tcp4VariableData;\r
1041 } else {\r
1042 VariableDataSize = sizeof (EFI_TCP6_VARIABLE_DATA);\r
1043\r
1044 if (NumConfiguredInstance > 1) {\r
1045 VariableDataSize += sizeof (EFI_TCP6_SERVICE_POINT) * (NumConfiguredInstance - 1);\r
1046 }\r
1047\r
1048 Tcp6VariableData = AllocateZeroPool (VariableDataSize);\r
1049 if (Tcp6VariableData == NULL) {\r
1050 return EFI_OUT_OF_RESOURCES;\r
1051 }\r
1052\r
1053 Tcp6VariableData->DriverHandle = TcpService->DriverBindingHandle;\r
1054 Tcp6VariableData->ServiceCount = NumConfiguredInstance;\r
1055\r
1056 Tcp6ServicePoint = &Tcp6VariableData->Services[0];\r
1057 VariableData = Tcp6VariableData;\r
1058 }\r
1059\r
1060 //\r
1061 // Go through the running queue to fill the service points.\r
1062 //\r
1063 NET_LIST_FOR_EACH (Entry, &mTcpRunQue) {\r
1064 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
1065\r
1066 TcpProto = (TCP_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
1067\r
1068 if (TcpProto->TcpService == TcpService) {\r
1069 //\r
1070 // This tcp instance belongs to the TcpService.\r
1071 //\r
1072 if (TcpService->IpVersion == IP_VERSION_4) {\r
1073 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
1074 CopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
1075 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
1076 CopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
1077 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
1078\r
1079 Tcp4ServicePoint++;\r
1080 } else {\r
1081 Tcp6ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
1082 IP6_COPY_ADDRESS (&Tcp6ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip);\r
1083 Tcp6ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
1084 IP6_COPY_ADDRESS (&Tcp6ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip);\r
1085 Tcp6ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
1086\r
1087 Tcp6ServicePoint++;\r
1088 }\r
1089 }\r
1090 }\r
1091\r
1092 //\r
1093 // Go through the listening queue to fill the service points.\r
1094 //\r
1095 NET_LIST_FOR_EACH (Entry, &mTcpListenQue) {\r
1096 TcpPcb = NET_LIST_USER_STRUCT (Entry, TCP_CB, List);\r
1097\r
1098 TcpProto = (TCP_PROTO_DATA *) TcpPcb->Sk->ProtoReserved;\r
1099\r
1100 if (TcpProto->TcpService == TcpService) {\r
1101 //\r
1102 // This tcp instance belongs to the TcpService.\r
1103 //\r
1104 if (TcpService->IpVersion == IP_VERSION_4) {\r
1105 Tcp4ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
1106 CopyMem (&Tcp4ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
1107 Tcp4ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
1108 CopyMem (&Tcp4ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip, sizeof (EFI_IPv4_ADDRESS));\r
1109 Tcp4ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
1110\r
1111 Tcp4ServicePoint++;\r
1112 } else {\r
1113 Tcp6ServicePoint->InstanceHandle = TcpPcb->Sk->SockHandle;\r
1114 IP6_COPY_ADDRESS (&Tcp6ServicePoint->LocalAddress, &TcpPcb->LocalEnd.Ip);\r
1115 Tcp6ServicePoint->LocalPort = NTOHS (TcpPcb->LocalEnd.Port);\r
1116 IP6_COPY_ADDRESS (&Tcp6ServicePoint->RemoteAddress, &TcpPcb->RemoteEnd.Ip);\r
1117 Tcp6ServicePoint->RemotePort = NTOHS (TcpPcb->RemoteEnd.Port);\r
1118\r
1119 Tcp6ServicePoint++;\r
1120 }\r
1121 }\r
1122 }\r
1123\r
1124 //\r
1125 // Get the mac string.\r
1126 //\r
1127 Status = NetLibGetMacString (\r
1128 TcpService->ControllerHandle,\r
1129 TcpService->DriverBindingHandle,\r
1130 &NewMacString\r
1131 );\r
1132 if (EFI_ERROR (Status)) {\r
1133 goto ON_ERROR;\r
1134 }\r
1135\r
1136 if (TcpService->MacString != NULL) {\r
1137 //\r
1138 // The variable is set already. We're going to update it.\r
1139 //\r
1140 if (StrCmp (TcpService->MacString, NewMacString) != 0) {\r
1141 //\r
1142 // The mac address is changed. Delete the previous variable first.\r
1143 //\r
1144 gRT->SetVariable (\r
1145 TcpService->MacString,\r
1146 ServiceBindingGuid,\r
1147 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1148 0,\r
1149 NULL\r
1150 );\r
1151 }\r
1152\r
1153 FreePool (TcpService->MacString);\r
1154 }\r
1155\r
1156 TcpService->MacString = NewMacString;\r
1157\r
1158 Status = gRT->SetVariable (\r
1159 TcpService->MacString,\r
1160 ServiceBindingGuid,\r
1161 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1162 VariableDataSize,\r
1163 VariableData\r
1164 );\r
1165\r
1166ON_ERROR:\r
1167\r
1168 FreePool (VariableData);\r
1169\r
1170 return Status;\r
1171}\r
1172\r
1173/**\r
1174 Clear the variable and free the resource.\r
1175\r
1176 @param[in] TcpService Tcp service data.\r
1177\r
1178**/\r
1179VOID\r
1180TcpClearVariableData (\r
1181 IN TCP_SERVICE_DATA *TcpService\r
1182 )\r
1183{\r
1184 EFI_GUID *ServiceBindingGuid;\r
1185\r
1186 ASSERT (TcpService->MacString != NULL);\r
1187\r
1188 if (TcpService->IpVersion == IP_VERSION_4) {\r
1189 ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
1190 } else {\r
1191 ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
1192 }\r
1193\r
1194 gRT->SetVariable (\r
1195 TcpService->MacString,\r
1196 ServiceBindingGuid,\r
1197 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
1198 0,\r
1199 NULL\r
1200 );\r
1201\r
1202 FreePool (TcpService->MacString);\r
1203 TcpService->MacString = NULL;\r
1204}\r
1205\r
1206/**\r
1207 Install the device path protocol on the TCP instance.\r
1208\r
1209 @param[in] Sock Pointer to the socket representing the TCP instance.\r
1210\r
1211 @retval EFI_SUCCESS The device path protocol was installed.\r
1212 @retval other Failed to install the device path protocol.\r
1213\r
1214**/\r
1215EFI_STATUS\r
1216TcpInstallDevicePath (\r
1217 IN SOCKET *Sock\r
1218 )\r
1219{\r
1220 TCP_PROTO_DATA *TcpProto;\r
1221 TCP_SERVICE_DATA *TcpService;\r
1222 TCP_CB *Tcb;\r
1223 IPv4_DEVICE_PATH Ip4DPathNode;\r
1224 IPv6_DEVICE_PATH Ip6DPathNode;\r
1225 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1226 EFI_STATUS Status;\r
1227 TCP_PORTNO LocalPort;\r
1228 TCP_PORTNO RemotePort;\r
1229\r
1230 TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved;\r
1231 TcpService = TcpProto->TcpService;\r
1232 Tcb = TcpProto->TcpPcb;\r
1233\r
1234 LocalPort = NTOHS (Tcb->LocalEnd.Port);\r
1235 RemotePort = NTOHS (Tcb->RemoteEnd.Port);\r
1236 if (Sock->IpVersion == IP_VERSION_4) {\r
1237 NetLibCreateIPv4DPathNode (\r
1238 &Ip4DPathNode,\r
1239 TcpService->ControllerHandle,\r
1240 Tcb->LocalEnd.Ip.Addr[0],\r
1241 LocalPort,\r
1242 Tcb->RemoteEnd.Ip.Addr[0],\r
1243 RemotePort,\r
1244 EFI_IP_PROTO_TCP,\r
1245 Tcb->UseDefaultAddr\r
1246 );\r
1247\r
501793fa
RN
1248 IP4_COPY_ADDRESS (&Ip4DPathNode.SubnetMask, &Tcb->SubnetMask);\r
1249\r
a3bcde70
HT
1250 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip4DPathNode;\r
1251 } else {\r
1252 NetLibCreateIPv6DPathNode (\r
1253 &Ip6DPathNode,\r
1254 TcpService->ControllerHandle,\r
1255 &Tcb->LocalEnd.Ip.v6,\r
1256 LocalPort,\r
1257 &Tcb->RemoteEnd.Ip.v6,\r
1258 RemotePort,\r
1259 EFI_IP_PROTO_TCP\r
1260 );\r
1261\r
1262 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &Ip6DPathNode;\r
1263 }\r
1264\r
1265 Sock->DevicePath = AppendDevicePathNode (Sock->ParentDevicePath, DevicePath);\r
1266 if (Sock->DevicePath == NULL) {\r
1267 return EFI_OUT_OF_RESOURCES;\r
1268 }\r
1269\r
1270 Status = gBS->InstallProtocolInterface (\r
1271 &Sock->SockHandle,\r
1272 &gEfiDevicePathProtocolGuid,\r
1273 EFI_NATIVE_INTERFACE,\r
1274 Sock->DevicePath\r
1275 );\r
1276 if (EFI_ERROR (Status)) {\r
1277 FreePool (Sock->DevicePath);\r
1278 Sock->DevicePath = NULL;\r
1279 }\r
1280\r
1281 return Status;\r
1282}\r
1283\r