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