Home | History | Annotate | Download | only in IScsiDxe
      1 /** @file
      2   The wrap of TCP/IP Socket interface.
      3 
      4 Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "IScsiImpl.h"
     16 
     17 /**
     18   The common notify function associated with various Tcp4Io events.
     19 
     20   @param[in]  Event   The event signaled.
     21   @param[in]  Context The context.
     22 **/
     23 VOID
     24 EFIAPI
     25 Tcp4IoCommonNotify (
     26   IN EFI_EVENT  Event,
     27   IN VOID       *Context
     28   )
     29 {
     30   *((BOOLEAN *) Context) = TRUE;
     31 }
     32 
     33 /**
     34   Create a TCP socket with the specified configuration data.
     35 
     36   @param[in]  Image      The handle of the driver image.
     37   @param[in]  Controller The handle of the controller.
     38   @param[in]  ConfigData The Tcp4 configuration data.
     39   @param[in]  Tcp4Io     The Tcp4Io.
     40 
     41   @retval EFI_SUCCESS    The TCP socket is created and configured.
     42   @retval Others         Failed to create the TCP socket or configure it.
     43 **/
     44 EFI_STATUS
     45 Tcp4IoCreateSocket (
     46   IN EFI_HANDLE           Image,
     47   IN EFI_HANDLE           Controller,
     48   IN TCP4_IO_CONFIG_DATA  *ConfigData,
     49   IN TCP4_IO              *Tcp4Io
     50   )
     51 {
     52   EFI_STATUS            Status;
     53   EFI_TCP4_PROTOCOL     *Tcp4;
     54   EFI_TCP4_CONFIG_DATA  Tcp4ConfigData;
     55   EFI_TCP4_OPTION       ControlOption;
     56   EFI_TCP4_ACCESS_POINT *AccessPoint;
     57 
     58   Tcp4Io->Handle = NULL;
     59   Tcp4Io->ConnToken.CompletionToken.Event = NULL;
     60   Tcp4Io->TxToken.CompletionToken.Event = NULL;
     61   Tcp4Io->RxToken.CompletionToken.Event = NULL;
     62   Tcp4Io->CloseToken.CompletionToken.Event = NULL;
     63   Tcp4 = NULL;
     64 
     65   //
     66   // Create the TCP4 child instance and get the TCP4 protocol.
     67   //
     68   Status = NetLibCreateServiceChild (
     69             Controller,
     70             Image,
     71             &gEfiTcp4ServiceBindingProtocolGuid,
     72             &Tcp4Io->Handle
     73             );
     74   if (EFI_ERROR (Status)) {
     75     return Status;
     76   }
     77 
     78   Status = gBS->OpenProtocol (
     79                   Tcp4Io->Handle,
     80                   &gEfiTcp4ProtocolGuid,
     81                   (VOID **)&Tcp4Io->Tcp4,
     82                   Image,
     83                   Controller,
     84                   EFI_OPEN_PROTOCOL_BY_DRIVER
     85                   );
     86   if (EFI_ERROR (Status)) {
     87     goto ON_ERROR;
     88   }
     89 
     90   Tcp4Io->Image       = Image;
     91   Tcp4Io->Controller  = Controller;
     92   Tcp4                = Tcp4Io->Tcp4;
     93 
     94   //
     95   // Set the configuration parameters.
     96   //
     97   ControlOption.ReceiveBufferSize       = 0x200000;
     98   ControlOption.SendBufferSize          = 0x200000;
     99   ControlOption.MaxSynBackLog           = 0;
    100   ControlOption.ConnectionTimeout       = 0;
    101   ControlOption.DataRetries             = 6;
    102   ControlOption.FinTimeout              = 0;
    103   ControlOption.TimeWaitTimeout         = 0;
    104   ControlOption.KeepAliveProbes         = 4;
    105   ControlOption.KeepAliveTime           = 0;
    106   ControlOption.KeepAliveInterval       = 0;
    107   ControlOption.EnableNagle             = FALSE;
    108   ControlOption.EnableTimeStamp         = FALSE;
    109   ControlOption.EnableWindowScaling     = TRUE;
    110   ControlOption.EnableSelectiveAck      = FALSE;
    111   ControlOption.EnablePathMtuDiscovery  = FALSE;
    112 
    113   Tcp4ConfigData.TypeOfService          = 8;
    114   Tcp4ConfigData.TimeToLive             = 255;
    115   Tcp4ConfigData.ControlOption          = &ControlOption;
    116 
    117   AccessPoint = &Tcp4ConfigData.AccessPoint;
    118 
    119   AccessPoint->UseDefaultAddress = FALSE;
    120   AccessPoint->StationPort = 0;
    121   AccessPoint->RemotePort = ConfigData->RemotePort;
    122   AccessPoint->ActiveFlag = TRUE;
    123 
    124   CopyMem (&AccessPoint->StationAddress, &ConfigData->LocalIp, sizeof (EFI_IPv4_ADDRESS));
    125   CopyMem (&AccessPoint->SubnetMask, &ConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
    126   CopyMem (&AccessPoint->RemoteAddress, &ConfigData->RemoteIp, sizeof (EFI_IPv4_ADDRESS));
    127 
    128   //
    129   // Configure the TCP4 protocol.
    130   //
    131   Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData);
    132   if (EFI_ERROR (Status)) {
    133     goto ON_ERROR;
    134   }
    135 
    136   if (!EFI_IP4_EQUAL (&ConfigData->Gateway, &mZeroIp4Addr)) {
    137     //
    138     // the gateway is not zero, add the default route by hand
    139     //
    140     Status = Tcp4->Routes (Tcp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, &ConfigData->Gateway);
    141     if (EFI_ERROR (Status)) {
    142       goto ON_ERROR;
    143     }
    144   }
    145   //
    146   // Create events for variuos asynchronous operations.
    147   //
    148   Status = gBS->CreateEvent (
    149                   EVT_NOTIFY_SIGNAL,
    150                   TPL_NOTIFY,
    151                   Tcp4IoCommonNotify,
    152                   &Tcp4Io->IsConnDone,
    153                   &Tcp4Io->ConnToken.CompletionToken.Event
    154                   );
    155   if (EFI_ERROR (Status)) {
    156     goto ON_ERROR;
    157   }
    158 
    159   Status = gBS->CreateEvent (
    160                   EVT_NOTIFY_SIGNAL,
    161                   TPL_NOTIFY,
    162                   Tcp4IoCommonNotify,
    163                   &Tcp4Io->IsTxDone,
    164                   &Tcp4Io->TxToken.CompletionToken.Event
    165                   );
    166   if (EFI_ERROR (Status)) {
    167     goto ON_ERROR;
    168   }
    169 
    170   Status = gBS->CreateEvent (
    171                   EVT_NOTIFY_SIGNAL,
    172                   TPL_NOTIFY,
    173                   Tcp4IoCommonNotify,
    174                   &Tcp4Io->IsRxDone,
    175                   &Tcp4Io->RxToken.CompletionToken.Event
    176                   );
    177   if (EFI_ERROR (Status)) {
    178     goto ON_ERROR;
    179   }
    180 
    181   Status = gBS->CreateEvent (
    182                   EVT_NOTIFY_SIGNAL,
    183                   TPL_NOTIFY,
    184                   Tcp4IoCommonNotify,
    185                   &Tcp4Io->IsCloseDone,
    186                   &Tcp4Io->CloseToken.CompletionToken.Event
    187                   );
    188   if (EFI_ERROR (Status)) {
    189     goto ON_ERROR;
    190   }
    191 
    192   Tcp4Io->IsTxDone  = FALSE;
    193   Tcp4Io->IsRxDone  = FALSE;
    194 
    195   return EFI_SUCCESS;
    196 
    197 ON_ERROR:
    198 
    199   if (Tcp4Io->RxToken.CompletionToken.Event != NULL) {
    200     gBS->CloseEvent (Tcp4Io->RxToken.CompletionToken.Event);
    201   }
    202 
    203   if (Tcp4Io->TxToken.CompletionToken.Event != NULL) {
    204     gBS->CloseEvent (Tcp4Io->TxToken.CompletionToken.Event);
    205   }
    206 
    207   if (Tcp4Io->ConnToken.CompletionToken.Event != NULL) {
    208     gBS->CloseEvent (Tcp4Io->ConnToken.CompletionToken.Event);
    209   }
    210 
    211   if (Tcp4 != NULL) {
    212     Tcp4->Configure (Tcp4, NULL);
    213 
    214     gBS->CloseProtocol (
    215           Tcp4Io->Handle,
    216           &gEfiTcp4ProtocolGuid,
    217           Image,
    218           Controller
    219           );
    220   }
    221 
    222   NetLibDestroyServiceChild (
    223     Controller,
    224     Image,
    225     &gEfiTcp4ServiceBindingProtocolGuid,
    226     Tcp4Io->Handle
    227     );
    228 
    229   return Status;
    230 }
    231 
    232 /**
    233   Destroy the socket.
    234 
    235   @param[in]  Tcp4Io The Tcp4Io which wraps the socket to be destroyeds.
    236 **/
    237 VOID
    238 Tcp4IoDestroySocket (
    239   IN TCP4_IO  *Tcp4Io
    240   )
    241 {
    242   EFI_TCP4_PROTOCOL *Tcp4;
    243 
    244   Tcp4 = Tcp4Io->Tcp4;
    245 
    246   Tcp4->Configure (Tcp4, NULL);
    247 
    248   gBS->CloseEvent (Tcp4Io->TxToken.CompletionToken.Event);
    249   gBS->CloseEvent (Tcp4Io->RxToken.CompletionToken.Event);
    250   gBS->CloseEvent (Tcp4Io->ConnToken.CompletionToken.Event);
    251 
    252   gBS->CloseProtocol (
    253         Tcp4Io->Handle,
    254         &gEfiTcp4ProtocolGuid,
    255         Tcp4Io->Image,
    256         Tcp4Io->Controller
    257         );
    258 
    259   NetLibDestroyServiceChild (
    260     Tcp4Io->Controller,
    261     Tcp4Io->Image,
    262     &gEfiTcp4ServiceBindingProtocolGuid,
    263     Tcp4Io->Handle
    264     );
    265 }
    266 
    267 /**
    268   Connect to the other endpoint of the TCP socket.
    269 
    270   @param[in, out]  Tcp4Io    The Tcp4Io wrapping the TCP socket.
    271   @param[in]       Timeout   The time to wait for connection done.
    272 
    273   @retval EFI_SUCCESS          Connect to the other endpoint of the TCP socket successfully.
    274   @retval EFI_TIMEOUT          Failed to connect to the other endpoint of the TCP socket in the                               specified time period.
    275   @retval Others               Other errors as indicated.
    276 **/
    277 EFI_STATUS
    278 Tcp4IoConnect (
    279   IN OUT TCP4_IO    *Tcp4Io,
    280   IN EFI_EVENT      Timeout
    281   )
    282 {
    283   EFI_TCP4_PROTOCOL *Tcp4;
    284   EFI_STATUS        Status;
    285 
    286   Tcp4Io->IsConnDone  = FALSE;
    287   Tcp4                = Tcp4Io->Tcp4;
    288   Status              = Tcp4->Connect (Tcp4, &Tcp4Io->ConnToken);
    289   if (EFI_ERROR (Status)) {
    290     return Status;
    291   }
    292 
    293   while (!Tcp4Io->IsConnDone && EFI_ERROR (gBS->CheckEvent (Timeout))) {
    294     Tcp4->Poll (Tcp4);
    295   }
    296 
    297   if (!Tcp4Io->IsConnDone) {
    298     Status = EFI_TIMEOUT;
    299   } else {
    300     Status = Tcp4Io->ConnToken.CompletionToken.Status;
    301   }
    302 
    303   return Status;
    304 }
    305 
    306 /**
    307   Reset the socket.
    308 
    309   @param[in, out]  Tcp4Io The Tcp4Io wrapping the TCP socket.
    310 **/
    311 VOID
    312 Tcp4IoReset (
    313   IN OUT TCP4_IO  *Tcp4Io
    314   )
    315 {
    316   EFI_STATUS        Status;
    317   EFI_TCP4_PROTOCOL *Tcp4;
    318 
    319   Tcp4Io->CloseToken.AbortOnClose = TRUE;
    320   Tcp4Io->IsCloseDone             = FALSE;
    321 
    322   Tcp4 = Tcp4Io->Tcp4;
    323   Status = Tcp4->Close (Tcp4, &Tcp4Io->CloseToken);
    324   if (EFI_ERROR (Status)) {
    325     return ;
    326   }
    327 
    328   while (!Tcp4Io->IsCloseDone) {
    329     Tcp4->Poll (Tcp4);
    330   }
    331 }
    332 
    333 /**
    334   Transmit the Packet to the other endpoint of the socket.
    335 
    336   @param[in]   Tcp4Io          The Tcp4Io wrapping the TCP socket.
    337   @param[in]   Packet          The packet to transmit.
    338 
    339   @retval EFI_SUCCESS          The packet is trasmitted.
    340   @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
    341   @retval Others               Other errors as indicated.
    342 **/
    343 EFI_STATUS
    344 Tcp4IoTransmit (
    345   IN TCP4_IO  *Tcp4Io,
    346   IN NET_BUF  *Packet
    347   )
    348 {
    349   EFI_TCP4_TRANSMIT_DATA  *TxData;
    350   EFI_TCP4_PROTOCOL       *Tcp4;
    351   EFI_STATUS              Status;
    352 
    353   TxData = AllocatePool (sizeof (EFI_TCP4_TRANSMIT_DATA) + (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA));
    354   if (TxData == NULL) {
    355     return EFI_OUT_OF_RESOURCES;
    356   }
    357 
    358   TxData->Push        = TRUE;
    359   TxData->Urgent      = FALSE;
    360   TxData->DataLength  = Packet->TotalSize;
    361 
    362   //
    363   // Build the fragment table.
    364   //
    365   TxData->FragmentCount = Packet->BlockOpNum;
    366   NetbufBuildExt (Packet, (NET_FRAGMENT *) &TxData->FragmentTable[0], &TxData->FragmentCount);
    367 
    368   Tcp4Io->TxToken.Packet.TxData = TxData;
    369 
    370   //
    371   // Trasnmit the packet.
    372   //
    373   Tcp4    = Tcp4Io->Tcp4;
    374   Status  = Tcp4->Transmit (Tcp4, &Tcp4Io->TxToken);
    375   if (EFI_ERROR (Status)) {
    376     goto ON_EXIT;
    377   }
    378 
    379   while (!Tcp4Io->IsTxDone) {
    380     Tcp4->Poll (Tcp4);
    381   }
    382 
    383   Tcp4Io->IsTxDone  = FALSE;
    384 
    385   Status            = Tcp4Io->TxToken.CompletionToken.Status;
    386 
    387 ON_EXIT:
    388 
    389   FreePool (TxData);
    390 
    391   return Status;
    392 }
    393 
    394 /**
    395   Receive data from the socket.
    396 
    397   @param[in]  Tcp4Io           The Tcp4Io which wraps the socket to be destroyed.
    398   @param[in]  Packet           The buffer to hold the data copy from the soket rx buffer.
    399   @param[in]  AsyncMode        Is this receive asyncronous or not.
    400   @param[in]  Timeout          The time to wait for receiving the amount of data the Packet
    401                                can hold.
    402 
    403   @retval EFI_SUCCESS          The required amount of data is received from the socket.
    404   @retval EFI_OUT_OF_RESOURCES Failed to allocate momery.
    405   @retval EFI_TIMEOUT          Failed to receive the required amount of data in the
    406                                specified time period.
    407   @retval Others               Other errors as indicated.
    408 **/
    409 EFI_STATUS
    410 Tcp4IoReceive (
    411   IN TCP4_IO    *Tcp4Io,
    412   IN NET_BUF    *Packet,
    413   IN BOOLEAN    AsyncMode,
    414   IN EFI_EVENT  Timeout
    415   )
    416 {
    417   EFI_TCP4_PROTOCOL     *Tcp4;
    418   EFI_TCP4_RECEIVE_DATA RxData;
    419   EFI_STATUS            Status;
    420   NET_FRAGMENT          *Fragment;
    421   UINT32                FragmentCount;
    422   UINT32                CurrentFragment;
    423 
    424   FragmentCount = Packet->BlockOpNum;
    425   Fragment      = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
    426   if (Fragment == NULL) {
    427     return EFI_OUT_OF_RESOURCES;
    428   }
    429   //
    430   // Build the fragment table.
    431   //
    432   NetbufBuildExt (Packet, Fragment, &FragmentCount);
    433 
    434   RxData.FragmentCount          = 1;
    435   Tcp4Io->RxToken.Packet.RxData = &RxData;
    436   CurrentFragment               = 0;
    437   Tcp4                          = Tcp4Io->Tcp4;
    438   Status                        = EFI_SUCCESS;
    439 
    440   while (CurrentFragment < FragmentCount) {
    441     RxData.DataLength                       = Fragment[CurrentFragment].Len;
    442     RxData.FragmentTable[0].FragmentLength  = Fragment[CurrentFragment].Len;
    443     RxData.FragmentTable[0].FragmentBuffer  = Fragment[CurrentFragment].Bulk;
    444 
    445     Status = Tcp4->Receive (Tcp4, &Tcp4Io->RxToken);
    446     if (EFI_ERROR (Status)) {
    447       goto ON_EXIT;
    448     }
    449 
    450     while (!Tcp4Io->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
    451       //
    452       // Poll until some data is received or something error happens.
    453       //
    454       Tcp4->Poll (Tcp4);
    455     }
    456 
    457     if (!Tcp4Io->IsRxDone) {
    458       //
    459       // Timeout occurs, cancel the receive request.
    460       //
    461       Tcp4->Cancel (Tcp4, &Tcp4Io->RxToken.CompletionToken);
    462 
    463       Status = EFI_TIMEOUT;
    464       goto ON_EXIT;
    465     } else {
    466       Tcp4Io->IsRxDone = FALSE;
    467     }
    468 
    469     if (EFI_ERROR (Tcp4Io->RxToken.CompletionToken.Status)) {
    470       Status = Tcp4Io->RxToken.CompletionToken.Status;
    471       goto ON_EXIT;
    472     }
    473 
    474     Fragment[CurrentFragment].Len -= RxData.FragmentTable[0].FragmentLength;
    475     if (Fragment[CurrentFragment].Len == 0) {
    476       CurrentFragment++;
    477     } else {
    478       Fragment[CurrentFragment].Bulk += RxData.FragmentTable[0].FragmentLength;
    479     }
    480   }
    481 
    482 ON_EXIT:
    483   Tcp4Io->RxToken.Packet.RxData = NULL;
    484   FreePool (Fragment);
    485 
    486   return Status;
    487 }
    488