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 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 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 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 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