Home | History | Annotate | Download | only in TcpDxe
      1 /** @file
      2   The driver binding and service binding protocol for the TCP driver.
      3 
      4   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
      5 
      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
      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 "TcpMain.h"
     17 
     18 UINT16                        mTcp4RandomPort;
     19 UINT16                        mTcp6RandomPort;
     20 
     21 TCP_HEARTBEAT_TIMER           mTcpTimer = {
     22   NULL,
     23   0
     24 };
     25 
     26 EFI_TCP4_PROTOCOL             gTcp4ProtocolTemplate = {
     27   Tcp4GetModeData,
     28   Tcp4Configure,
     29   Tcp4Routes,
     30   Tcp4Connect,
     31   Tcp4Accept,
     32   Tcp4Transmit,
     33   Tcp4Receive,
     34   Tcp4Close,
     35   Tcp4Cancel,
     36   Tcp4Poll
     37 };
     38 
     39 EFI_TCP6_PROTOCOL             gTcp6ProtocolTemplate = {
     40   Tcp6GetModeData,
     41   Tcp6Configure,
     42   Tcp6Connect,
     43   Tcp6Accept,
     44   Tcp6Transmit,
     45   Tcp6Receive,
     46   Tcp6Close,
     47   Tcp6Cancel,
     48   Tcp6Poll
     49 };
     50 
     51 SOCK_INIT_DATA                mTcpDefaultSockData = {
     52   SockStream,
     53   SO_CLOSED,
     54   NULL,
     55   TCP_BACKLOG,
     56   TCP_SND_BUF_SIZE,
     57   TCP_RCV_BUF_SIZE,
     58   IP_VERSION_4,
     59   NULL,
     60   TcpCreateSocketCallback,
     61   TcpDestroySocketCallback,
     62   NULL,
     63   NULL,
     64   0,
     65   TcpDispatcher,
     66   NULL,
     67 };
     68 
     69 EFI_DRIVER_BINDING_PROTOCOL   gTcp4DriverBinding = {
     70   Tcp4DriverBindingSupported,
     71   Tcp4DriverBindingStart,
     72   Tcp4DriverBindingStop,
     73   0xa,
     74   NULL,
     75   NULL
     76 };
     77 
     78 EFI_DRIVER_BINDING_PROTOCOL   gTcp6DriverBinding = {
     79   Tcp6DriverBindingSupported,
     80   Tcp6DriverBindingStart,
     81   Tcp6DriverBindingStop,
     82   0xa,
     83   NULL,
     84   NULL
     85 };
     86 
     87 EFI_SERVICE_BINDING_PROTOCOL  gTcpServiceBinding = {
     88   TcpServiceBindingCreateChild,
     89   TcpServiceBindingDestroyChild
     90 };
     91 
     92 
     93 /**
     94   Create and start the heartbeat timer for the TCP driver.
     95 
     96   @retval EFI_SUCCESS            The timer was successfully created and started.
     97   @retval other                  The timer was not created.
     98 
     99 **/
    100 EFI_STATUS
    101 TcpCreateTimer (
    102   VOID
    103   )
    104 {
    105   EFI_STATUS  Status;
    106 
    107   Status = EFI_SUCCESS;
    108 
    109   if (mTcpTimer.RefCnt == 0) {
    110 
    111     Status = gBS->CreateEvent (
    112                     EVT_TIMER | EVT_NOTIFY_SIGNAL,
    113                     TPL_NOTIFY,
    114                     TcpTicking,
    115                     NULL,
    116                     &mTcpTimer.TimerEvent
    117                     );
    118     if (!EFI_ERROR (Status)) {
    119 
    120       Status = gBS->SetTimer (
    121                       mTcpTimer.TimerEvent,
    122                       TimerPeriodic,
    123                       (UINT64) (TICKS_PER_SECOND / TCP_TICK_HZ)
    124                       );
    125     }
    126   }
    127 
    128   if (!EFI_ERROR (Status)) {
    129 
    130     mTcpTimer.RefCnt++;
    131   }
    132 
    133   return Status;
    134 }
    135 
    136 /**
    137   Stop and destroy the heartbeat timer for TCP driver.
    138 
    139 **/
    140 VOID
    141 TcpDestroyTimer (
    142   VOID
    143   )
    144 {
    145   ASSERT (mTcpTimer.RefCnt > 0);
    146 
    147   mTcpTimer.RefCnt--;
    148 
    149   if (mTcpTimer.RefCnt > 0) {
    150     return;
    151   }
    152 
    153   gBS->SetTimer (mTcpTimer.TimerEvent, TimerCancel, 0);
    154   gBS->CloseEvent (mTcpTimer.TimerEvent);
    155   mTcpTimer.TimerEvent = NULL;
    156 }
    157 
    158 /**
    159   The entry point for Tcp driver, which is used to install Tcp driver on the ImageHandle.
    160 
    161   @param[in]  ImageHandle   The firmware allocated handle for this driver image.
    162   @param[in]  SystemTable   Pointer to the EFI system table.
    163 
    164   @retval EFI_SUCCESS   The driver loaded.
    165   @retval other         The driver did not load.
    166 
    167 **/
    168 EFI_STATUS
    169 EFIAPI
    170 TcpDriverEntryPoint (
    171   IN EFI_HANDLE        ImageHandle,
    172   IN EFI_SYSTEM_TABLE  *SystemTable
    173   )
    174 {
    175   EFI_STATUS  Status;
    176   UINT32      Seed;
    177 
    178   //
    179   // Install the TCP Driver Binding Protocol
    180   //
    181   Status = EfiLibInstallDriverBindingComponentName2 (
    182              ImageHandle,
    183              SystemTable,
    184              &gTcp4DriverBinding,
    185              ImageHandle,
    186              &gTcpComponentName,
    187              &gTcpComponentName2
    188              );
    189   if (EFI_ERROR (Status)) {
    190     return Status;
    191   }
    192 
    193   //
    194   // Install the TCP Driver Binding Protocol
    195   //
    196   Status = EfiLibInstallDriverBindingComponentName2 (
    197              ImageHandle,
    198              SystemTable,
    199              &gTcp6DriverBinding,
    200              NULL,
    201              &gTcpComponentName,
    202              &gTcpComponentName2
    203              );
    204   if (EFI_ERROR (Status)) {
    205     gBS->UninstallMultipleProtocolInterfaces (
    206            ImageHandle,
    207            &gEfiDriverBindingProtocolGuid,
    208            &gTcp4DriverBinding,
    209            &gEfiComponentName2ProtocolGuid,
    210            &gTcpComponentName2,
    211            &gEfiComponentNameProtocolGuid,
    212            &gTcpComponentName,
    213            NULL
    214            );
    215     return Status;
    216   }
    217 
    218   //
    219   // Initialize ISS and random port.
    220   //
    221   Seed            = NetRandomInitSeed ();
    222   mTcpGlobalIss   = NET_RANDOM (Seed) % mTcpGlobalIss;
    223   mTcp4RandomPort = (UINT16) (TCP_PORT_KNOWN + (NET_RANDOM (Seed) % TCP_PORT_KNOWN));
    224   mTcp6RandomPort = mTcp4RandomPort;
    225 
    226   return EFI_SUCCESS;
    227 }
    228 
    229 /**
    230   Create a new TCP4 or TCP6 driver service binding protocol
    231 
    232   @param[in]  Controller         Controller handle of device to bind driver to.
    233   @param[in]  Image              The TCP driver's image handle.
    234   @param[in]  IpVersion          IP_VERSION_4 or IP_VERSION_6.
    235 
    236   @retval EFI_OUT_OF_RESOURCES   Failed to allocate some resources.
    237   @retval EFI_SUCCESS            A new IP6 service binding private was created.
    238 
    239 **/
    240 EFI_STATUS
    241 TcpCreateService (
    242   IN EFI_HANDLE  Controller,
    243   IN EFI_HANDLE  Image,
    244   IN UINT8       IpVersion
    245   )
    246 {
    247   EFI_STATUS         Status;
    248   EFI_GUID           *IpServiceBindingGuid;
    249   EFI_GUID           *TcpServiceBindingGuid;
    250   TCP_SERVICE_DATA   *TcpServiceData;
    251   IP_IO_OPEN_DATA    OpenData;
    252 
    253   if (IpVersion == IP_VERSION_4) {
    254     IpServiceBindingGuid  = &gEfiIp4ServiceBindingProtocolGuid;
    255     TcpServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
    256   } else {
    257     IpServiceBindingGuid  = &gEfiIp6ServiceBindingProtocolGuid;
    258     TcpServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
    259   }
    260 
    261   Status = gBS->OpenProtocol (
    262                   Controller,
    263                   TcpServiceBindingGuid,
    264                   NULL,
    265                   Image,
    266                   Controller,
    267                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    268                   );
    269   if (!EFI_ERROR (Status)) {
    270     return EFI_ALREADY_STARTED;
    271   }
    272 
    273   Status = gBS->OpenProtocol (
    274                   Controller,
    275                   IpServiceBindingGuid,
    276                   NULL,
    277                   Image,
    278                   Controller,
    279                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    280                   );
    281   if (EFI_ERROR (Status)) {
    282     return EFI_UNSUPPORTED;
    283   }
    284 
    285   //
    286   // Create the TCP service data.
    287   //
    288   TcpServiceData = AllocateZeroPool (sizeof (TCP_SERVICE_DATA));
    289   if (TcpServiceData == NULL) {
    290     return EFI_OUT_OF_RESOURCES;
    291   }
    292 
    293   TcpServiceData->Signature            = TCP_DRIVER_SIGNATURE;
    294   TcpServiceData->ControllerHandle     = Controller;
    295   TcpServiceData->DriverBindingHandle  = Image;
    296   TcpServiceData->IpVersion            = IpVersion;
    297   CopyMem (
    298     &TcpServiceData->ServiceBinding,
    299     &gTcpServiceBinding,
    300     sizeof (EFI_SERVICE_BINDING_PROTOCOL)
    301     );
    302 
    303   TcpServiceData->IpIo = IpIoCreate (Image, Controller, IpVersion);
    304   if (TcpServiceData->IpIo == NULL) {
    305     Status = EFI_OUT_OF_RESOURCES;
    306     goto ON_ERROR;
    307   }
    308 
    309 
    310   InitializeListHead (&TcpServiceData->SocketList);
    311   ZeroMem (&OpenData, sizeof (IP_IO_OPEN_DATA));
    312 
    313   if (IpVersion == IP_VERSION_4) {
    314     CopyMem (
    315       &OpenData.IpConfigData.Ip4CfgData,
    316       &mIp4IoDefaultIpConfigData,
    317       sizeof (EFI_IP4_CONFIG_DATA)
    318       );
    319     OpenData.IpConfigData.Ip4CfgData.DefaultProtocol = EFI_IP_PROTO_TCP;
    320   } else {
    321     CopyMem (
    322       &OpenData.IpConfigData.Ip6CfgData,
    323       &mIp6IoDefaultIpConfigData,
    324       sizeof (EFI_IP6_CONFIG_DATA)
    325       );
    326     OpenData.IpConfigData.Ip6CfgData.DefaultProtocol = EFI_IP_PROTO_TCP;
    327   }
    328 
    329   OpenData.PktRcvdNotify  = TcpRxCallback;
    330   Status                  = IpIoOpen (TcpServiceData->IpIo, &OpenData);
    331   if (EFI_ERROR (Status)) {
    332     goto ON_ERROR;
    333   }
    334 
    335   Status = TcpCreateTimer ();
    336   if (EFI_ERROR (Status)) {
    337     goto ON_ERROR;
    338   }
    339 
    340   Status = gBS->InstallMultipleProtocolInterfaces (
    341                   &Controller,
    342                   TcpServiceBindingGuid,
    343                   &TcpServiceData->ServiceBinding,
    344                   NULL
    345                   );
    346   if (EFI_ERROR (Status)) {
    347     TcpDestroyTimer ();
    348 
    349     goto ON_ERROR;
    350   }
    351 
    352   return EFI_SUCCESS;
    353 
    354 ON_ERROR:
    355 
    356   if (TcpServiceData->IpIo != NULL) {
    357     IpIoDestroy (TcpServiceData->IpIo);
    358     TcpServiceData->IpIo = NULL;
    359   }
    360 
    361   FreePool (TcpServiceData);
    362 
    363   return Status;
    364 }
    365 
    366 /**
    367   Callback function which provided by user to remove one node in NetDestroyLinkList process.
    368 
    369   @param[in]    Entry           The entry to be removed.
    370   @param[in]    Context         Pointer to the callback context corresponds to the Context in NetDestroyLinkList.
    371 
    372   @retval EFI_SUCCESS           The entry has been removed successfully.
    373   @retval Others                Fail to remove the entry.
    374 
    375 **/
    376 EFI_STATUS
    377 EFIAPI
    378 TcpDestroyChildEntryInHandleBuffer (
    379   IN LIST_ENTRY         *Entry,
    380   IN VOID               *Context
    381   )
    382 {
    383   SOCKET                        *Sock;
    384   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
    385   UINTN                         NumberOfChildren;
    386   EFI_HANDLE                    *ChildHandleBuffer;
    387 
    388   if (Entry == NULL || Context == NULL) {
    389     return EFI_INVALID_PARAMETER;
    390   }
    391 
    392   Sock = NET_LIST_USER_STRUCT_S (Entry, SOCKET, Link, SOCK_SIGNATURE);
    393   ServiceBinding    = ((TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ServiceBinding;
    394   NumberOfChildren  = ((TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->NumberOfChildren;
    395   ChildHandleBuffer = ((TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT *) Context)->ChildHandleBuffer;
    396 
    397   if (!NetIsInHandleBuffer (Sock->SockHandle, NumberOfChildren, ChildHandleBuffer)) {
    398     return EFI_SUCCESS;
    399   }
    400 
    401   return ServiceBinding->DestroyChild (ServiceBinding, Sock->SockHandle);
    402 }
    403 
    404 /**
    405   Destroy a TCP6 or TCP4 service binding instance. It will release all
    406   the resources allocated by the instance.
    407 
    408   @param[in]  Controller         Controller handle of device to bind driver to.
    409   @param[in]  ImageHandle        The TCP driver's image handle.
    410   @param[in]  NumberOfChildren   Number of Handles in ChildHandleBuffer. If number
    411                                  of children is zero stop the entire bus driver.
    412   @param[in]  ChildHandleBuffer  An array of child handles to be freed. May be NULL
    413                                  if NumberOfChildren is 0.
    414   @param[in]  IpVersion          IP_VERSION_4 or IP_VERSION_6
    415 
    416   @retval EFI_SUCCESS            The resources used by the instance were cleaned up.
    417   @retval Others                 Failed to clean up some of the resources.
    418 
    419 **/
    420 EFI_STATUS
    421 TcpDestroyService (
    422   IN EFI_HANDLE  Controller,
    423   IN EFI_HANDLE  ImageHandle,
    424   IN UINTN       NumberOfChildren,
    425   IN EFI_HANDLE  *ChildHandleBuffer, OPTIONAL
    426   IN UINT8       IpVersion
    427   )
    428 {
    429   EFI_HANDLE                    NicHandle;
    430   EFI_GUID                      *IpProtocolGuid;
    431   EFI_GUID                      *ServiceBindingGuid;
    432   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
    433   TCP_SERVICE_DATA              *TcpServiceData;
    434   EFI_STATUS                    Status;
    435   LIST_ENTRY                    *List;
    436   TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT  Context;
    437 
    438   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
    439 
    440   if (IpVersion == IP_VERSION_4) {
    441     IpProtocolGuid     = &gEfiIp4ProtocolGuid;
    442     ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
    443   } else {
    444     IpProtocolGuid     = &gEfiIp6ProtocolGuid;
    445     ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
    446   }
    447 
    448   NicHandle = NetLibGetNicHandle (Controller, IpProtocolGuid);
    449   if (NicHandle == NULL) {
    450     return EFI_SUCCESS;
    451   }
    452 
    453   Status = gBS->OpenProtocol (
    454                   NicHandle,
    455                   ServiceBindingGuid,
    456                   (VOID **) &ServiceBinding,
    457                   ImageHandle,
    458                   Controller,
    459                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    460                   );
    461   if (EFI_ERROR (Status)) {
    462     return EFI_DEVICE_ERROR;
    463   }
    464 
    465   TcpServiceData = TCP_SERVICE_FROM_THIS (ServiceBinding);
    466 
    467   if (NumberOfChildren != 0) {
    468     List = &TcpServiceData->SocketList;
    469     Context.ServiceBinding = ServiceBinding;
    470     Context.NumberOfChildren = NumberOfChildren;
    471     Context.ChildHandleBuffer = ChildHandleBuffer;
    472     Status = NetDestroyLinkList (
    473                List,
    474                TcpDestroyChildEntryInHandleBuffer,
    475                &Context,
    476                NULL
    477                );
    478   } else if (IsListEmpty (&TcpServiceData->SocketList)) {
    479     //
    480     // Uninstall TCP servicebinding protocol
    481     //
    482     gBS->UninstallMultipleProtocolInterfaces (
    483            NicHandle,
    484            ServiceBindingGuid,
    485            ServiceBinding,
    486            NULL
    487            );
    488 
    489     //
    490     // Destroy the IpIO consumed by TCP driver
    491     //
    492     IpIoDestroy (TcpServiceData->IpIo);
    493     TcpServiceData->IpIo = NULL;
    494 
    495     //
    496     // Destroy the heartbeat timer.
    497     //
    498     TcpDestroyTimer ();
    499 
    500     //
    501     // Release the TCP service data
    502     //
    503     FreePool (TcpServiceData);
    504 
    505     Status = EFI_SUCCESS;
    506   }
    507 
    508   return Status;
    509 }
    510 
    511 /**
    512   Test to see if this driver supports ControllerHandle.
    513 
    514   @param[in]  This                Protocol instance pointer.
    515   @param[in]  ControllerHandle    Handle of device to test.
    516   @param[in]  RemainingDevicePath Optional parameter use to pick a specific
    517                                   child device to start.
    518 
    519   @retval EFI_SUCCESS             This driver supports this device.
    520   @retval EFI_ALREADY_STARTED     This driver is already running on this device.
    521   @retval other                   This driver does not support this device.
    522 
    523 **/
    524 EFI_STATUS
    525 EFIAPI
    526 Tcp4DriverBindingSupported (
    527   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    528   IN EFI_HANDLE                   ControllerHandle,
    529   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    530   )
    531 {
    532   EFI_STATUS  Status;
    533 
    534   //
    535   // Test for the Tcp4ServiceBinding Protocol
    536   //
    537   Status = gBS->OpenProtocol (
    538                   ControllerHandle,
    539                   &gEfiTcp4ServiceBindingProtocolGuid,
    540                   NULL,
    541                   This->DriverBindingHandle,
    542                   ControllerHandle,
    543                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    544                   );
    545   if (!EFI_ERROR (Status)) {
    546     return EFI_ALREADY_STARTED;
    547   }
    548 
    549   //
    550   // Test for the Ip4ServiceBinding Protocol
    551   //
    552   Status = gBS->OpenProtocol (
    553                   ControllerHandle,
    554                   &gEfiIp4ServiceBindingProtocolGuid,
    555                   NULL,
    556                   This->DriverBindingHandle,
    557                   ControllerHandle,
    558                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    559                   );
    560   return Status;
    561 }
    562 
    563 /**
    564   Start this driver on ControllerHandle.
    565 
    566   @param[in]  This                   Protocol instance pointer.
    567   @param[in]  ControllerHandle       Handle of device to bind driver to.
    568   @param[in]  RemainingDevicePath    Optional parameter use to pick a specific child
    569                                      device to start.
    570 
    571   @retval EFI_SUCCESS            The driver is added to ControllerHandle.
    572   @retval EFI_OUT_OF_RESOURCES   There are not enough resources to start the
    573                                  driver.
    574   @retval other                  The driver cannot be added to ControllerHandle.
    575 
    576 **/
    577 EFI_STATUS
    578 EFIAPI
    579 Tcp4DriverBindingStart (
    580   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    581   IN EFI_HANDLE                   ControllerHandle,
    582   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    583   )
    584 {
    585   EFI_STATUS  Status;
    586 
    587   Status = TcpCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_4);
    588   if ((Status == EFI_ALREADY_STARTED) || (Status == EFI_UNSUPPORTED)) {
    589     Status = EFI_SUCCESS;
    590   }
    591 
    592   return Status;
    593 }
    594 
    595 /**
    596   Stop this driver on ControllerHandle.
    597 
    598   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    599   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
    600                                 support a bus specific I/O protocol for the driver
    601                                 to use to stop the device.
    602   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
    603   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
    604                                 if NumberOfChildren is 0.
    605 
    606   @retval EFI_SUCCESS           The device was stopped.
    607   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
    608 
    609 **/
    610 EFI_STATUS
    611 EFIAPI
    612 Tcp4DriverBindingStop (
    613   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    614   IN  EFI_HANDLE                   ControllerHandle,
    615   IN  UINTN                        NumberOfChildren,
    616   IN  EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
    617   )
    618 {
    619   return TcpDestroyService (
    620            ControllerHandle,
    621            This->DriverBindingHandle,
    622            NumberOfChildren,
    623            ChildHandleBuffer,
    624            IP_VERSION_4
    625            );
    626 }
    627 
    628 /**
    629   Test to see if this driver supports ControllerHandle.
    630 
    631   @param[in]  This                Protocol instance pointer.
    632   @param[in]  ControllerHandle    Handle of device to test.
    633   @param[in]  RemainingDevicePath Optional parameter use to pick a specific
    634                                   child device to start.
    635 
    636   @retval EFI_SUCCESS             This driver supports this device.
    637   @retval EFI_ALREADY_STARTED     This driver is already running on this device.
    638   @retval other                   This driver does not support this device.
    639 
    640 **/
    641 EFI_STATUS
    642 EFIAPI
    643 Tcp6DriverBindingSupported (
    644   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    645   IN EFI_HANDLE                   ControllerHandle,
    646   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    647   )
    648 {
    649   EFI_STATUS  Status;
    650 
    651   //
    652   // Test for the Tcp6ServiceBinding Protocol
    653   //
    654   Status = gBS->OpenProtocol (
    655                   ControllerHandle,
    656                   &gEfiTcp6ServiceBindingProtocolGuid,
    657                   NULL,
    658                   This->DriverBindingHandle,
    659                   ControllerHandle,
    660                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    661                   );
    662   if (!EFI_ERROR (Status)) {
    663     return EFI_ALREADY_STARTED;
    664   }
    665 
    666   //
    667   // Test for the Ip6ServiceBinding Protocol
    668   //
    669   Status = gBS->OpenProtocol (
    670                   ControllerHandle,
    671                   &gEfiIp6ServiceBindingProtocolGuid,
    672                   NULL,
    673                   This->DriverBindingHandle,
    674                   ControllerHandle,
    675                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL
    676                   );
    677   return Status;
    678 }
    679 
    680 /**
    681   Start this driver on ControllerHandle.
    682 
    683   @param[in]  This                   Protocol instance pointer.
    684   @param[in]  ControllerHandle       Handle of device to bind driver to.
    685   @param[in]  RemainingDevicePath    Optional parameter use to pick a specific child
    686                                      device to start.
    687 
    688   @retval EFI_SUCCESS            The driver is added to ControllerHandle.
    689   @retval EFI_OUT_OF_RESOURCES   There are not enough resources to start the
    690                                  driver.
    691   @retval other                  The driver cannot be added to ControllerHandle.
    692 
    693 **/
    694 EFI_STATUS
    695 EFIAPI
    696 Tcp6DriverBindingStart (
    697   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    698   IN EFI_HANDLE                   ControllerHandle,
    699   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    700   )
    701 {
    702   EFI_STATUS  Status;
    703 
    704   Status = TcpCreateService (ControllerHandle, This->DriverBindingHandle, IP_VERSION_6);
    705   if ((Status == EFI_ALREADY_STARTED) || (Status == EFI_UNSUPPORTED)) {
    706     Status = EFI_SUCCESS;
    707   }
    708 
    709   return Status;
    710 }
    711 
    712 /**
    713   Stop this driver on ControllerHandle.
    714 
    715   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    716   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
    717                                 support a bus specific I/O protocol for the driver
    718                                 to use to stop the device.
    719   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
    720   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
    721                                 if NumberOfChildren is 0.
    722 
    723   @retval EFI_SUCCESS           The device was stopped.
    724   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
    725 
    726 **/
    727 EFI_STATUS
    728 EFIAPI
    729 Tcp6DriverBindingStop (
    730   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    731   IN  EFI_HANDLE                   ControllerHandle,
    732   IN  UINTN                        NumberOfChildren,
    733   IN  EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
    734   )
    735 {
    736   return TcpDestroyService (
    737            ControllerHandle,
    738            This->DriverBindingHandle,
    739            NumberOfChildren,
    740            ChildHandleBuffer,
    741            IP_VERSION_6
    742            );
    743 }
    744 
    745 /**
    746   The Callback funtion called after the TCP socket was created.
    747 
    748   @param[in]  This            Pointer to the socket just created
    749   @param[in]  Context         Context of the socket
    750 
    751   @retval EFI_SUCCESS         This protocol installed successfully.
    752   @retval other               An error occured.
    753 
    754 **/
    755 EFI_STATUS
    756 TcpCreateSocketCallback (
    757   IN SOCKET  *This,
    758   IN VOID    *Context
    759   )
    760 {
    761   EFI_STATUS        Status;
    762   TCP_SERVICE_DATA  *TcpServiceData;
    763   EFI_GUID          *IpProtocolGuid;
    764   VOID              *Ip;
    765 
    766   if (This->IpVersion == IP_VERSION_4) {
    767     IpProtocolGuid = &gEfiIp4ProtocolGuid;
    768   } else {
    769     IpProtocolGuid = &gEfiIp6ProtocolGuid;
    770   }
    771 
    772   TcpServiceData = ((TCP_PROTO_DATA *) This->ProtoReserved)->TcpService;
    773 
    774   //
    775   // Open the default IP protocol of IP_IO BY_DRIVER.
    776   //
    777   Status = gBS->OpenProtocol (
    778                   TcpServiceData->IpIo->ChildHandle,
    779                   IpProtocolGuid,
    780                   &Ip,
    781                   TcpServiceData->DriverBindingHandle,
    782                   This->SockHandle,
    783                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    784                   );
    785   if (EFI_ERROR (Status)) {
    786     return Status;
    787   }
    788 
    789   //
    790   // Open the device path on the handle where service binding resides on.
    791   //
    792   Status = gBS->OpenProtocol (
    793                   TcpServiceData->ControllerHandle,
    794                   &gEfiDevicePathProtocolGuid,
    795                   (VOID **) &This->ParentDevicePath,
    796                   TcpServiceData->DriverBindingHandle,
    797                   This->SockHandle,
    798                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    799                   );
    800   if (EFI_ERROR (Status)) {
    801     gBS->CloseProtocol (
    802            TcpServiceData->IpIo->ChildHandle,
    803            IpProtocolGuid,
    804            TcpServiceData->DriverBindingHandle,
    805            This->SockHandle
    806            );
    807   } else {
    808     //
    809     // Insert this socket into the SocketList.
    810     //
    811     InsertTailList (&TcpServiceData->SocketList, &This->Link);
    812   }
    813 
    814   return Status;
    815 }
    816 
    817 /**
    818   The callback function called before the TCP socket was to be destroyed.
    819 
    820   @param[in]  This                   The TCP socket to be destroyed.
    821   @param[in]  Context                The context of the socket.
    822 
    823 **/
    824 VOID
    825 TcpDestroySocketCallback (
    826   IN SOCKET  *This,
    827   IN VOID    *Context
    828   )
    829 {
    830   TCP_SERVICE_DATA  *TcpServiceData;
    831   EFI_GUID          *IpProtocolGuid;
    832 
    833   if (This->IpVersion == IP_VERSION_4) {
    834     IpProtocolGuid = &gEfiIp4ProtocolGuid;
    835   } else {
    836     IpProtocolGuid = &gEfiIp6ProtocolGuid;
    837   }
    838 
    839   TcpServiceData = ((TCP_PROTO_DATA *) This->ProtoReserved)->TcpService;
    840 
    841   //
    842   // Remove this node from the list.
    843   //
    844   RemoveEntryList (&This->Link);
    845 
    846   //
    847   // Close the IP protocol.
    848   //
    849   gBS->CloseProtocol (
    850          TcpServiceData->IpIo->ChildHandle,
    851          IpProtocolGuid,
    852          TcpServiceData->DriverBindingHandle,
    853          This->SockHandle
    854          );
    855 }
    856 
    857 /**
    858   Creates a child handle with a set of TCP services.
    859 
    860   The CreateChild() function installs a protocol on ChildHandle.
    861   If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle.
    862   If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle.
    863 
    864   @param[in]      This          Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
    865   @param[in, out] ChildHandle   Pointer to the handle of the child to create.
    866                                 If it is NULL, then a new handle is created.
    867                                 If it is a pointer to an existing UEFI handle,
    868                                 then the protocol is added to the existing UEFI handle.
    869 
    870   @retval EFI_SUCCES            The protocol was added to ChildHandle.
    871   @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
    872   @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to create
    873                                 the child.
    874   @retval other                 The child handle was not created.
    875 
    876 **/
    877 EFI_STATUS
    878 EFIAPI
    879 TcpServiceBindingCreateChild (
    880   IN     EFI_SERVICE_BINDING_PROTOCOL  *This,
    881   IN OUT EFI_HANDLE                    *ChildHandle
    882   )
    883 {
    884   SOCKET            *Sock;
    885   TCP_SERVICE_DATA  *TcpServiceData;
    886   TCP_PROTO_DATA    TcpProto;
    887   EFI_STATUS        Status;
    888   EFI_TPL           OldTpl;
    889 
    890   if (NULL == This || NULL == ChildHandle) {
    891     return EFI_INVALID_PARAMETER;
    892   }
    893 
    894   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    895 
    896   Status              = EFI_SUCCESS;
    897   TcpServiceData      = TCP_SERVICE_FROM_THIS (This);
    898   TcpProto.TcpService = TcpServiceData;
    899   TcpProto.TcpPcb     = NULL;
    900 
    901   //
    902   // Create a tcp instance with defualt Tcp default
    903   // sock init data and TcpProto
    904   //
    905   mTcpDefaultSockData.ProtoData     = &TcpProto;
    906   mTcpDefaultSockData.DataSize      = sizeof (TCP_PROTO_DATA);
    907   mTcpDefaultSockData.DriverBinding = TcpServiceData->DriverBindingHandle;
    908   mTcpDefaultSockData.IpVersion     = TcpServiceData->IpVersion;
    909 
    910   if (TcpServiceData->IpVersion == IP_VERSION_4) {
    911     mTcpDefaultSockData.Protocol = &gTcp4ProtocolTemplate;
    912   } else {
    913     mTcpDefaultSockData.Protocol = &gTcp6ProtocolTemplate;
    914   }
    915 
    916   Sock = SockCreateChild (&mTcpDefaultSockData);
    917   if (NULL == Sock) {
    918     DEBUG (
    919       (EFI_D_ERROR,
    920       "TcpDriverBindingCreateChild: No resource to create a Tcp Child\n")
    921       );
    922 
    923     Status = EFI_OUT_OF_RESOURCES;
    924   } else {
    925     *ChildHandle = Sock->SockHandle;
    926   }
    927 
    928   mTcpDefaultSockData.ProtoData  = NULL;
    929 
    930   gBS->RestoreTPL (OldTpl);
    931   return Status;
    932 }
    933 
    934 /**
    935   Destroys a child handle with a set of TCP services.
    936 
    937   The DestroyChild() function does the opposite of CreateChild(). It removes a protocol
    938   that was installed by CreateChild() from ChildHandle. If the removed protocol is the
    939   last protocol on ChildHandle, then ChildHandle is destroyed.
    940 
    941   @param  This        Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.
    942   @param  ChildHandle Handle of the child to be destroyed.
    943 
    944   @retval EFI_SUCCES            The protocol was removed from ChildHandle.
    945   @retval EFI_UNSUPPORTED       ChildHandle does not support the protocol that is being removed.
    946   @retval EFI_INVALID_PARAMETER Child handle is NULL.
    947   @retval EFI_ACCESS_DENIED     The protocol could not be removed from the ChildHandle
    948                                 because its services are being used.
    949   @retval other                 The child handle was not destroyed.
    950 
    951 **/
    952 EFI_STATUS
    953 EFIAPI
    954 TcpServiceBindingDestroyChild (
    955   IN EFI_SERVICE_BINDING_PROTOCOL  *This,
    956   IN EFI_HANDLE                    ChildHandle
    957   )
    958 {
    959   EFI_STATUS  Status;
    960   VOID        *Tcp;
    961   SOCKET      *Sock;
    962 
    963   if (NULL == This || NULL == ChildHandle) {
    964     return EFI_INVALID_PARAMETER;
    965   }
    966 
    967   //
    968   // retrieve the Tcp4 protocol from ChildHandle
    969   //
    970   Status = gBS->OpenProtocol (
    971                   ChildHandle,
    972                   &gEfiTcp4ProtocolGuid,
    973                   &Tcp,
    974                   gTcp4DriverBinding.DriverBindingHandle,
    975                   ChildHandle,
    976                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    977                   );
    978   if (EFI_ERROR (Status)) {
    979     //
    980     // No Tcp4, try the Tcp6 protocol
    981     //
    982     Status = gBS->OpenProtocol (
    983                     ChildHandle,
    984                     &gEfiTcp6ProtocolGuid,
    985                     &Tcp,
    986                     gTcp6DriverBinding.DriverBindingHandle,
    987                     ChildHandle,
    988                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    989                     );
    990     if (EFI_ERROR (Status)) {
    991       Status = EFI_UNSUPPORTED;
    992     }
    993   }
    994 
    995   if (!EFI_ERROR (Status)) {
    996     //
    997     // destroy this sock and related Tcp protocol control
    998     // block
    999     //
   1000     Sock = SOCK_FROM_THIS (Tcp);
   1001 
   1002     SockDestroyChild (Sock);
   1003   }
   1004 
   1005   return Status;
   1006 }
   1007