VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c@ 78223

Last change on this file since 78223 was 77662, checked in by vboxsync, 6 years ago

EFI: First step in UDK2018 merge. Does not build yet.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette