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