]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c
Fix potential memory access violation
[mirror_edk2.git] / MdeModulePkg / Library / DxeTcpIoLib / DxeTcpIoLib.c
CommitLineData
4bad9ada 1/** @file\r
2 This library is used to share code between UEFI network stack modules.\r
3 It provides the helper routines to access TCP service.\r
4\r
5Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at<BR>\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include <Uefi.h>\r
17\r
18#include <Library/TcpIoLib.h>\r
19#include <Library/BaseLib.h>\r
20#include <Library/DebugLib.h>\r
21#include <Library/UefiBootServicesTableLib.h>\r
22#include <Library/MemoryAllocationLib.h>\r
23#include <Library/BaseMemoryLib.h>\r
24\r
25/**
26 The common notify function associated with various TcpIo events. \r
27
28 @param[in] Event The event signaled.
29 @param[in] Context The context.
30
31**/
32VOID
33EFIAPI
34TcpIoCommonNotify (\r
35 IN EFI_EVENT Event,
36 IN VOID *Context
37 )
38{\r
39 if ((Event == NULL) || (Context == NULL)) {\r
40 return ;\r
41 }\r
42\r
43 *((BOOLEAN *) Context) = TRUE;
44}\r
45\r
46/**
47 The internal function for delay configuring TCP6 when IP6 driver is still in DAD.\r
48
49 @param[in] Tcp6 The EFI_TCP6_PROTOCOL protocol instance.
50 @param[in] Tcp6ConfigData The Tcp6 configuration data.
51
52 @retval EFI_SUCCESS The operational settings successfully
53 completed.
54 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
55 @retval Others Failed to finish the operation.\r
56\r
57**/
58EFI_STATUS
59TcpIoGetMapping (\r
60 IN EFI_TCP6_PROTOCOL *Tcp6,
61 IN EFI_TCP6_CONFIG_DATA *Tcp6ConfigData
62 )
63{
64 EFI_STATUS Status;
65 EFI_EVENT Event;
66\r
67 if ((Tcp6 == NULL) || (Tcp6ConfigData == NULL)) {\r
68 return EFI_INVALID_PARAMETER;\r
69 }\r
70\r
71 Event = NULL;
72 Status = gBS->CreateEvent (
73 EVT_TIMER,
74 TPL_CALLBACK,
75 NULL,
76 NULL,
77 &Event
78 );
79 if (EFI_ERROR (Status)) {
80 goto ON_EXIT;
81 }
82
83 Status = gBS->SetTimer (
84 Event,
85 TimerRelative,
86 TCP_GET_MAPPING_TIMEOUT\r
87 );
88
89 if (EFI_ERROR (Status)) {
90 goto ON_EXIT;
91 }
92
93 while (EFI_ERROR (gBS->CheckEvent (Event))) {
94
95 Tcp6->Poll (Tcp6);
96
97 Status = Tcp6->Configure (Tcp6, Tcp6ConfigData);
98
99 if (!EFI_ERROR (Status)) {
100 break;
101 }
102 }
103
104ON_EXIT:
105
106 if (Event != NULL) {
107 gBS->CloseEvent (Event);
108 }
109
110 return Status;
111}\r
112\r
113/**\r
114 Create a TCP socket with the specified configuration data. \r
115\r
116 @param[in] Image The handle of the driver image.\r
117 @param[in] Controller The handle of the controller.\r
118 @param[in] TcpVersion The version of Tcp, TCP_VERSION_4 or TCP_VERSION_6.\r
119 @param[in] ConfigData The Tcp configuration data.\r
120 @param[out] TcpIo The TcpIo.\r
121 \r
122 @retval EFI_SUCCESS The TCP socket is created and configured.\r
123 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
124 @retval EFI_UNSUPPORTED One or more of the control options are not
125 supported in the implementation.\r
126 @retval Others Failed to create the TCP socket or configure it.\r
127\r
128**/\r
129EFI_STATUS\r
130EFIAPI\r
131TcpIoCreateSocket (\r
132 IN EFI_HANDLE Image,\r
133 IN EFI_HANDLE Controller,\r
134 IN UINT8 TcpVersion,\r
135 IN TCP_IO_CONFIG_DATA *ConfigData,\r
136 OUT TCP_IO *TcpIo\r
137 )\r
138{\r
139 EFI_STATUS Status;\r
140 EFI_EVENT Event;\r
141 EFI_GUID *ServiceBindingGuid;\r
142 EFI_GUID *ProtocolGuid;\r
143 VOID **Interface;\r
144 EFI_TCP4_OPTION ControlOption;\r
145 EFI_TCP4_CONFIG_DATA Tcp4ConfigData;\r
146 EFI_TCP4_ACCESS_POINT *AccessPoint4;\r
147 EFI_TCP4_PROTOCOL *Tcp4;\r
148 EFI_TCP6_CONFIG_DATA Tcp6ConfigData;\r
149 EFI_TCP6_ACCESS_POINT *AccessPoint6;\r
150 EFI_TCP6_PROTOCOL *Tcp6;\r
151\r
152 if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (TcpIo == NULL)) {\r
153 return EFI_INVALID_PARAMETER;\r
154 }\r
155\r
156 Tcp4 = NULL;\r
157 Tcp6 = NULL;\r
158\r
159 ZeroMem (TcpIo, sizeof (TCP_IO));\r
160\r
161 if (TcpVersion == TCP_VERSION_4) {\r
162 ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
163 ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
164 Interface = (VOID **) (&TcpIo->Tcp.Tcp4);\r
165 } else if (TcpVersion == TCP_VERSION_6) {\r
166 ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
167 ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
168 Interface = (VOID **) (&TcpIo->Tcp.Tcp6);\r
169 } else {\r
170 return EFI_UNSUPPORTED;\r
171 }\r
172\r
173 TcpIo->TcpVersion = TcpVersion;\r
174\r
175 //\r
176 // Create the TCP child instance and get the TCP protocol.\r
177 // \r
178 Status = NetLibCreateServiceChild (
179 Controller,
180 Image,
181 ServiceBindingGuid,\r
182 &TcpIo->Handle\r
183 );
184 if (EFI_ERROR (Status)) {
185 return Status;
186 }
187
188 Status = gBS->OpenProtocol (
189 TcpIo->Handle,\r
190 ProtocolGuid,\r
191 Interface,\r
192 Image,
193 Controller,
194 EFI_OPEN_PROTOCOL_BY_DRIVER
195 );
196 if (EFI_ERROR (Status) || (*Interface == NULL)) {\r
197 goto ON_ERROR;
198 }\r
199\r
200 if (TcpVersion == TCP_VERSION_4) {\r
201 Tcp4 = TcpIo->Tcp.Tcp4;\r
202 } else {\r
203 Tcp6 = TcpIo->Tcp.Tcp6;\r
204 }\r
205
206 TcpIo->Image = Image;\r
207 TcpIo->Controller = Controller;\r
208
209 //
210 // Set the configuration parameters.
211 //
212 ControlOption.ReceiveBufferSize = 0x200000;
213 ControlOption.SendBufferSize = 0x200000;
214 ControlOption.MaxSynBackLog = 0;
215 ControlOption.ConnectionTimeout = 0;
216 ControlOption.DataRetries = 6;
217 ControlOption.FinTimeout = 0;
218 ControlOption.TimeWaitTimeout = 0;
219 ControlOption.KeepAliveProbes = 4;
220 ControlOption.KeepAliveTime = 0;
221 ControlOption.KeepAliveInterval = 0;
222 ControlOption.EnableNagle = FALSE;
223 ControlOption.EnableTimeStamp = FALSE;
224 ControlOption.EnableWindowScaling = TRUE;
225 ControlOption.EnableSelectiveAck = FALSE;
226 ControlOption.EnablePathMtuDiscovery = FALSE;
227\r
228 if (TcpVersion == TCP_VERSION_4) {\r
229 Tcp4ConfigData.TypeOfService = 8;\r
230 Tcp4ConfigData.TimeToLive = 255;\r
231 Tcp4ConfigData.ControlOption = &ControlOption;\r
232\r
233 AccessPoint4 = &Tcp4ConfigData.AccessPoint;\r
234\r
235 ZeroMem (AccessPoint4, sizeof (EFI_TCP4_ACCESS_POINT));\r
236 AccessPoint4->StationPort = ConfigData->Tcp4IoConfigData.StationPort;\r
237 AccessPoint4->RemotePort = ConfigData->Tcp4IoConfigData.RemotePort;\r
238 AccessPoint4->ActiveFlag = ConfigData->Tcp4IoConfigData.ActiveFlag;\r
239\r
240 CopyMem (\r
241 &AccessPoint4->StationAddress,\r
242 &ConfigData->Tcp4IoConfigData.LocalIp,\r
243 sizeof (EFI_IPv4_ADDRESS)\r
244 );\r
245 CopyMem (\r
246 &AccessPoint4->SubnetMask,\r
247 &ConfigData->Tcp4IoConfigData.SubnetMask,\r
248 sizeof (EFI_IPv4_ADDRESS)\r
249 );\r
250 CopyMem (\r
251 &AccessPoint4->RemoteAddress,\r
252 &ConfigData->Tcp4IoConfigData.RemoteIp,\r
253 sizeof (EFI_IPv4_ADDRESS)\r
254 );\r
255\r
256 ASSERT (Tcp4 != NULL);\r
257\r
258 //\r
259 // Configure the TCP4 protocol.\r
260 //\r
261 Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData);\r
262 if (EFI_ERROR (Status)) {\r
263 goto ON_ERROR;\r
264 }\r
265\r
266 if (!EFI_IP4_EQUAL (&ConfigData->Tcp4IoConfigData.Gateway, &mZeroIp4Addr)) {\r
267 //\r
268 // The gateway is not zero. Add the default route manually.\r
269 //\r
270 Status = Tcp4->Routes (\r
271 Tcp4,\r
272 FALSE,\r
273 &mZeroIp4Addr,\r
274 &mZeroIp4Addr,\r
275 &ConfigData->Tcp4IoConfigData.Gateway\r
276 );\r
277 if (EFI_ERROR (Status)) {\r
278 goto ON_ERROR;\r
279 }\r
280 }\r
281 } else {\r
282 Tcp6ConfigData.TrafficClass = 0;\r
283 Tcp6ConfigData.HopLimit = 255;\r
284 Tcp6ConfigData.ControlOption = (EFI_TCP6_OPTION *) &ControlOption;\r
285\r
286 AccessPoint6 = &Tcp6ConfigData.AccessPoint;\r
287\r
288 ZeroMem (AccessPoint6, sizeof (EFI_TCP6_ACCESS_POINT));\r
289 AccessPoint6->StationPort = ConfigData->Tcp6IoConfigData.StationPort;\r
290 AccessPoint6->RemotePort = ConfigData->Tcp6IoConfigData.RemotePort;\r
291 AccessPoint6->ActiveFlag = ConfigData->Tcp6IoConfigData.ActiveFlag;\r
292\r
293 IP6_COPY_ADDRESS (&AccessPoint6->RemoteAddress, &ConfigData->Tcp6IoConfigData.RemoteIp);\r
294\r
295\r
296 ASSERT (Tcp6 != NULL);\r
297 //\r
298 // Configure the TCP6 protocol.\r
299 //\r
300 Status = Tcp6->Configure (Tcp6, &Tcp6ConfigData);\r
301 if (Status == EFI_NO_MAPPING) {\r
302 Status = TcpIoGetMapping (Tcp6, &Tcp6ConfigData);\r
303 }\r
304\r
305 if (EFI_ERROR (Status)) {\r
306 goto ON_ERROR;\r
307 }\r
308 }\r
309\r
310 //
311 // Create events for variuos asynchronous operations.
312 //\r
313 Status = gBS->CreateEvent (\r
314 EVT_NOTIFY_SIGNAL,
315 TPL_NOTIFY,
316 TcpIoCommonNotify,\r
317 &TcpIo->IsConnDone,\r
318 &Event\r
319 );
320 if (EFI_ERROR (Status)) {
321 goto ON_ERROR;
322 }\r
323\r
324 TcpIo->ConnToken.Tcp4Token.CompletionToken.Event = Event;\r
325\r
326 Status = gBS->CreateEvent (
327 EVT_NOTIFY_SIGNAL,
328 TPL_NOTIFY,
329 TcpIoCommonNotify,\r
330 &TcpIo->IsListenDone,\r
331 &Event\r
332 );
333 if (EFI_ERROR (Status)) {
334 goto ON_ERROR;
335 }\r
336\r
337 TcpIo->ListenToken.Tcp4Token.CompletionToken.Event = Event;\r
338\r
339 Status = gBS->CreateEvent (
340 EVT_NOTIFY_SIGNAL,
341 TPL_NOTIFY,
342 TcpIoCommonNotify,\r
343 &TcpIo->IsTxDone,\r
344 &Event\r
345 );
346 if (EFI_ERROR (Status)) {
347 goto ON_ERROR;
348 }
349\r
350 TcpIo->TxToken.Tcp4Token.CompletionToken.Event = Event;\r
351\r
352\r
353 Status = gBS->CreateEvent (
354 EVT_NOTIFY_SIGNAL,
355 TPL_NOTIFY,
356 TcpIoCommonNotify,\r
357 &TcpIo->IsRxDone,\r
358 &Event\r
359 );
360 if (EFI_ERROR (Status)) {
361 goto ON_ERROR;
362 }
363\r
364 TcpIo->RxToken.Tcp4Token.CompletionToken.Event = Event;\r
365\r
366 Status = gBS->CreateEvent (
367 EVT_NOTIFY_SIGNAL,
368 TPL_NOTIFY,
369 TcpIoCommonNotify,\r
370 &TcpIo->IsCloseDone,\r
371 &Event\r
372 );
373 if (EFI_ERROR (Status)) {
374 goto ON_ERROR;
375 }
376\r
377 TcpIo->CloseToken.Tcp4Token.CompletionToken.Event = Event;\r
378\r
379\r
380 return EFI_SUCCESS;\r
381
382ON_ERROR:
383\r
384 TcpIoDestroySocket (TcpIo);\r
385
386 return Status;\r
387}\r
388 \r
389/**\r
390 Destroy the socket. \r
391\r
392 @param[in] TcpIo The TcpIo which wraps the socket to be destroyed.\r
393\r
394**/\r
395VOID\r
396EFIAPI\r
397TcpIoDestroySocket (\r
398 IN TCP_IO *TcpIo\r
399 )\r
400{\r
401 EFI_EVENT Event;\r
402 EFI_TCP4_PROTOCOL *Tcp4;\r
403 EFI_TCP6_PROTOCOL *Tcp6;\r
404 UINT8 TcpVersion;\r
405 EFI_GUID *ServiceBindingGuid;\r
406 EFI_GUID *ProtocolGuid;\r
407 EFI_HANDLE ChildHandle;\r
408\r
409 if (TcpIo == NULL) {\r
410 return ;\r
411 }\r
412\r
413 TcpVersion = TcpIo->TcpVersion;\r
414\r
415 if ((TcpVersion != TCP_VERSION_4) && (TcpVersion != TCP_VERSION_6)) {\r
416 return ;\r
417 }\r
418\r
419 Event = TcpIo->ConnToken.Tcp4Token.CompletionToken.Event;\r
420\r
421 if (Event != NULL) {\r
422 gBS->CloseEvent (Event);\r
423 }\r
424\r
425 Event = TcpIo->ListenToken.Tcp4Token.CompletionToken.Event;\r
426\r
427 if (Event != NULL) {\r
428 gBS->CloseEvent (Event);\r
429 }\r
430\r
431 Event = TcpIo->TxToken.Tcp4Token.CompletionToken.Event;\r
432\r
433 if (Event != NULL) {\r
434 gBS->CloseEvent (Event);\r
435 }\r
436\r
437 Event = TcpIo->RxToken.Tcp4Token.CompletionToken.Event;\r
438\r
439 if (Event != NULL) {\r
440 gBS->CloseEvent (Event);\r
441 }\r
442\r
443 Event = TcpIo->CloseToken.Tcp4Token.CompletionToken.Event;\r
444\r
445 if (Event != NULL) {\r
446 gBS->CloseEvent (Event);\r
447 }\r
448\r
449 Tcp4 = NULL;\r
450 Tcp6 = NULL;\r
451\r
452\r
453 if (TcpVersion == TCP_VERSION_4) {\r
454 ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
455 ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
456 Tcp4 = TcpIo->Tcp.Tcp4;\r
457 if (Tcp4 != NULL) {\r
458 Tcp4->Configure (Tcp4, NULL);\r
459 }\r
460 } else {\r
461 ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
462 ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
463 Tcp6 = TcpIo->Tcp.Tcp6;\r
464 if (Tcp6 != NULL) {\r
465 Tcp6->Configure (Tcp6, NULL);\r
466 }\r
467 }\r
468\r
469 if ((Tcp4 != NULL) || (Tcp6 != NULL)) {\r
470\r
471 gBS->CloseProtocol (
472 TcpIo->Handle,\r
473 ProtocolGuid,\r
474 TcpIo->Image,\r
475 TcpIo->Controller\r
476 );\r
477 }\r
478\r
479 ChildHandle = NULL;\r
480\r
481 if (TcpIo->IsListenDone) {\r
482 if (TcpVersion == TCP_VERSION_4) {\r
483 Tcp4 = TcpIo->NewTcp.Tcp4;\r
484 if (Tcp4 != NULL) {\r
485 Tcp4->Configure (Tcp4, NULL);\r
486 ChildHandle = TcpIo->ListenToken.Tcp4Token.NewChildHandle;\r
487 }\r
488 } else {\r
489 Tcp6 = TcpIo->NewTcp.Tcp6;\r
490 if (Tcp6 != NULL) {\r
491 Tcp6->Configure (Tcp6, NULL);\r
492 ChildHandle = TcpIo->ListenToken.Tcp6Token.NewChildHandle;\r
493 }\r
494 }\r
495\r
496 if (ChildHandle != NULL) {\r
497\r
498 gBS->CloseProtocol (\r
499 ChildHandle,\r
500 ProtocolGuid,\r
501 TcpIo->Image,\r
502 TcpIo->Controller\r
503 );\r
504 }\r
505 }\r
506\r
507 NetLibDestroyServiceChild (
508 TcpIo->Controller,\r
509 TcpIo->Image,\r
510 ServiceBindingGuid,\r
511 TcpIo->Handle\r
512 );\r
513}\r
514\r
515/**\r
516 Connect to the other endpoint of the TCP socket.\r
517\r
518 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.\r
519 @param[in] Timeout The time to wait for connection done.\r
520 \r
521 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket\r
522 successfully.\r
523 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the\r
524 TCP socket in the specified time period.\r
525 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
526 @retval EFI_UNSUPPORTED One or more of the control options are not\r
527 supported in the implementation.\r
528 @retval Others Other errors as indicated.\r
529\r
530**/\r
531EFI_STATUS\r
532EFIAPI\r
533TcpIoConnect (\r
534 IN OUT TCP_IO *TcpIo,\r
535 IN EFI_EVENT Timeout\r
536 )\r
537{\r
538 EFI_TCP4_PROTOCOL *Tcp4;\r
539 EFI_TCP6_PROTOCOL *Tcp6;\r
540 EFI_STATUS Status;\r
541\r
542 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {\r
543 return EFI_INVALID_PARAMETER;\r
544 }\r
545\r
546 TcpIo->IsConnDone = FALSE;\r
547\r
548 Tcp4 = NULL;\r
549 Tcp6 = NULL;\r
550\r
551 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
552 Tcp4 = TcpIo->Tcp.Tcp4;\r
553 Status = Tcp4->Connect (Tcp4, &TcpIo->ConnToken.Tcp4Token);\r
554 } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
555 Tcp6 = TcpIo->Tcp.Tcp6;\r
556 Status = Tcp6->Connect (Tcp6, &TcpIo->ConnToken.Tcp6Token);\r
557 } else {\r
558 return EFI_UNSUPPORTED;\r
559 }\r
560\r
561 if (EFI_ERROR (Status)) {
562 return Status;
563 }
564
565 while (!TcpIo->IsConnDone && EFI_ERROR (gBS->CheckEvent (Timeout))) {\r
566 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
567 Tcp4->Poll (Tcp4);\r
568 } else {\r
569 Tcp6->Poll (Tcp6);\r
570 }\r
571 }
572
573 if (!TcpIo->IsConnDone) {\r
574 Status = EFI_TIMEOUT;
575 } else {\r
576 Status = TcpIo->ConnToken.Tcp4Token.CompletionToken.Status;\r
577 }\r
578
579 return Status;\r
580}\r
581\r
582/**\r
583 Accept the incomding request from the other endpoint of the TCP socket.\r
584\r
585 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.\r
586 @param[in] Timeout The time to wait for connection done.\r
587\r
588 \r
589 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket\r
590 successfully.\r
591 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
592 @retval EFI_UNSUPPORTED One or more of the control options are not\r
593 supported in the implementation.\r
594\r
595 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the\r
596 TCP socket in the specified time period. \r
597 @retval Others Other errors as indicated.\r
598\r
599**/\r
600EFI_STATUS\r
601EFIAPI\r
602TcpIoAccept (\r
603 IN OUT TCP_IO *TcpIo,\r
604 IN EFI_EVENT Timeout\r
605 )\r
606{\r
607 EFI_STATUS Status;\r
608 EFI_GUID *ProtocolGuid;\r
609 EFI_TCP4_PROTOCOL *Tcp4;\r
610 EFI_TCP6_PROTOCOL *Tcp6;\r
611\r
612 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {\r
613 return EFI_INVALID_PARAMETER;\r
614 }\r
615\r
616 TcpIo->IsListenDone = FALSE;\r
617\r
618 Tcp4 = NULL;\r
619 Tcp6 = NULL;\r
620\r
621 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
622 Tcp4 = TcpIo->Tcp.Tcp4;\r
623 Status = Tcp4->Accept (Tcp4, &TcpIo->ListenToken.Tcp4Token);\r
624 } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
625 Tcp6 = TcpIo->Tcp.Tcp6;\r
626 Status = Tcp6->Accept (Tcp6, &TcpIo->ListenToken.Tcp6Token);\r
627 } else {\r
628 return EFI_UNSUPPORTED;\r
629 }\r
630\r
631 if (EFI_ERROR (Status)) {
632 return Status;
633 }\r
634\r
635 while (!TcpIo->IsListenDone && EFI_ERROR (gBS->CheckEvent (Timeout))) {\r
636 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
637 Tcp4->Poll (Tcp4);\r
638 } else {\r
639 Tcp6->Poll (Tcp6);\r
640 }\r
641 }
642\r
643 if (!TcpIo->IsListenDone) {\r
644 Status = EFI_TIMEOUT;
645 } else {\r
646 Status = TcpIo->ListenToken.Tcp4Token.CompletionToken.Status;\r
647 }\r
648\r
649 //
650 // The new TCP instance handle created for the established connection is
651 // in ListenToken.
652 //
653 if (!EFI_ERROR (Status)) {\r
654 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
655 ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
656 } else {\r
657 ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
658 }\r
659 \r
660 Status = gBS->OpenProtocol (
661 TcpIo->ListenToken.Tcp4Token.NewChildHandle,\r
662 ProtocolGuid,\r
663 (VOID **) (&TcpIo->NewTcp.Tcp4),\r
664 TcpIo->Image,\r
665 TcpIo->Controller,\r
666 EFI_OPEN_PROTOCOL_BY_DRIVER
667 );
668
669 }
670\r
671 return Status;\r
672}\r
673\r
674/**\r
675 Reset the socket.\r
676\r
677 @param[in, out] TcpIo The TcpIo wrapping the TCP socket.\r
678\r
679**/\r
680VOID\r
681EFIAPI\r
682TcpIoReset (\r
683 IN OUT TCP_IO *TcpIo\r
684 )\r
685{\r
686 EFI_TCP4_PROTOCOL *Tcp4;\r
687 EFI_TCP6_PROTOCOL *Tcp6;\r
688 EFI_STATUS Status;\r
689\r
690 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {\r
691 return ;\r
692 }\r
693\r
694 TcpIo->IsCloseDone = FALSE;\r
695 Tcp4 = NULL;\r
696 Tcp6 = NULL;\r
697\r
698 if (TcpIo->TcpVersion == TCP_VERSION_4) { \r
699 TcpIo->CloseToken.Tcp4Token.AbortOnClose = TRUE;\r
700 Tcp4 = TcpIo->Tcp.Tcp4;\r
701 Status = Tcp4->Close (Tcp4, &TcpIo->CloseToken.Tcp4Token);\r
702 } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
703 TcpIo->CloseToken.Tcp6Token.AbortOnClose = TRUE;\r
704 Tcp6 = TcpIo->Tcp.Tcp6;\r
705 Status = Tcp6->Close (Tcp6, &TcpIo->CloseToken.Tcp6Token);\r
706 } else {\r
707 return ;\r
708 }\r
709\r
710 if (EFI_ERROR (Status)) {
711 return ;
712 }
713
714 while (!TcpIo->IsCloseDone) {\r
715 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
716 Tcp4->Poll (Tcp4);\r
717 } else {\r
718 Tcp6->Poll (Tcp6);\r
719 }\r
720 }\r
721}\r
722\r
723 \r
724/**\r
725 Transmit the Packet to the other endpoint of the socket.\r
726\r
727 @param[in] TcpIo The TcpIo wrapping the TCP socket.\r
728 @param[in] Packet The packet to transmit.\r
729 \r
730 @retval EFI_SUCCESS The packet is trasmitted.\r
731 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
732 @retval EFI_UNSUPPORTED One or more of the control options are not\r
733 supported in the implementation.\r
734 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
735 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
736 @retval Others Other errors as indicated.\r
737\r
738**/\r
739EFI_STATUS\r
740EFIAPI\r
741TcpIoTransmit (\r
742 IN TCP_IO *TcpIo,\r
743 IN NET_BUF *Packet\r
744 )\r
745{\r
746 EFI_STATUS Status;\r
747 VOID *Data;\r
748 EFI_TCP4_PROTOCOL *Tcp4;\r
749 EFI_TCP6_PROTOCOL *Tcp6;\r
750 UINTN Size;\r
751\r
752 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) {\r
753 return EFI_INVALID_PARAMETER;\r
754 }\r
755\r
756 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
757\r
758 Size = sizeof (EFI_TCP4_TRANSMIT_DATA) + \r
759 (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);\r
760 } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
761 Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +\r
762 (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);\r
763 } else {\r
764 return EFI_UNSUPPORTED;\r
765 }\r
766\r
767 Data = AllocatePool (Size);\r
768 if (Data == NULL) {\r
769 return EFI_OUT_OF_RESOURCES;
770 }\r
771\r
772 ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push = TRUE;\r
773 ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent = FALSE;\r
774 ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;\r
775\r
776 //
777 // Build the fragment table.
778 //
779 ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;\r
780\r
781 NetbufBuildExt (\r
782 Packet,\r
783 (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0],\r
784 &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount\r
785 );\r
786\r
787 Tcp4 = NULL;\r
788 Tcp6 = NULL;\r
789 Status = EFI_DEVICE_ERROR;\r
790\r
791 //
792 // Trasnmit the packet.
793 //\r
794 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
795 TcpIo->TxToken.Tcp4Token.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data;\r
796 Tcp4 = TcpIo->Tcp.Tcp4;\r
797 if (TcpIo->IsListenDone) {\r
798 Tcp4 = TcpIo->NewTcp.Tcp4;\r
799 }\r
800\r
801 if (Tcp4 == NULL) {\r
802 goto ON_EXIT;\r
803 }\r
804 \r
805 Status = Tcp4->Transmit (Tcp4, &TcpIo->TxToken.Tcp4Token);\r
806 } else {\r
807 TcpIo->TxToken.Tcp6Token.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data;\r
808 Tcp6 = TcpIo->Tcp.Tcp6;\r
809 if (TcpIo->IsListenDone) {\r
810 Tcp6 = TcpIo->NewTcp.Tcp6;\r
811 }\r
812\r
813 if (Tcp6 == NULL) {\r
814 goto ON_EXIT;\r
815 }\r
816\r
817 Status = Tcp6->Transmit (Tcp6, &TcpIo->TxToken.Tcp6Token);\r
818 }\r
819\r
820 if (EFI_ERROR (Status)) {
821 goto ON_EXIT;
822 }
823
824 while (!TcpIo->IsTxDone) {\r
825 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
826 Tcp4->Poll (Tcp4);\r
827 } else {\r
828 Tcp6->Poll (Tcp6);\r
829 }\r
830 }
831
832 TcpIo->IsTxDone = FALSE;\r
833 Status = TcpIo->TxToken.Tcp4Token.CompletionToken.Status;\r
834\r
835ON_EXIT:
836
837 FreePool (Data);\r
838
839 return Status;\r
840}\r
841\r
842/**\r
843 Receive data from the socket.\r
844\r
845 @param[in, out] TcpIo The TcpIo which wraps the socket to be destroyed.\r
846 @param[in] Packet The buffer to hold the data copy from the socket rx buffer.\r
847 @param[in] AsyncMode Is this receive asyncronous or not.\r
848 @param[in] Timeout The time to wait for receiving the amount of data the Packet\r
849 can hold.\r
850\r
851 @retval EFI_SUCCESS The required amount of data is received from the socket.\r
852 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
853 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.\r
854 @retval EFI_OUT_OF_RESOURCES Failed to allocate momery.\r
855 @retval EFI_TIMEOUT Failed to receive the required amount of data in the\r
856 specified time period.\r
857 @retval Others Other errors as indicated.\r
858\r
859**/\r
860EFI_STATUS\r
861EFIAPI\r
862TcpIoReceive (\r
863 IN OUT TCP_IO *TcpIo,\r
864 IN NET_BUF *Packet,\r
865 IN BOOLEAN AsyncMode,\r
866 IN EFI_EVENT Timeout\r
867 )\r
868{\r
869 EFI_TCP4_PROTOCOL *Tcp4;\r
870 EFI_TCP6_PROTOCOL *Tcp6;\r
871 EFI_TCP4_RECEIVE_DATA RxData;\r
872 EFI_STATUS Status;\r
873 NET_FRAGMENT *Fragment;\r
874 UINT32 FragmentCount;\r
875 UINT32 CurrentFragment;\r
876\r
877 if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) {\r
878 return EFI_INVALID_PARAMETER;\r
879 }\r
880\r
881 Tcp4 = NULL;\r
882 Tcp6 = NULL;\r
883\r
884 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
4bad9ada 885 Tcp4 = TcpIo->Tcp.Tcp4;\r
886\r
887 if (TcpIo->IsListenDone) {\r
888 Tcp4 = TcpIo->NewTcp.Tcp4;\r
889 }\r
890\r
891 if (Tcp4 == NULL) {\r
892 return EFI_DEVICE_ERROR;\r
893 }\r
894\r
70b356a9 895 TcpIo->RxToken.Tcp4Token.Packet.RxData = &RxData;\r
896\r
4bad9ada 897 } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
4bad9ada 898 Tcp6 = TcpIo->Tcp.Tcp6;\r
899\r
900 if (TcpIo->IsListenDone) {\r
901 Tcp6 = TcpIo->NewTcp.Tcp6;\r
902 }\r
903\r
904 if (Tcp6 == NULL) {\r
905 return EFI_DEVICE_ERROR; \r
906 }\r
907\r
70b356a9 908 TcpIo->RxToken.Tcp6Token.Packet.RxData = (EFI_TCP6_RECEIVE_DATA *) &RxData;\r
909\r
4bad9ada 910 } else {\r
911 return EFI_UNSUPPORTED;\r
912 }\r
913\r
914 FragmentCount = Packet->BlockOpNum;
915 Fragment = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
ec50ecf2
ED
916 if (Fragment == NULL) {\r
917 Status = EFI_OUT_OF_RESOURCES;\r
918 goto ON_EXIT;\r
4bad9ada 919 }
920 //
921 // Build the fragment table.
922 //
923 NetbufBuildExt (Packet, Fragment, &FragmentCount);
924\r
925 RxData.FragmentCount = 1;\r
926 CurrentFragment = 0;\r
927 Status = EFI_SUCCESS;
928
929 while (CurrentFragment < FragmentCount) {
930 RxData.DataLength = Fragment[CurrentFragment].Len;
931 RxData.FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;
932 RxData.FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;
933\r
934 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
935 Status = Tcp4->Receive (Tcp4, &TcpIo->RxToken.Tcp4Token);\r
936 } else {\r
937 Status = Tcp6->Receive (Tcp6, &TcpIo->RxToken.Tcp6Token);\r
938 }\r
939 \r
940 if (EFI_ERROR (Status)) {
941 goto ON_EXIT;
942 }
943 \r
944 while (!TcpIo->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
945 //\r
946 // Poll until some data is received or an error occurs.\r
947 //\r
948 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
949 Tcp4->Poll (Tcp4);\r
950 } else {\r
951 Tcp6->Poll (Tcp6);\r
952 }\r
953 }\r
954
955 if (!TcpIo->IsRxDone) {\r
956 //
957 // Timeout occurs, cancel the receive request.
958 //
959 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
960 Tcp4->Cancel (Tcp4, &TcpIo->RxToken.Tcp4Token.CompletionToken);\r
961 } else {\r
962 Tcp6->Cancel (Tcp6, &TcpIo->RxToken.Tcp6Token.CompletionToken);\r
963 }\r
964
965 Status = EFI_TIMEOUT;
966 goto ON_EXIT;
967 } else {
968 TcpIo->IsRxDone = FALSE;\r
969 }\r
970\r
971 Status = TcpIo->RxToken.Tcp4Token.CompletionToken.Status;\r
972\r
973 if (EFI_ERROR (Status)) {\r
974 goto ON_EXIT;
975 }
976
977 Fragment[CurrentFragment].Len -= RxData.FragmentTable[0].FragmentLength;
978 if (Fragment[CurrentFragment].Len == 0) {
979 CurrentFragment++;
980 } else {
981 Fragment[CurrentFragment].Bulk += RxData.FragmentTable[0].FragmentLength;
982 }
983 }
984
985ON_EXIT:
986\r
987 if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
988 TcpIo->RxToken.Tcp4Token.Packet.RxData = NULL;\r
989 } else {\r
990 TcpIo->RxToken.Tcp6Token.Packet.RxData = NULL;\r
991 }\r
ec50ecf2
ED
992 \r
993 if (Fragment != NULL) {\r
994 FreePool (Fragment);\r
995 }\r
4bad9ada 996
997 return Status;\r
998}\r