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