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