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