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