]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c
MdeModulePkg/TcpIoLib: Cancel TCP token if connect/accept is timeout.
[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 - 2017, 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 EFI_OUT_OF_RESOURCES Failed to allocate memory.
127 @retval Others Failed to create the TCP socket or configure it.
128
129 **/
130 EFI_STATUS
131 EFIAPI
132 TcpIoCreateSocket (
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
392 ON_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 **/
405 VOID
406 EFIAPI
407 TcpIoDestroySocket (
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 **/
545 EFI_STATUS
546 EFIAPI
547 TcpIoConnect (
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 **/
619 EFI_STATUS
620 EFIAPI
621 TcpIoAccept (
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 **/
704 VOID
705 EFIAPI
706 TcpIoReset (
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 **/
763 EFI_STATUS
764 EFIAPI
765 TcpIoTransmit (
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
859 ON_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 **/
884 EFI_STATUS
885 EFIAPI
886 TcpIoReceive (
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
1010 ON_EXIT:
1011
1012 if (Fragment != NULL) {
1013 FreePool (Fragment);
1014 }
1015
1016 return Status;
1017 }