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 - 2011, 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
TcpIoCommonNotify(IN EFI_EVENT Event,IN VOID * Context)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
TcpIoGetMapping(IN EFI_TCP6_PROTOCOL * Tcp6,IN EFI_TCP6_CONFIG_DATA * Tcp6ConfigData)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
TcpIoCreateSocket(IN EFI_HANDLE Image,IN EFI_HANDLE Controller,IN UINT8 TcpVersion,IN TCP_IO_CONFIG_DATA * ConfigData,OUT TCP_IO * TcpIo)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
TcpIoDestroySocket(IN TCP_IO * TcpIo)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.
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
TcpIoConnect(IN OUT TCP_IO * TcpIo,IN EFI_EVENT Timeout)547 TcpIoConnect (
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 **/
614 EFI_STATUS
615 EFIAPI
TcpIoAccept(IN OUT TCP_IO * TcpIo,IN EFI_EVENT Timeout)616 TcpIoAccept (
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 **/
694 VOID
695 EFIAPI
TcpIoReset(IN OUT TCP_IO * TcpIo)696 TcpIoReset (
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 **/
753 EFI_STATUS
754 EFIAPI
TcpIoTransmit(IN TCP_IO * TcpIo,IN NET_BUF * Packet)755 TcpIoTransmit (
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 
849 ON_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 **/
874 EFI_STATUS
875 EFIAPI
TcpIoReceive(IN OUT TCP_IO * TcpIo,IN NET_BUF * Packet,IN BOOLEAN AsyncMode,IN EFI_EVENT Timeout)876 TcpIoReceive (
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 
1000 ON_EXIT:
1001 
1002   if (Fragment != NULL) {
1003     FreePool (Fragment);
1004   }
1005 
1006   return Status;
1007 }
1008