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