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
EslServiceConnect(IN EFI_HANDLE BindingHandle,IN EFI_HANDLE Controller)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
EslServiceDisconnect(IN EFI_HANDLE BindingHandle,IN EFI_HANDLE Controller)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
EslServiceLoad(IN EFI_HANDLE ImageHandle)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
EslServiceUnload(VOID)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