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