Home | History | Annotate | Download | only in EfiSocketLib
      1 /** @file
      2   Connect to and disconnect from the various network layers
      3 
      4   Copyright (c) 2011, Intel Corporation
      5   All rights reserved. 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 "Socket.h"
     16 
     17 
     18 /**
     19   Connect to the network service bindings
     20 
     21   Walk the network service protocols on the controller handle and
     22   locate any that are not in use.  Create ::ESL_SERVICE structures to
     23   manage the network layer interfaces for the socket driver.  Tag
     24   each of the network interfaces that are being used.  Finally, this
     25   routine calls ESL_SOCKET_BINDING::pfnInitialize to prepare the network
     26   interface for use by the socket layer.
     27 
     28   @param [in] BindingHandle    Handle for protocol binding.
     29   @param [in] Controller       Handle of device to work with.
     30 
     31   @retval EFI_SUCCESS          This driver is added to Controller.
     32   @retval EFI_OUT_OF_RESOURCES No more memory available.
     33   @retval EFI_UNSUPPORTED      This driver does not support this device.
     34 
     35 **/
     36 EFI_STATUS
     37 EFIAPI
     38 EslServiceConnect (
     39   IN EFI_HANDLE BindingHandle,
     40   IN EFI_HANDLE Controller
     41   )
     42 {
     43   BOOLEAN bInUse;
     44   EFI_STATUS ExitStatus;
     45   UINTN LengthInBytes;
     46   UINT8 * pBuffer;
     47   CONST ESL_SOCKET_BINDING * pEnd;
     48   VOID * pJunk;
     49   ESL_SERVICE ** ppServiceListHead;
     50   ESL_SERVICE * pService;
     51   CONST ESL_SOCKET_BINDING * pSocketBinding;
     52   EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;
     53   EFI_STATUS Status;
     54   EFI_TPL TplPrevious;
     55 
     56   DBG_ENTER ( );
     57 
     58   //
     59   //  Assume the list is empty
     60   //
     61   ExitStatus = EFI_UNSUPPORTED;
     62   bInUse = FALSE;
     63 
     64   //
     65   //  Walk the list of network connection points
     66   //
     67   pSocketBinding = &cEslSocketBinding[0];
     68   pEnd = &pSocketBinding[ cEslSocketBindingEntries ];
     69   while ( pEnd > pSocketBinding ) {
     70     //
     71     //  Determine if the controller supports the network protocol
     72     //
     73     Status = gBS->OpenProtocol (
     74                     Controller,
     75                     pSocketBinding->pNetworkBinding,
     76                     (VOID**)&pServiceBinding,
     77                     BindingHandle,
     78                     Controller,
     79                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
     80                     );
     81     if ( !EFI_ERROR ( Status )) {
     82       //
     83       //  Determine if the socket layer is already connected
     84       //
     85       Status = gBS->OpenProtocol (
     86                       Controller,
     87                       (EFI_GUID *)pSocketBinding->pTagGuid,
     88                       &pJunk,
     89                       BindingHandle,
     90                       Controller,
     91                       EFI_OPEN_PROTOCOL_GET_PROTOCOL
     92                       );
     93       if ( EFI_UNSUPPORTED == Status ) {
     94         //
     95         //  Allocate a service structure since the tag is not present
     96         //
     97         LengthInBytes = sizeof ( *pService );
     98         Status = gBS->AllocatePool (
     99                         EfiRuntimeServicesData,
    100                         LengthInBytes,
    101                         (VOID **) &pService
    102                         );
    103         if ( !EFI_ERROR ( Status )) {
    104           DEBUG (( DEBUG_POOL | DEBUG_INIT,
    105                     "0x%08x: Allocate pService, %d bytes\r\n",
    106                     pService,
    107                     LengthInBytes ));
    108 
    109           //
    110           //  Set the structure signature and service binding
    111           //
    112           ZeroMem ( pService, LengthInBytes );
    113           pService->Signature = SERVICE_SIGNATURE;
    114           pService->pSocketBinding = pSocketBinding;
    115           pService->Controller = Controller;
    116           pService->pServiceBinding = pServiceBinding;
    117 
    118           //
    119           //  Mark the controller in use
    120           //
    121           if ( !bInUse ) {
    122             Status = gBS->InstallMultipleProtocolInterfaces (
    123                             &Controller,
    124                             &gEfiCallerIdGuid,
    125                             NULL,
    126                             NULL
    127                             );
    128             if ( !EFI_ERROR ( Status )) {
    129               DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
    130                         "Installed: gEfiCallerIdGuid on   0x%08x\r\n",
    131                         Controller ));
    132               bInUse = TRUE;
    133             }
    134             else {
    135               if ( EFI_INVALID_PARAMETER == Status ) {
    136                 Status = EFI_SUCCESS;
    137               }
    138             }
    139           }
    140           if ( !EFI_ERROR ( Status )) {
    141             //
    142             //  Mark the network service protocol in use
    143             //
    144             Status = gBS->InstallMultipleProtocolInterfaces (
    145                             &Controller,
    146                             pSocketBinding->pTagGuid,
    147                             pService,
    148                             NULL
    149                             );
    150             if ( !EFI_ERROR ( Status )) {
    151               DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
    152                         "Installed: %s TagGuid on   0x%08x\r\n",
    153                         pSocketBinding->pName,
    154                         Controller ));
    155 
    156               //
    157               //  Synchronize with the socket layer
    158               //
    159               RAISE_TPL ( TplPrevious, TPL_SOCKETS );
    160 
    161               //
    162               //  Connect the service to the list
    163               //
    164               pBuffer = (UINT8 *)&mEslLayer;
    165               pBuffer = &pBuffer[ pSocketBinding->ServiceListOffset ];
    166               ppServiceListHead = (ESL_SERVICE **)pBuffer;
    167               pService->pNext = *ppServiceListHead;
    168               *ppServiceListHead = pService;
    169 
    170               //
    171               //  Release the socket layer synchronization
    172               //
    173               RESTORE_TPL ( TplPrevious );
    174 
    175               //
    176               //  At least one service was made available
    177               //
    178               ExitStatus = EFI_SUCCESS;
    179             }
    180             else {
    181               DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
    182                         "ERROR - Failed to install %s TagGuid on 0x%08x, Status: %r\r\n",
    183                         pSocketBinding->pName,
    184                         Controller,
    185                         Status ));
    186             }
    187 
    188             if ( EFI_ERROR ( Status )) {
    189               //
    190               //  The controller is no longer in use
    191               //
    192               if ( bInUse ) {
    193                 gBS->UninstallMultipleProtocolInterfaces (
    194                           Controller,
    195                           &gEfiCallerIdGuid,
    196                           NULL,
    197                           NULL );
    198                 DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
    199                             "Removed:   gEfiCallerIdGuid from 0x%08x\r\n",
    200                             Controller ));
    201               }
    202             }
    203           }
    204           else {
    205             DEBUG (( DEBUG_ERROR | DEBUG_INIT,
    206                       "ERROR - Failed to install gEfiCallerIdGuid on 0x%08x, Status: %r\r\n",
    207                       Controller,
    208                       Status ));
    209           }
    210 
    211           //
    212           //  Release the service if necessary
    213           //
    214           if ( EFI_ERROR ( Status )) {
    215             gBS->FreePool ( pService );
    216             DEBUG (( DEBUG_POOL | DEBUG_INIT,
    217                       "0x%08x: Free pService, %d bytes\r\n",
    218                       pService,
    219                       sizeof ( *pService )));
    220             pService = NULL;
    221           }
    222         }
    223         else {
    224           DEBUG (( DEBUG_ERROR | DEBUG_INIT,
    225                     "ERROR - Failed service allocation, Status: %r\r\n",
    226                     Status ));
    227           ExitStatus = EFI_OUT_OF_RESOURCES;
    228           break;
    229         }
    230       }
    231     }
    232 
    233     //
    234     //  Set the next network protocol
    235     //
    236     pSocketBinding += 1;
    237   }
    238 
    239   //
    240   //  Display the driver start status
    241   //
    242   DBG_EXIT_STATUS ( ExitStatus );
    243   return ExitStatus;
    244 }
    245 
    246 
    247 /**
    248   Shutdown the connections to the network layer by locating the
    249   tags on the network interfaces established by ::EslServiceConnect.
    250   This routine shutdowns any activity on the network interface and
    251   then frees the ::ESL_SERVICE structures.
    252 
    253   @param [in] BindingHandle    Handle for protocol binding.
    254   @param [in] Controller       Handle of device to stop driver on.
    255 
    256   @retval EFI_SUCCESS          This driver is removed Controller.
    257   @retval EFI_DEVICE_ERROR     The device could not be stopped due to a device error.
    258   @retval other                This driver was not removed from this device.
    259 
    260 **/
    261 EFI_STATUS
    262 EFIAPI
    263 EslServiceDisconnect (
    264   IN  EFI_HANDLE BindingHandle,
    265   IN  EFI_HANDLE Controller
    266   )
    267 {
    268   UINT8 * pBuffer;
    269   CONST ESL_SOCKET_BINDING * pEnd;
    270   ESL_PORT * pPort;
    271   ESL_SERVICE * pPreviousService;
    272   ESL_SERVICE * pService;
    273   ESL_SERVICE ** ppServiceListHead;
    274   CONST ESL_SOCKET_BINDING * pSocketBinding;
    275   EFI_STATUS Status;
    276   EFI_TPL TplPrevious;
    277 
    278   DBG_ENTER ( );
    279 
    280   //
    281   //  Walk the list of network connection points in reverse order
    282   //
    283   pEnd = &cEslSocketBinding[0];
    284   pSocketBinding = &pEnd[ cEslSocketBindingEntries ];
    285   while ( pEnd < pSocketBinding ) {
    286     //
    287     //  Set the next network protocol
    288     //
    289     pSocketBinding -= 1;
    290 
    291     //
    292     //  Determine if the driver connected
    293     //
    294     Status = gBS->OpenProtocol (
    295                     Controller,
    296                     (EFI_GUID *)pSocketBinding->pTagGuid,
    297                     (VOID **)&pService,
    298                     BindingHandle,
    299                     Controller,
    300                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    301                     );
    302     if ( !EFI_ERROR ( Status )) {
    303 
    304       //
    305       //  Synchronize with the socket layer
    306       //
    307       RAISE_TPL ( TplPrevious, TPL_SOCKETS );
    308 
    309       //
    310       //  Walk the list of ports
    311       //
    312       pPort = pService->pPortList;
    313       while ( NULL != pPort ) {
    314         //
    315         //  Remove the port from the port list
    316         //
    317         pPort->pService = NULL;
    318         pService->pPortList = pPort->pLinkService;
    319 
    320         //
    321         //  Close the port
    322         //
    323         EslSocketPortCloseStart ( pPort,
    324                                   TRUE,
    325                                   DEBUG_POOL | DEBUG_INIT );
    326 
    327         //
    328         //  Set the next port
    329         //
    330         pPort = pService->pPortList;
    331       }
    332 
    333       //
    334       //  Remove the service from the service list
    335       //
    336       pBuffer = (UINT8 *)&mEslLayer;
    337       pBuffer = &pBuffer[ pService->pSocketBinding->ServiceListOffset ];
    338       ppServiceListHead = (ESL_SERVICE **)pBuffer;
    339       pPreviousService = *ppServiceListHead;
    340       if ( pService == pPreviousService ) {
    341         //
    342         //  Remove the service from the beginning of the list
    343         //
    344         *ppServiceListHead = pService->pNext;
    345       }
    346       else {
    347         //
    348         //  Remove the service from the middle of the list
    349         //
    350         while ( NULL != pPreviousService ) {
    351           if ( pService == pPreviousService->pNext ) {
    352             pPreviousService->pNext = pService->pNext;
    353             break;
    354           }
    355           pPreviousService = pPreviousService->pNext;
    356         }
    357       }
    358 
    359       //
    360       //  Release the socket layer synchronization
    361       //
    362       RESTORE_TPL ( TplPrevious );
    363 
    364       //
    365       //  Break the driver connection
    366       //
    367       Status = gBS->UninstallMultipleProtocolInterfaces (
    368                 Controller,
    369                 pSocketBinding->pTagGuid,
    370                 pService,
    371                 NULL );
    372       if ( !EFI_ERROR ( Status )) {
    373         DEBUG (( DEBUG_POOL | DEBUG_INIT,
    374                     "Removed:   %s TagGuid from 0x%08x\r\n",
    375                     pSocketBinding->pName,
    376                     Controller ));
    377       }
    378       else {
    379         DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INIT,
    380                     "ERROR - Failed to removed %s TagGuid from 0x%08x, Status: %r\r\n",
    381                     pSocketBinding->pName,
    382                     Controller,
    383                     Status ));
    384       }
    385 
    386       //
    387       //  Free the service structure
    388       //
    389       Status = gBS->FreePool ( pService );
    390       if ( !EFI_ERROR ( Status )) {
    391         DEBUG (( DEBUG_POOL | DEBUG_INIT,
    392                   "0x%08x: Free pService, %d bytes\r\n",
    393                   pService,
    394                   sizeof ( *pService )));
    395       }
    396       else {
    397         DEBUG (( DEBUG_POOL | DEBUG_INIT,
    398                   "ERROR - Failed to free pService 0x%08x, Status: %r\r\n",
    399                   pService,
    400                   Status ));
    401       }
    402       pService = NULL;
    403     }
    404   }
    405 
    406   //
    407   //  The controller is no longer in use
    408   //
    409   gBS->UninstallMultipleProtocolInterfaces (
    410             Controller,
    411             &gEfiCallerIdGuid,
    412             NULL,
    413             NULL );
    414   DEBUG (( DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,
    415               "Removed:   gEfiCallerIdGuid from 0x%08x\r\n",
    416               Controller ));
    417 
    418   //
    419   //  The driver is disconnected from the network controller
    420   //
    421   Status = EFI_SUCCESS;
    422 
    423   //
    424   //  Display the driver start status
    425   //
    426   DBG_EXIT_STATUS ( Status );
    427   return Status;
    428 }
    429 
    430 
    431 
    432 /**
    433 Initialize the service layer
    434 
    435 @param [in] ImageHandle       Handle for the image.
    436 
    437 **/
    438 VOID
    439 EFIAPI
    440 EslServiceLoad (
    441   IN EFI_HANDLE ImageHandle
    442   )
    443 {
    444   ESL_LAYER * pLayer;
    445 
    446   //
    447   //  Save the image handle
    448   //
    449   pLayer = &mEslLayer;
    450   ZeroMem ( pLayer, sizeof ( *pLayer ));
    451   pLayer->Signature = LAYER_SIGNATURE;
    452   pLayer->ImageHandle = ImageHandle;
    453 
    454   //
    455   //  Connect the service binding protocol to the image handle
    456   //
    457   pLayer->pServiceBinding = &mEfiServiceBinding;
    458 }
    459 
    460 
    461 /**
    462   Shutdown the service layer
    463 
    464 **/
    465 VOID
    466 EFIAPI
    467 EslServiceUnload (
    468   VOID
    469   )
    470 {
    471   ESL_LAYER * pLayer;
    472 
    473   //
    474   //  Undo the work by ServiceLoad
    475   //
    476   pLayer = &mEslLayer;
    477   pLayer->ImageHandle = NULL;
    478   pLayer->pServiceBinding = NULL;
    479 }
    480