]> git.proxmox.com Git - mirror_edk2.git/blob - RedfishPkg/RedfishDiscoverDxe/RedfishDiscoverDxe.c
NetworkPkg/IScsiDxe: re-set session-level authentication state before login
[mirror_edk2.git] / RedfishPkg / RedfishDiscoverDxe / RedfishDiscoverDxe.c
1 /** @file
2
3 The implementation of EFI Redfidh Discover Protocol.
4
5 (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "RedfishDiscoverInternal.h"
12
13 LIST_ENTRY mRedfishDiscoverList;
14 LIST_ENTRY mRedfishInstanceList;
15 EFI_SMBIOS_PROTOCOL *mSmbios = NULL;
16
17 UINTN mNumNetworkInterface = 0;
18 UINTN mNumRestExInstance = 0;
19 LIST_ENTRY mEfiRedfishDiscoverNetworkInterface;
20 LIST_ENTRY mEfiRedfishDiscoverRestExInstance;
21
22 EFI_GUID mRedfishDiscoverTcp4InstanceGuid = EFI_REDFISH_DISCOVER_TCP4_INSTANCE_GUID;
23 EFI_GUID mRedfishDiscoverTcp6InstanceGuid = EFI_REDFISH_DISCOVER_TCP6_INSTANCE_GUID;
24 EFI_GUID mRedfishDiscoverRestExInstanceGuid = EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_GUID;
25
26 EFI_HANDLE EfiRedfishDiscoverProtocolHandle = NULL;
27
28 EFI_STATUS
29 EFIAPI
30 Tcp4GetSubnetInfo (
31 IN EFI_HANDLE ImageHandle,
32 IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
33 );
34
35 EFI_STATUS
36 EFIAPI
37 Tcp6GetSubnetInfo (
38 IN EFI_HANDLE ImageHandle,
39 IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
40 );
41
42 static REDFISH_DISCOVER_REQUIRED_PROTOCOL gRequiredProtocol[] = {
43 {
44 ProtocolTypeTcp4,
45 L"TCP4 Service Binding Protocol",
46 &gEfiTcp4ProtocolGuid,
47 &gEfiTcp4ServiceBindingProtocolGuid,
48 &mRedfishDiscoverTcp4InstanceGuid,
49 Tcp4GetSubnetInfo
50 },
51 {
52 ProtocolTypeTcp6,
53 L"TCP6 Service Binding Protocol",
54 &gEfiTcp6ProtocolGuid,
55 &gEfiTcp6ServiceBindingProtocolGuid,
56 &mRedfishDiscoverTcp6InstanceGuid,
57 Tcp6GetSubnetInfo
58 },
59 {
60 ProtocolTypeRestEx,
61 L"REST EX Service Binding Protocol",
62 &gEfiRestExProtocolGuid,
63 &gEfiRestExServiceBindingProtocolGuid,
64 &mRedfishDiscoverRestExInstanceGuid,
65 NULL
66 }
67 };
68
69 /**
70 This function creates REST EX instance for the found Resfish service.
71 by known owner handle.
72
73 @param[in] Instance EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
74 @param[in] Token Client token.
75
76 @retval NULL Instance not found.
77 @retval EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE The instance owned by this owner.
78
79 **/
80 EFI_STATUS
81 CreateRestExInstance (
82 IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
83 IN EFI_REDFISH_DISCOVERED_TOKEN *Token
84 )
85 {
86 EFI_STATUS Status;
87
88 Status = RestExLibCreateChild (
89 Instance->Owner,
90 FixedPcdGetBool (PcdRedfishDiscoverAccessModeInBand)? EfiRestExServiceInBandAccess: EfiRestExServiceOutOfBandAccess,
91 EfiRestExConfigHttp,
92 EfiRestExServiceRedfish,
93 &Token->DiscoverList.RedfishInstances->Information.RedfishRestExHandle
94 );
95 return Status;
96 }
97
98 /**
99 This function gets EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
100 by known owner handle.
101
102 @param[in] ImageHandle Image handle owns EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
103 @param[in] TargetNetworkInterface Target network interface used by this EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
104 @param[in] DiscoverFlags EFI_REDFISH_DISCOVER_FLAG
105
106 @retval NULL Instance not found.
107 @retval EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE The instance owned by this owner.
108
109 **/
110 EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *
111 GetInstanceByOwner (
112 IN EFI_HANDLE ImageHandle,
113 IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *TargetNetworkInterface,
114 IN EFI_REDFISH_DISCOVER_FLAG DiscoverFlags
115 )
116 {
117 EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *ThisInstance;
118
119 if (IsListEmpty (&mRedfishDiscoverList)) {
120 return NULL;
121 }
122 ThisInstance =
123 (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)GetFirstNode (&mRedfishDiscoverList);
124 while (TRUE) {
125 if ((ThisInstance->Owner == ImageHandle) &&
126 (ThisInstance->DiscoverFlags == DiscoverFlags) &&
127 (ThisInstance->NetworkInterface == TargetNetworkInterface)) {
128 return ThisInstance;
129 }
130 if (IsNodeAtEnd (&mRedfishDiscoverList, &ThisInstance->Entry)) {
131 break;
132 }
133 ThisInstance =
134 (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)GetNextNode (&mRedfishDiscoverList, &ThisInstance->Entry);
135 };
136 return NULL;
137 }
138
139 /**
140 This function gets the subnet information of this TCP4 instance.
141
142 @param[in] ImageHandle EFI handle with this image.
143 @param[in] Instance Instance of Network interface.
144 @retval EFI_STATUS Get subnet information successfully.
145 @retval Otherwise Fail to get subnet information.
146 **/
147 EFI_STATUS
148 EFIAPI
149 Tcp4GetSubnetInfo (
150 IN EFI_HANDLE ImageHandle,
151 IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
152 )
153 {
154 EFI_STATUS Status;
155 EFI_TCP4_PROTOCOL *Tcp4;
156 EFI_TCP4_CONFIG_DATA Tcp4CfgData;
157 EFI_TCP4_OPTION Tcp4Option;
158 EFI_IP4_MODE_DATA IpModedata;
159 UINT8 SubnetMaskIndex;
160 UINT8 BitMask;
161 UINT8 PrefixLength;
162 BOOLEAN GotPrefixLength;
163
164 if (Instance == NULL) {
165 return EFI_INVALID_PARAMETER;
166 }
167 Tcp4 = (EFI_TCP4_PROTOCOL *)Instance->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
168
169 ZeroMem ((VOID *)&Tcp4CfgData, sizeof (EFI_TCP4_CONFIG_DATA));
170 ZeroMem ((VOID *)&Tcp4Option, sizeof (EFI_TCP4_OPTION));
171 // Give a local host IP address just for getting subnet information.
172 Tcp4CfgData.AccessPoint.UseDefaultAddress = TRUE;
173 Tcp4CfgData.AccessPoint.RemoteAddress.Addr [0] = 127;
174 Tcp4CfgData.AccessPoint.RemoteAddress.Addr [1] = 0;
175 Tcp4CfgData.AccessPoint.RemoteAddress.Addr [2] = 0;
176 Tcp4CfgData.AccessPoint.RemoteAddress.Addr [3] = 1;
177 Tcp4CfgData.AccessPoint.RemotePort = 80;
178 Tcp4CfgData.AccessPoint.ActiveFlag = TRUE;
179
180 Tcp4CfgData.ControlOption = &Tcp4Option;
181 Tcp4Option.ReceiveBufferSize = 65535;
182 Tcp4Option.SendBufferSize = 65535;
183 Tcp4Option.MaxSynBackLog = 5;
184 Tcp4Option.ConnectionTimeout = 60;
185 Tcp4Option.DataRetries = 12;
186 Tcp4Option.FinTimeout = 2;
187 Tcp4Option.KeepAliveProbes = 6;
188 Tcp4Option.KeepAliveTime = 7200;
189 Tcp4Option.KeepAliveInterval = 30;
190 Tcp4Option.EnableNagle = TRUE;
191 Status = Tcp4->Configure (Tcp4, &Tcp4CfgData);
192 if (EFI_ERROR (Status)) {
193 DEBUG ((DEBUG_ERROR, "%a: Can't get subnet information\n", __FUNCTION__));
194 return Status;
195 }
196 Status = Tcp4->GetModeData (Tcp4, NULL, NULL, &IpModedata, NULL, NULL);
197 if (EFI_ERROR (Status)) {
198 DEBUG ((DEBUG_ERROR, "%a: Can't get IP mode data information\n", __FUNCTION__));
199 return Status;
200 }
201 IP4_COPY_ADDRESS (&Instance->SubnetMask, &IpModedata.ConfigData.SubnetMask);
202 Instance->SubnetAddr.v4.Addr [0] = IpModedata.ConfigData.StationAddress.Addr [0] & Instance->SubnetMask.v4.Addr [0];
203 Instance->SubnetAddr.v4.Addr [1] = IpModedata.ConfigData.StationAddress.Addr [1] & Instance->SubnetMask.v4.Addr [1];
204 Instance->SubnetAddr.v4.Addr [2] = IpModedata.ConfigData.StationAddress.Addr [2] & Instance->SubnetMask.v4.Addr [2];
205 Instance->SubnetAddr.v4.Addr [3] = IpModedata.ConfigData.StationAddress.Addr [3] & Instance->SubnetMask.v4.Addr [3];
206 //
207 // Calculate the subnet mask prefix.
208 //
209 GotPrefixLength = FALSE;
210 PrefixLength = 0;
211 SubnetMaskIndex = 0;
212 while (GotPrefixLength == FALSE && SubnetMaskIndex < 4) {
213 BitMask = 0x80;
214 while (BitMask != 0) {
215 if ((Instance->SubnetMask.v4.Addr [SubnetMaskIndex] & BitMask) != 0) {
216 PrefixLength ++;
217 } else {
218 GotPrefixLength = TRUE;
219 break;
220 }
221 BitMask = BitMask >> 1;
222 };
223 SubnetMaskIndex ++;
224 };
225 Instance->SubnetPrefixLength = PrefixLength;
226 return EFI_SUCCESS;
227 }
228
229 /**
230 This function gets the subnet information of this TCP6 instance.
231
232 @param[in] ImageHandle EFI handle with this image.
233 @param[in] Instance Instance of Network interface.
234 @retval EFI_STATUS Get subnet information successfully.
235 @retval Otherwise Fail to get subnet information.
236 **/
237 EFI_STATUS
238 EFIAPI
239 Tcp6GetSubnetInfo (
240 IN EFI_HANDLE ImageHandle,
241 IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance
242 )
243 {
244 EFI_STATUS Status;
245 EFI_TCP6_PROTOCOL *Tcp6;
246 EFI_IP6_MODE_DATA IpModedata;
247
248 if (Instance == NULL) {
249 return EFI_INVALID_PARAMETER;
250 }
251 Tcp6 = (EFI_TCP6_PROTOCOL *)Instance->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
252
253 Status = Tcp6->GetModeData (Tcp6, NULL, NULL, &IpModedata, NULL, NULL);
254 if (EFI_ERROR (Status)) {
255 DEBUG ((DEBUG_ERROR, "%a: Can't get IP mode data information\n"));
256 return Status;
257 }
258 if (IpModedata.AddressCount == 0) {
259 DEBUG ((DEBUG_INFO, "%a: No IPv6 address configured.\n"));
260 }
261 if (Instance->SubnetAddrInfoIPv6 != NULL) {
262 FreePool (Instance->SubnetAddrInfoIPv6);
263 }
264 Instance->SubnetAddrInfoIPv6 = AllocateZeroPool (IpModedata.AddressCount * sizeof (EFI_IP6_ADDRESS_INFO));
265 if (Instance->SubnetAddrInfoIPv6 == NULL) {
266 DEBUG ((DEBUG_ERROR, "%a: Failed to allocate memory fir IPv6 subnet address information\n"));
267 return EFI_OUT_OF_RESOURCES;
268 }
269 Instance->SubnetAddrInfoIPv6Number = IpModedata.AddressCount;
270 CopyMem (
271 (VOID *)Instance->SubnetAddrInfoIPv6,
272 (VOID *)&IpModedata.AddressList,
273 IpModedata.AddressCount * sizeof (EFI_IP6_ADDRESS_INFO)
274 );
275 FreePool (IpModedata.AddressList);
276 return EFI_SUCCESS;
277 }
278
279 /**
280 This function searches EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
281 instance with the given EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
282
283 @param[in] TargetNetworkInterface EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
284 NULL for all EFI_REDFISH_DISCOVER_NETWORK_INTERFACEs.
285
286 @retval Non-NULL EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL is returned.
287 @retval NULL Non of EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance is returned.
288 **/
289 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *
290 GetTargetNetworkInterfaceInternal (
291 IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *TargetNetworkInterface
292 )
293 {
294 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
295
296 ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
297 while (TRUE) {
298 if (CompareMem((VOID *)&ThisNetworkInterface->MacAddress, &TargetNetworkInterface->MacAddress, ThisNetworkInterface->HwAddressSize) == 0) {
299 return ThisNetworkInterface;
300 }
301 if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
302 return NULL;
303 }
304 ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
305 };
306 return NULL;
307 }
308
309 /**
310 This function validate if target network interface is ready for discovering
311 Redfish service.
312
313 @param[in] TargetNetworkInterface EFI_REDFISH_DISCOVER_NETWORK_INTERFACE.
314 NULL for all EFI_REDFISH_DISCOVER_NETWORK_INTERFACEs.
315 @param[in] Flags EFI_REDFISH_DISCOVER_FLAG
316
317 @retval EFI_SUCCESS Target network interface is ready to use.
318 @retval EFI_UNSUPPORTED Target network interface is not ready to use.
319 **/
320 EFI_STATUS
321 ValidateTargetNetworkInterface (
322 IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *TargetNetworkInterface,
323 IN EFI_REDFISH_DISCOVER_FLAG Flags
324 )
325 {
326 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
327
328 if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface) && TargetNetworkInterface == NULL) {
329 return EFI_UNSUPPORTED;
330 }
331 if (TargetNetworkInterface == NULL) {
332 return EFI_SUCCESS; // Return EFI_SUCCESS if no network interface is specified.
333 }
334
335 ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode(&mEfiRedfishDiscoverNetworkInterface);
336 while (TRUE) {
337 if (CompareMem((VOID *)&ThisNetworkInterface->MacAddress, &TargetNetworkInterface->MacAddress, ThisNetworkInterface->HwAddressSize) == 0) {
338 break;
339 }
340 if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
341 return EFI_UNSUPPORTED;
342 }
343 ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
344 };
345 if ((Flags & EFI_REDFISH_DISCOVER_SSDP) != 0) {
346 // Validate if UDP4/6 is supported on the given network interface.
347 // SSDP is not supported.
348
349 return EFI_SUCCESS;
350 }
351 if (ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle == NULL) {
352 return EFI_UNSUPPORTED; // The required protocol on this network interface is not found.
353 }
354 return EFI_SUCCESS;
355 }
356 /**
357 This function returns number of network interface instance.
358
359 @retval UINTN Number of network interface instances.
360 **/
361 UINTN
362 NumberOfNetworkInterface (VOID)
363 {
364 UINTN Num;
365 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
366
367 if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
368 return 0;
369 }
370
371 Num = 1;
372 ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
373 while (TRUE) {
374 if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
375 break;
376 }
377 ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
378 Num ++;
379 };
380 return Num;
381 }
382
383 /**
384 This function checks the IP version supported on this
385 netwoek interface.
386
387 @param[in] ThisNetworkInterface EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
388
389 @retval TRUE Is IPv6, otherwise IPv4.
390
391 **/
392 BOOLEAN
393 CheckIsIpVersion6 (
394 IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface
395 )
396 {
397 if (ThisNetworkInterface->NetworkProtocolType == ProtocolTypeTcp6) {
398 return TRUE;
399 }
400 return FALSE;
401 }
402
403 /**
404 This function discover Redfish service through SMBIOS host interface.
405
406 @param[in] Instance EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE
407
408 @retval EFI_SUCCESS Redfish service is discovered through SMBIOS Host interface.
409 @retval Others Fail to discover Redfish service throught SMBIOS host interface
410
411 **/
412 EFI_STATUS
413 DiscoverRedfishHostInterface (IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance)
414 {
415 EFI_STATUS Status;
416 REDFISH_OVER_IP_PROTOCOL_DATA *Data;
417 REDFISH_INTERFACE_DATA *DeviceDescriptor;
418 CHAR8 UuidStr[sizeof"00000000-0000-0000-0000-000000000000" + 1];
419 CHAR16 Ipv6Str [sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + 1];
420 CHAR8 RedfishServiceLocateStr [sizeof"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + 1];
421 UINTN StrSize;
422 UINTN MacCompareStstus;
423 BOOLEAN IsHttps;
424
425 Data = NULL;
426 DeviceDescriptor = NULL;
427
428 if (mSmbios == NULL) {
429 Status = gBS->LocateProtocol(&gEfiSmbiosProtocolGuid, NULL, (VOID **)&mSmbios);
430 if (EFI_ERROR (Status)) {
431 return Status;
432 }
433 }
434 Status = RedfishGetHostInterfaceProtocolData (mSmbios, &DeviceDescriptor, &Data); // Search for SMBIOS type 42h
435 if (!EFI_ERROR (Status) && Data != NULL && DeviceDescriptor != NULL) {
436 //
437 // Chceck if we can reach out Redfish service using this network interface.
438 // Check with MAC address using Device Descroptor Data Device Type 04 and Type 05.
439 // Those two types of Redfish host interface device has MAC information.
440 //
441 if (DeviceDescriptor->DeviceType == REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2) {
442 MacCompareStstus = CompareMem(&Instance->NetworkInterface->MacAddress, &DeviceDescriptor->DeviceDescriptor.PciPcieDeviceV2.MacAddress, 6);
443 } else if (DeviceDescriptor->DeviceType == REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2){
444 MacCompareStstus = CompareMem(&Instance->NetworkInterface->MacAddress, &DeviceDescriptor->DeviceDescriptor.UsbDeviceV2.MacAddress, 6);
445 } else {
446 return EFI_UNSUPPORTED;
447 }
448 if (MacCompareStstus != 0) {
449 return EFI_UNSUPPORTED;
450 }
451
452 if (Data->RedfishServiceIpAddressFormat == 1) {
453 IP4_COPY_ADDRESS ((VOID *)&Instance->TargetIpAddress.v4, (VOID *)Data->RedfishServiceIpAddress);
454 } else {
455 IP6_COPY_ADDRESS ((VOID *)&Instance->TargetIpAddress.v6, (VOID *)Data->RedfishServiceIpAddress);
456 }
457
458 if (Instance->HostIntfValidation) {
459 DEBUG ((DEBUG_ERROR,"%a:Send UPnP unicast SSDP to validate this Redfish Host Interface is not supported.\n", __FUNCTION__));
460 Status = EFI_UNSUPPORTED;
461 } else {
462 //
463 // Add this istance to list without detial information of Redfish
464 // service.
465 //
466 IsHttps = FALSE;
467 if (Data->RedfishServiceIpPort == 443) {
468 IsHttps = TRUE;
469 }
470 StrSize = sizeof(UuidStr);
471 AsciiSPrint(UuidStr, StrSize, "%g", &Data->ServiceUuid);
472 //
473 // Generate Redfish service location string.
474 //
475 if (Data->RedfishServiceIpAddressFormat == REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP6) {
476 NetLibIp6ToStr((IPv6_ADDRESS *)&Data->RedfishServiceIpAddress, Ipv6Str, sizeof (Ipv6Str));
477 if (Data->RedfishServiceIpPort == 0 || IsHttps == TRUE) {
478 AsciiSPrintUnicodeFormat (
479 RedfishServiceLocateStr,
480 sizeof (RedfishServiceLocateStr),
481 L"%s",
482 Ipv6Str
483 );
484 } else {
485 AsciiSPrintUnicodeFormat(
486 RedfishServiceLocateStr,
487 sizeof (RedfishServiceLocateStr),
488 L"[%s]:%d",
489 Ipv6Str,
490 Data->RedfishServiceIpPort
491 );
492 }
493 } else {
494 if (Data->RedfishServiceIpPort == 0 || IsHttps == TRUE) {
495 AsciiSPrint(
496 RedfishServiceLocateStr,
497 sizeof (RedfishServiceLocateStr),
498 "%d.%d.%d.%d",
499 Data->RedfishServiceIpAddress [0],
500 Data->RedfishServiceIpAddress [1],
501 Data->RedfishServiceIpAddress [2],
502 Data->RedfishServiceIpAddress [3]
503 );
504 } else {
505 AsciiSPrint(
506 RedfishServiceLocateStr,
507 sizeof (RedfishServiceLocateStr),
508 "%d.%d.%d.%d:%d",
509 Data->RedfishServiceIpAddress [0],
510 Data->RedfishServiceIpAddress [1],
511 Data->RedfishServiceIpAddress [2],
512 Data->RedfishServiceIpAddress [3],
513 Data->RedfishServiceIpPort
514 );
515 }
516 }
517 Status = AddAndSignalNewRedfishService (
518 Instance,
519 NULL,
520 RedfishServiceLocateStr,
521 UuidStr,
522 NULL,
523 NULL,
524 NULL,
525 NULL,
526 IsHttps
527 );
528 }
529 }
530 return Status;
531 }
532
533 /**
534 The function adds a new found Redfish service to internal list and
535 notify client.
536
537 @param[in] Instance EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.
538 @param[in] RedfishVersion Redfish version.
539 @param[in] RedfishLocation Redfish location.
540 @param[in] Uuid Service UUID string.
541 @param[in] Os OS string.
542 @param[in] OsVer OS version string.
543 @param[in] Product Product string.
544 @param[in] ProductVer Product verison string.
545 @param[in] UseHttps Redfish service requires secured connection.
546 @retval EFI_SUCCESS Redfish service is added to list successfully.
547
548 **/
549 EFI_STATUS
550 AddAndSignalNewRedfishService (
551 IN EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance,
552 IN UINTN *RedfishVersion OPTIONAL,
553 IN CHAR8 *RedfishLocation OPTIONAL,
554 IN CHAR8 *Uuid OPTIONAL,
555 IN CHAR8 *Os OPTIONAL,
556 IN CHAR8 *OsVer OPTIONAL,
557 IN CHAR8 *Product OPTIONAL,
558 IN CHAR8 *ProductVer OPTIONAL,
559 IN BOOLEAN UseHttps
560 )
561 {
562 BOOLEAN NewFound;
563 BOOLEAN InfoRefresh;
564 BOOLEAN RestExOpened;
565 BOOLEAN DeleteRestEx;
566 EFI_STATUS Status;
567 EFI_REDFISH_DISCOVERED_INTERNAL_LIST *DiscoveredList;
568 EFI_REDFISH_DISCOVERED_INSTANCE *DiscoveredInstance;
569 CHAR16 *Char16Uuid;
570 EFI_REST_EX_PROTOCOL *RestEx;
571 EFI_REST_EX_HTTP_CONFIG_DATA *RestExHttpConfigData;
572 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NetworkInterface;
573
574 NewFound = TRUE;
575 InfoRefresh = FALSE;
576 Char16Uuid = NULL;
577 RestExOpened = FALSE;
578 DeleteRestEx = FALSE;
579
580 DEBUG ((DEBUG_INFO,"%a:Add this instance to Redfish instance list.\n", __FUNCTION__));
581
582 if (Uuid != NULL) {
583 Char16Uuid = (CHAR16 *)AllocateZeroPool(AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
584 AsciiStrToUnicodeStrS ((const CHAR8 *)Uuid, Char16Uuid, AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
585 }
586 DiscoveredList = NULL;
587 DiscoveredInstance = NULL;
588 RestExHttpConfigData = NULL;
589
590 NetworkInterface = Instance->NetworkInterface;
591 if (!IsListEmpty (&mRedfishInstanceList)) {
592 //
593 // Is this a duplicate redfish service.
594 //
595 DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetFirstNode (&mRedfishInstanceList);
596 NewFound = FALSE;
597 do {
598 if (Char16Uuid == NULL || DiscoveredList->Instance->Information.Uuid == NULL) {
599 //
600 // Check if this Redfish instance already found using IP addrress.
601 //
602 if (!CheckIsIpVersion6(NetworkInterface)) {
603 if (CompareMem ((VOID *)&Instance->TargetIpAddress.v4,
604 (VOID *)&DiscoveredList->Instance->Information.RedfishHostIpAddress.v4,
605 sizeof (EFI_IPv4_ADDRESS)
606 ) == 0)
607 {
608 DiscoveredInstance = DiscoveredList->Instance;
609 if (DiscoveredList->Instance->Information.Uuid == NULL &&
610 Char16Uuid != NULL) {
611 InfoRefresh = TRUE;
612 DiscoveredInstance = DiscoveredList->Instance;
613 DEBUG((DEBUG_INFO,"*** This Redfish Service information refresh ***\n"));
614 }
615 break;
616 }
617 } else {
618 if (CompareMem ((VOID *)&Instance->TargetIpAddress.v6,
619 (VOID *)&DiscoveredList->Instance->Information.RedfishHostIpAddress.v6,
620 sizeof (EFI_IPv6_ADDRESS)
621 ) == 0)
622 {
623 DiscoveredInstance = DiscoveredList->Instance;
624 break;
625 }
626 }
627 } else {
628 //
629 // Check if this Redfish instance already found using UUID.
630 //
631 if (StrCmp((const CHAR16 *)Char16Uuid, (const CHAR16 *)DiscoveredList->Instance->Information.Uuid) == 0) {
632 DiscoveredInstance = DiscoveredList->Instance;
633 break;
634 }
635 }
636 if (IsNodeAtEnd (&mRedfishInstanceList, &DiscoveredList->NextInstance)) {
637 NewFound = TRUE;
638 break;
639 }
640 DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetNextNode (&mRedfishInstanceList, &DiscoveredList->NextInstance);
641 } while (TRUE);
642 }
643 if (NewFound || InfoRefresh) {
644 if (!InfoRefresh) {
645 DiscoveredList = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INTERNAL_LIST));
646 if (DiscoveredList == NULL) {
647 return EFI_OUT_OF_RESOURCES;
648 }
649 InitializeListHead (&DiscoveredList->NextInstance);
650 DiscoveredInstance = (EFI_REDFISH_DISCOVERED_INSTANCE *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INSTANCE));
651 if (DiscoveredInstance == NULL) {
652 FreePool ((VOID *)DiscoveredList);
653 return EFI_OUT_OF_RESOURCES;
654 }
655 }
656 DEBUG ((DEBUG_INFO,"*** Redfish Service Information ***\n"));
657
658 DiscoveredInstance->Information.UseHttps = UseHttps;
659 if (RedfishVersion != NULL) {
660 DiscoveredInstance->Information.RedfishVersion = *RedfishVersion;
661 DEBUG ((DEBUG_INFO,"Redfish service version: %d.\n", DiscoveredInstance->Information.RedfishVersion));
662 }
663 if (RedfishLocation != NULL) {
664 DiscoveredInstance->Information.Location = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)RedfishLocation) * sizeof(CHAR16));
665 AsciiStrToUnicodeStrS ((const CHAR8 *)RedfishLocation, DiscoveredInstance->Information.Location, AsciiStrSize((const CHAR8 *)RedfishLocation) * sizeof(CHAR16));
666 DEBUG ((DEBUG_INFO,"Redfish service location: %s.\n", DiscoveredInstance->Information.Location));
667 }
668 if (Uuid != NULL) {
669 DiscoveredInstance->Information.Uuid = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
670 AsciiStrToUnicodeStrS ((const CHAR8 *)Uuid, DiscoveredInstance->Information.Uuid, AsciiStrSize((const CHAR8 *)Uuid) * sizeof(CHAR16));
671 DEBUG ((DEBUG_INFO,"Service UUID: %s.\n", DiscoveredInstance->Information.Uuid));
672 }
673 if (Os != NULL) {
674 DiscoveredInstance->Information.Os = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)Os) * sizeof(CHAR16));
675 AsciiStrToUnicodeStrS ((const CHAR8 *)Os, DiscoveredInstance->Information.Os, AsciiStrSize((const CHAR8 *)Os) * sizeof(CHAR16));
676 DEBUG ((DEBUG_INFO,"Redfish service OS: %s, Version:%s.\n", DiscoveredInstance->Information.Os, DiscoveredInstance->Information.OsVersion));
677 }
678 if (OsVer != NULL) {
679 DiscoveredInstance->Information.OsVersion = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)OsVer) * sizeof(CHAR16));
680 AsciiStrToUnicodeStrS ((const CHAR8 *)OsVer, DiscoveredInstance->Information.OsVersion, AsciiStrSize((const CHAR8 *)OsVer) * sizeof(CHAR16));
681 }
682 if (Product != NULL && ProductVer != NULL) {
683 DiscoveredInstance->Information.Product = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)Product) * sizeof(CHAR16));
684 AsciiStrToUnicodeStrS ((const CHAR8 *)Product, DiscoveredInstance->Information.Product, AsciiStrSize((const CHAR8 *)Product) * sizeof(CHAR16));
685 DiscoveredInstance->Information.ProductVer = (CHAR16 *)AllocatePool(AsciiStrSize((const CHAR8 *)ProductVer) * sizeof(CHAR16));
686 AsciiStrToUnicodeStrS ((const CHAR8 *)ProductVer, DiscoveredInstance->Information.ProductVer, AsciiStrSize((const CHAR8 *)ProductVer) * sizeof(CHAR16));
687 DEBUG ((DEBUG_INFO,"Redfish service product: %s, Version:%s.\n", DiscoveredInstance->Information.Product, DiscoveredInstance->Information.ProductVer));
688 }
689
690 if (RedfishLocation == NULL) {
691 // This is the Redfish reported from SMBIOS 42h
692 // without validation.
693
694 IP4_COPY_ADDRESS((VOID *)&DiscoveredInstance->Information.RedfishHostIpAddress.v4, (VOID *)&Instance->TargetIpAddress.v4);
695 }
696 if (!InfoRefresh) {
697 DiscoveredList->Instance = DiscoveredInstance;
698 InsertTailList(&mRedfishInstanceList, &DiscoveredList->NextInstance);
699 }
700 DiscoveredInstance->Status = EFI_SUCCESS;
701 } else {
702 if (DiscoveredList != NULL) {
703 DEBUG((DEBUG_INFO,"*** This Redfish Service was already found ***\n"));
704 if (DiscoveredInstance->Information.Uuid != NULL) {
705 DEBUG((DEBUG_INFO,"Service UUID: %s.\n", DiscoveredInstance->Information.Uuid));
706 } else {
707 DEBUG((DEBUG_INFO,"Service UUID: unknown.\n"));
708 }
709 }
710 }
711 if (Char16Uuid != NULL) {
712 FreePool((VOID *)Char16Uuid);
713 }
714
715 Status = EFI_SUCCESS;
716 if (NewFound || InfoRefresh) {
717 //
718 // Build up EFI_REDFISH_DISCOVERED_LIST in token.
719 //
720 Instance->DiscoverToken->DiscoverList.NumberOfServiceFound = 1;
721 Instance->DiscoverToken->DiscoverList.RedfishInstances = DiscoveredInstance;
722 DiscoveredInstance->Status = EFI_SUCCESS;
723 if (!InfoRefresh) {
724 Status = CreateRestExInstance (Instance, Instance->DiscoverToken); // Create REST EX child.
725 if (EFI_ERROR (Status)) {
726 DEBUG ((DEBUG_ERROR, "%a:Can't create REST EX child instance.\n",__FUNCTION__));
727 goto ON_EXIT;
728 }
729 Status = gBS->OpenProtocol ( // Configure local host information.
730 Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
731 &gEfiRestExProtocolGuid,
732 (VOID **)&RestEx,
733 Instance->NetworkInterface->OpenDriverAgentHandle,
734 Instance->NetworkInterface->OpenDriverControllerHandle,
735 EFI_OPEN_PROTOCOL_BY_DRIVER
736 );
737 if (EFI_ERROR (Status)) {
738 DeleteRestEx = TRUE;
739 goto ERROR_EXIT;
740 }
741 RestExOpened = TRUE;
742 RestExHttpConfigData = AllocateZeroPool (sizeof (EFI_REST_EX_HTTP_CONFIG_DATA));
743 if (RestExHttpConfigData == NULL) {
744 Status = EFI_OUT_OF_RESOURCES;
745 DeleteRestEx = TRUE;
746 goto EXIT_FREE_CONFIG_DATA;
747 }
748 RestExHttpConfigData->SendReceiveTimeout = 5000;
749 RestExHttpConfigData->HttpConfigData.HttpVersion = HttpVersion11;
750 RestExHttpConfigData->HttpConfigData.LocalAddressIsIPv6 = CheckIsIpVersion6(NetworkInterface);
751 if (RestExHttpConfigData->HttpConfigData.LocalAddressIsIPv6) {
752 RestExHttpConfigData->HttpConfigData.AccessPoint.IPv6Node = AllocateZeroPool (sizeof (EFI_HTTPv6_ACCESS_POINT));
753 if (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv6Node == NULL) {
754 Status = EFI_OUT_OF_RESOURCES;
755 goto EXIT_FREE_CONFIG_DATA;
756 }
757 } else {
758 RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node = AllocateZeroPool (sizeof (EFI_HTTPv4_ACCESS_POINT));
759 if (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node == NULL) {
760 Status = EFI_OUT_OF_RESOURCES;
761 goto EXIT_FREE_CONFIG_DATA;
762 }
763 RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node->UseDefaultAddress = TRUE;
764 }
765 Status = RestEx->Configure (
766 RestEx,
767 (EFI_REST_EX_CONFIG_DATA)(UINT8 *)RestExHttpConfigData
768 );
769 if (EFI_ERROR (Status)) {
770 DEBUG ((DEBUG_ERROR,"%a:REST EX configured..\n", __FUNCTION__));
771 DeleteRestEx = TRUE;
772 goto EXIT_FREE_ALL;
773 }
774 //
775 // Signal client, close REST EX before signaling client.
776 //
777 if (RestExOpened) {
778 gBS->CloseProtocol(
779 Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
780 &gEfiRestExProtocolGuid,
781 Instance->NetworkInterface->OpenDriverAgentHandle,
782 Instance->NetworkInterface->OpenDriverControllerHandle
783 );
784 RestExOpened = FALSE;
785 }
786 }
787 Status = gBS->SignalEvent(Instance->DiscoverToken->Event);
788 if (!EFI_ERROR (Status)) {
789 DEBUG ((DEBUG_ERROR,"%a:No event to signal!\n", __FUNCTION__));
790 }
791 }
792
793 EXIT_FREE_ALL:;
794 if (RestExHttpConfigData != NULL && RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node != NULL) {
795 FreePool (RestExHttpConfigData->HttpConfigData.AccessPoint.IPv4Node);
796 }
797
798 EXIT_FREE_CONFIG_DATA:;
799 if (RestExHttpConfigData != NULL) {
800 FreePool((VOID *)RestExHttpConfigData);
801 }
802 if (RestExOpened) {
803 gBS->CloseProtocol(
804 Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
805 &gEfiRestExProtocolGuid,
806 Instance->NetworkInterface->OpenDriverAgentHandle,
807 Instance->NetworkInterface->OpenDriverControllerHandle
808 );
809 }
810 ERROR_EXIT:;
811 if (DeleteRestEx && RestExOpened) {
812 gBS->CloseProtocol(
813 Instance->DiscoverToken->DiscoverList.RedfishInstances->Information.RedfishRestExHandle,
814 &gEfiRestExProtocolGuid,
815 Instance->NetworkInterface->OpenDriverAgentHandle,
816 Instance->NetworkInterface->OpenDriverControllerHandle
817 );
818 }
819 ON_EXIT:;
820 return Status;
821 }
822
823 /**
824 This function gets the subnet information of this network interface instance.
825 can discover Redfish service on it.
826
827 @param[in] Instance EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance.
828 @param[in] ImageHandle EFI Image handle request the network interface list.
829
830 @retval EFI_SUCCESS
831
832 **/
833 EFI_STATUS
834 NetworkInterfaceGetSubnetInfo (
835 IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *Instance,
836 IN EFI_HANDLE ImageHandle
837 )
838 {
839 EFI_STATUS Status;
840 UINT32 ProtocolType;
841 UINT32 IPv6InfoIndex;
842 EFI_IP6_ADDRESS_INFO *ThisSubnetAddrInfoIPv6;
843 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NewNetworkInterface;
844
845 if (Instance->GotSubnetInfo) {
846 return EFI_SUCCESS;
847 }
848
849 ProtocolType = Instance->NetworkProtocolType;
850 if (gRequiredProtocol [ProtocolType].GetSubnetInfo != NULL && Instance->GotSubnetInfo == FALSE) {
851 Status = gRequiredProtocol [ProtocolType].GetSubnetInfo (
852 ImageHandle,
853 Instance
854 );
855 if (EFI_ERROR (Status)) {
856 DEBUG ((DEBUG_ERROR,"%a:Faile to get Subnet infomation.\n", __FUNCTION__));
857 return Status;
858 } else {
859 DEBUG ((DEBUG_INFO,"%a:MAC address: %s\n", __FUNCTION__, Instance->StrMacAddr));
860 if (CheckIsIpVersion6 (Instance)) {
861 if (Instance->SubnetAddrInfoIPv6Number == 0) {
862 DEBUG ((DEBUG_ERROR,"%a: There is no Subnet infomation for IPv6 network interface.\n", __FUNCTION__));
863 return EFI_NOT_FOUND;
864 }
865 ThisSubnetAddrInfoIPv6 = Instance->SubnetAddrInfoIPv6; // First IPv6 address information.
866 IP6_COPY_ADDRESS (&Instance->SubnetAddr.v6, &ThisSubnetAddrInfoIPv6->Address);
867 Instance->SubnetPrefixLength = ThisSubnetAddrInfoIPv6->PrefixLength;
868 DEBUG((DEBUG_INFO," IPv6 Subnet ID:%d, Prefix length: %d.\n",
869 ThisSubnetAddrInfoIPv6->Address.Addr [7] + (UINT16)ThisSubnetAddrInfoIPv6->Address.Addr [6] * 256,
870 ThisSubnetAddrInfoIPv6->PrefixLength)
871 );
872 //
873 // If this is IPv6, then we may have to propagate network interface for IPv6 network scopes
874 // according to the Ipv6 address information.
875 //
876 ThisSubnetAddrInfoIPv6 ++;
877 for (IPv6InfoIndex = 0; IPv6InfoIndex < Instance->SubnetAddrInfoIPv6Number - 1; IPv6InfoIndex++) {
878 //
879 // Build up addtional EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instances.
880 //
881 NewNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL));
882 if (NewNetworkInterface != NULL) {
883 CopyMem ((VOID *)NewNetworkInterface, (VOID *)Instance, sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL)); // Clone information of first instance.
884 IP6_COPY_ADDRESS (&NewNetworkInterface->SubnetAddr.v6, &ThisSubnetAddrInfoIPv6->Address);
885 NewNetworkInterface->SubnetPrefixLength = ThisSubnetAddrInfoIPv6->PrefixLength;
886 NewNetworkInterface->GotSubnetInfo = TRUE;
887 InsertTailList (&mEfiRedfishDiscoverNetworkInterface, &NewNetworkInterface->Entry);
888 ThisSubnetAddrInfoIPv6 ++;
889 mNumNetworkInterface ++;
890 DEBUG((DEBUG_INFO," IPv6 Subnet ID:%d, Prefix length: %d.\n",
891 ThisSubnetAddrInfoIPv6->Address.Addr [7] + (UINT16)ThisSubnetAddrInfoIPv6->Address.Addr [6] * 256,
892 ThisSubnetAddrInfoIPv6->PrefixLength)
893 );
894 } else {
895 return EFI_OUT_OF_RESOURCES;
896 }
897 }
898 } else {
899 DEBUG ((DEBUG_INFO," IPv4 Subnet:%d.%d.%d.%d Subnet mask: %d.%d.%d.%d.\n",
900 Instance->SubnetAddr.v4.Addr [0],
901 Instance->SubnetAddr.v4.Addr [1],
902 Instance->SubnetAddr.v4.Addr [2],
903 Instance->SubnetAddr.v4.Addr [3],
904 Instance->SubnetMask.v4.Addr [0],
905 Instance->SubnetMask.v4.Addr [1],
906 Instance->SubnetMask.v4.Addr [2],
907 Instance->SubnetMask.v4.Addr [3]
908 ));
909 }
910 }
911 }
912 Instance->GotSubnetInfo = TRUE; // Only try to get Subnet Info once.
913 return EFI_SUCCESS;
914 }
915
916 /**
917 This function gets the network interface list which Redfish discover protocol
918 can discover Redfish service on it.
919
920 @param[in] This EFI_REDFISH_DISCOVER_PROTOCOL instance.
921 @param[in] ImageHandle EFI Image handle request the network interface list,
922 @param[out] NumberOfNetworkIntfs Number of network interfaces can do Redfish service discovery.
923 @param[out] NetworkIntfInstances Network interface instances. It's an array of instance. The number of entries
924 in array is indicated by NumberOfNetworkIntfs.
925 Caller has to release the memory
926 allocated by Redfish discover protocol.
927
928 @retval EFI_SUCCESS The information of network interface is returned in NumberOfNetworkIntfs and
929 NetworkIntfInstances.
930 @retval Others Fail to return the information of network interface.
931
932 **/
933 EFI_STATUS
934 EFIAPI
935 RedfishServiceGetNetworkInterface (
936 IN EFI_REDFISH_DISCOVER_PROTOCOL *This,
937 IN EFI_HANDLE ImageHandle,
938 OUT UINTN *NumberOfNetworkIntfs,
939 OUT EFI_REDFISH_DISCOVER_NETWORK_INTERFACE **NetworkIntfInstances
940 )
941 {
942 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterfaceIntn;
943 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *ThisNetworkInterface;
944
945 if (NetworkIntfInstances == NULL || NumberOfNetworkIntfs == NULL || ImageHandle == NULL) {
946 return EFI_INVALID_PARAMETER;
947 }
948
949 *NumberOfNetworkIntfs = 0;
950 *NetworkIntfInstances = NULL;
951
952 if (IsListEmpty ((const LIST_ENTRY*)&mEfiRedfishDiscoverNetworkInterface)) {
953 return EFI_NOT_FOUND;
954 }
955
956 ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE) * mNumNetworkInterface);
957 if (ThisNetworkInterface == NULL) {
958 return EFI_OUT_OF_RESOURCES;
959 }
960 *NetworkIntfInstances = ThisNetworkInterface;
961 ThisNetworkInterfaceIntn = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
962 while (TRUE) {
963 ThisNetworkInterface->IsIpv6 = FALSE;
964 if (CheckIsIpVersion6 (ThisNetworkInterfaceIntn)) {
965 ThisNetworkInterface->IsIpv6 = TRUE;
966 }
967 CopyMem((VOID *)&ThisNetworkInterface->MacAddress, &ThisNetworkInterfaceIntn->MacAddress, ThisNetworkInterfaceIntn->HwAddressSize);
968 NetworkInterfaceGetSubnetInfo(ThisNetworkInterfaceIntn, ImageHandle); // Get subnet info.
969 if (!ThisNetworkInterface->IsIpv6) {
970 IP4_COPY_ADDRESS(&ThisNetworkInterface->SubnetId.v4, &ThisNetworkInterfaceIntn->SubnetAddr.v4); // IPv4 subnet information.
971 } else {
972 IP6_COPY_ADDRESS (&ThisNetworkInterface->SubnetId.v6, &ThisNetworkInterfaceIntn->SubnetAddr.v6); // IPv6 subnet information in IPv6 address information.
973 }
974 ThisNetworkInterface->SubnetPrefixLength = ThisNetworkInterfaceIntn->SubnetPrefixLength;
975 ThisNetworkInterface->VlanId = ThisNetworkInterfaceIntn->VlanId;
976 (*NumberOfNetworkIntfs) ++;
977 if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterfaceIntn->Entry)) {
978 break;
979 }
980 ThisNetworkInterfaceIntn = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterfaceIntn->Entry);
981 ThisNetworkInterface ++;
982 };
983 return EFI_SUCCESS;
984 }
985 /**
986 This function acquires Redfish services by discovering static Redfish setting
987 according to Redfish Host Interface or through SSDP. Returns a list of EFI
988 handles in EFI_REDFISH_DISCOVERED_LIST. Each of EFI handle has cooresponding
989 EFI REST EX instance installed on it. Each REST EX isntance is a child instance which
990 created through EFI REST EX serivce protoocl for communicating with specific
991 Redfish service.
992
993 @param[in] This EFI_REDFISH_DISCOVER_PROTOCOL instance.
994 @param[in] ImageHandle EFI image owns these Redfish service instances.
995 @param[in] TargetNetworkInterface Target network interface to do the discovery.
996 NULL means discover Redfish service on all network interfaces on platform.
997 @param[in] Flags Redfish service discover flags.
998 @param[in] Token EFI_REDFISH_DISCOVERED_TOKEN instance.
999 The memory of EFI_REDFISH_DISCOVERED_LIST and the strings in
1000 EFI_REDFISH_DISCOVERED_INFORMATION are all allocated by Acquire()
1001 and must be freed when caller invoke Release().
1002
1003 @retval EFI_SUCCESS REST EX instance of discovered Redfish services are returned.
1004 @retval EFI_INVALID_PARAMETERS ImageHandle == NULL, Flags == 0, Token == NULL, Token->Timeout > 5,
1005 or Token->Event == NULL.
1006 @retval Others Fail acquire Redfish services.
1007
1008 **/
1009 EFI_STATUS
1010 EFIAPI
1011 RedfishServiceAcquireService (
1012 IN EFI_REDFISH_DISCOVER_PROTOCOL *This,
1013 IN EFI_HANDLE ImageHandle,
1014 IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *TargetNetworkInterface,
1015 IN EFI_REDFISH_DISCOVER_FLAG Flags,
1016 IN EFI_REDFISH_DISCOVERED_TOKEN *Token
1017 )
1018 {
1019 EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *Instance;
1020 EFI_STATUS Status1;
1021 EFI_STATUS Status2;
1022 BOOLEAN NewInstance;
1023 UINTN NumNetworkInterfaces;
1024 UINTN NetworkInterfacesIndex;
1025 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *TargetNetworkInterfaceInternal;
1026
1027 DEBUG ((DEBUG_INFO,"%a:Entry.\n", __FUNCTION__));
1028
1029 //
1030 // Validate parameters.
1031 //
1032 if (ImageHandle == NULL || Token == NULL || ((Flags & ~EFI_REDFISH_DISCOVER_VALIDATION) == 0)) {
1033 DEBUG ((DEBUG_ERROR,"%a:Invalid parameters.\n", __FUNCTION__));
1034 return EFI_INVALID_PARAMETER;
1035 }
1036 //
1037 // Validate target network interface.
1038 //
1039 if (EFI_ERROR (ValidateTargetNetworkInterface (TargetNetworkInterface, Flags))) {
1040 return EFI_UNSUPPORTED;
1041 }
1042 if (TargetNetworkInterface != NULL) {
1043 TargetNetworkInterfaceInternal = GetTargetNetworkInterfaceInternal (TargetNetworkInterface);
1044 NumNetworkInterfaces = 1;
1045 } else {
1046 TargetNetworkInterfaceInternal = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
1047 NumNetworkInterfaces = NumberOfNetworkInterface ();
1048 if (NumNetworkInterfaces == 0) {
1049 DEBUG ((DEBUG_ERROR,"%a:No network interface on platform.\n", __FUNCTION__));
1050 return EFI_UNSUPPORTED;
1051 }
1052 }
1053 for (NetworkInterfacesIndex = 0; NetworkInterfacesIndex < NumNetworkInterfaces; NetworkInterfacesIndex ++) {
1054 Status1 = EFI_SUCCESS;
1055 Status2 = EFI_SUCCESS;
1056 NewInstance = FALSE;
1057 Instance = GetInstanceByOwner (ImageHandle, TargetNetworkInterfaceInternal, Flags & ~EFI_REDFISH_DISCOVER_VALIDATION); // Check if we can re-use previous instance.
1058 if (Instance == NULL) {
1059 DEBUG ((DEBUG_INFO,"%a:Create new EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE.\n", __FUNCTION__));
1060 Instance = (EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE *)AllocateZeroPool(sizeof(EFI_REDFISH_DISCOVERED_INTERNAL_INSTANCE));
1061 if (Instance == NULL) {
1062 DEBUG ((DEBUG_ERROR,"%a:Memory allocation fail.\n", __FUNCTION__));
1063 }
1064 InitializeListHead (&Instance->Entry);
1065 Instance->Owner = ImageHandle;
1066 Instance->DiscoverFlags = Flags & ~EFI_REDFISH_DISCOVER_VALIDATION;
1067 Instance->NetworkInterface = TargetNetworkInterfaceInternal;
1068 //
1069 // Get subnet information in case subnet information is not set because
1070 // RedfishServiceGetNetworkInterfaces hasn't been called yet.
1071 //
1072 NetworkInterfaceGetSubnetInfo (TargetNetworkInterfaceInternal, ImageHandle);
1073 NewInstance = TRUE;
1074 }
1075 if (TargetNetworkInterfaceInternal->StrMacAddr != NULL) {
1076 DEBUG((DEBUG_INFO,"%a:Acquire Redfish service on network interface MAC address:%s.\n", __FUNCTION__, TargetNetworkInterfaceInternal->StrMacAddr));
1077 } else {
1078 DEBUG((DEBUG_INFO,"%a:WARNING: No MAC address on this network interface.\n", __FUNCTION__));
1079 }
1080
1081 Instance->DiscoverToken = Token; // Always use the latest Token passed by caller.
1082 if ((Flags & EFI_REDFISH_DISCOVER_HOST_INTERFACE) != 0) {
1083 DEBUG ((DEBUG_INFO,"%a:Redfish HOST interface discovery.\n", __FUNCTION__));
1084 Instance->HostIntfValidation = FALSE;
1085 if ((Flags & EFI_REDFISH_DISCOVER_VALIDATION) != 0) {
1086 Instance->HostIntfValidation = TRUE;
1087 }
1088 Status1 = DiscoverRedfishHostInterface (Instance); // Discover Redfish service through Redfish Host Interface.
1089 }
1090 if ((Flags & EFI_REDFISH_DISCOVER_SSDP) != 0) {
1091 DEBUG ((DEBUG_ERROR,"%a:Redfish service discovery through SSDP is not supported\n", __FUNCTION__));
1092 return EFI_UNSUPPORTED;
1093 } else {
1094 if (EFI_ERROR (Status1) && EFI_ERROR (Status2)) {
1095 FreePool ((VOID *)Instance);
1096 DEBUG ((DEBUG_ERROR,"%a:Something wrong on Redfish service discovery Status1=%x, Status2=%x.\n", __FUNCTION__, Status1, Status2));
1097 } else {
1098 if (NewInstance) {
1099 InsertTailList(&mRedfishDiscoverList, &Instance->Entry);
1100 }
1101 }
1102 }
1103 if (TargetNetworkInterface == NULL) {
1104 //
1105 // Discover Redfish services on all of network interfaces.
1106 //
1107 TargetNetworkInterfaceInternal = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &TargetNetworkInterfaceInternal->Entry);
1108 }
1109 }
1110 return EFI_SUCCESS;
1111 }
1112
1113 /**
1114 This function aborts Redfish service discovery on the given network interface.
1115
1116 @param[in] This EFI_REDFISH_DISCOVER_PROTOCOL instance.
1117 @param[in] TargetNetworkInterface Target network interface to do the discovery.
1118
1119 @retval EFI_SUCCESS REST EX instance of discovered Redfish services are returned.
1120 @retval Others Fail to abort Redfish service discovery.
1121
1122 **/
1123 EFI_STATUS
1124 EFIAPI
1125 RedfishServiceAbortAcquire (
1126 IN EFI_REDFISH_DISCOVER_PROTOCOL *This,
1127 IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE *TargetNetworkInterface OPTIONAL
1128 )
1129 {
1130 // This function is used to abort Redfish service discovery through SSDP
1131 // on the network interface. SSDP is optionally supprted by EFI_REDFISH_DISCOVER_PROTOCOL,
1132 // we dont have implementation for SSDP now.
1133
1134 return EFI_UNSUPPORTED;
1135 }
1136
1137 /**
1138 This function releases Redfish services found by RedfishServiceAcquire().
1139
1140 @param[in] This EFI_REDFISH_DISCOVER_PROTOCOL instance.
1141 @param[in] InstanceList The Redfish service to release.
1142
1143 @retval EFI_SUCCESS REST EX instances of discovered Redfish are released.
1144 @retval Others Fail to remove the entry
1145
1146 **/
1147 EFI_STATUS
1148 EFIAPI
1149 RedfishServiceReleaseService (
1150 IN EFI_REDFISH_DISCOVER_PROTOCOL *This,
1151 IN EFI_REDFISH_DISCOVERED_LIST *InstanceList
1152 )
1153 {
1154 UINTN NumService;
1155 BOOLEAN AnyFailRelease;
1156 EFI_REDFISH_DISCOVERED_INSTANCE *ThisRedfishInstance;
1157 EFI_REDFISH_DISCOVERED_INTERNAL_LIST *DiscoveredRedfishInstance;
1158
1159 if (IsListEmpty (&mRedfishInstanceList)) {
1160 DEBUG ((DEBUG_ERROR,"%a:No any discovered Redfish service.\n", __FUNCTION__));
1161 return EFI_NOT_FOUND;
1162 }
1163 AnyFailRelease = FALSE;
1164 ThisRedfishInstance = InstanceList->RedfishInstances;
1165 for (NumService = 0; NumService < InstanceList->NumberOfServiceFound; NumService ++) {
1166 DiscoveredRedfishInstance = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetFirstNode(&mRedfishInstanceList);
1167 do {
1168 if (DiscoveredRedfishInstance->Instance == ThisRedfishInstance) {
1169 RemoveEntryList (&DiscoveredRedfishInstance->NextInstance);
1170 if (ThisRedfishInstance->Information.Location != NULL) {
1171 FreePool (ThisRedfishInstance->Information.Location);
1172 }
1173 if (ThisRedfishInstance->Information.Uuid != NULL) {
1174 FreePool (ThisRedfishInstance->Information.Uuid);
1175 }
1176 if (ThisRedfishInstance->Information.Os != NULL) {
1177 FreePool (ThisRedfishInstance->Information.Os);
1178 }
1179 if (ThisRedfishInstance->Information.OsVersion != NULL) {
1180 FreePool (ThisRedfishInstance->Information.OsVersion);
1181 }
1182 if (ThisRedfishInstance->Information.Product != NULL) {
1183 FreePool (ThisRedfishInstance->Information.Product);
1184 }
1185 if (ThisRedfishInstance->Information.ProductVer != NULL) {
1186 FreePool (ThisRedfishInstance->Information.ProductVer);
1187 }
1188 FreePool((VOID *)ThisRedfishInstance);
1189 goto ReleaseNext;
1190 }
1191
1192 if (IsNodeAtEnd(&mRedfishInstanceList, &DiscoveredRedfishInstance->NextInstance)) {
1193 break;
1194 }
1195 DiscoveredRedfishInstance = (EFI_REDFISH_DISCOVERED_INTERNAL_LIST *)GetNextNode(&mRedfishInstanceList, &DiscoveredRedfishInstance->NextInstance);
1196 } while (TRUE);
1197 AnyFailRelease = TRUE;
1198 ReleaseNext:;
1199 //
1200 // Release next discovered Redfish Service.
1201 //
1202 ThisRedfishInstance = (EFI_REDFISH_DISCOVERED_INSTANCE *)((UINT8 *)ThisRedfishInstance + sizeof (EFI_REDFISH_DISCOVERED_INSTANCE));
1203 }
1204 if (AnyFailRelease) {
1205 return EFI_NOT_FOUND;
1206 } else {
1207 return EFI_SUCCESS;
1208 }
1209 }
1210
1211 EFI_REDFISH_DISCOVER_PROTOCOL mRedfishDiscover = {
1212 RedfishServiceGetNetworkInterface,
1213 RedfishServiceAcquireService,
1214 RedfishServiceAbortAcquire,
1215 RedfishServiceReleaseService
1216 };
1217
1218 /**
1219 This function create an EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL for the
1220 given network interface.
1221
1222
1223 @param[in] ControllerHandle MAC address of this network interface.
1224 @param[in] NetworkProtocolType Network protocol type.
1225 @param[out] IsNewInstance BOOLEAN means new instance or not.
1226 @param[out] NetworkInterface Pointer to to EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL.
1227
1228 @retval EFI_STATUS
1229 **/
1230 EFI_STATUS
1231 CreateRedfishDiscoverNetworkInterface (
1232 IN EFI_HANDLE ControllerHandle,
1233 IN UINT32 NetworkProtocolType,
1234 OUT BOOLEAN *IsNewInstance,
1235 OUT EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL **NetworkInterface
1236 )
1237 {
1238 EFI_MAC_ADDRESS MacAddress;
1239 UINTN HwAddressSize;
1240 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
1241 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NewNetworkInterface;
1242
1243 NetLibGetMacAddress (ControllerHandle, &MacAddress, &HwAddressSize);
1244 NewNetworkInterface = NULL;
1245 *IsNewInstance = TRUE;
1246 if (!IsListEmpty ((const LIST_ENTRY*)&mEfiRedfishDiscoverNetworkInterface)) {
1247 //
1248 // Check if this instance already exist.
1249 //
1250 ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
1251 if (ThisNetworkInterface != NULL) {
1252 while (TRUE) {
1253 if ((CompareMem ((CONST VOID *)&ThisNetworkInterface->MacAddress.Addr, (CONST VOID *)&MacAddress.Addr, HwAddressSize) == 0) &&
1254 (ThisNetworkInterface->NetworkProtocolType == NetworkProtocolType)){
1255 NewNetworkInterface = ThisNetworkInterface;
1256 *IsNewInstance = FALSE;
1257 break;
1258 }
1259 if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
1260 NewNetworkInterface = NULL;
1261 break;
1262 }
1263 ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
1264 };
1265 }
1266 }
1267 if (NewNetworkInterface == NULL) {
1268 //
1269 // Create a new instance.
1270 //
1271 NewNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL));
1272 if (NewNetworkInterface == NULL) {
1273 return EFI_OUT_OF_RESOURCES;
1274 }
1275 NewNetworkInterface->HwAddressSize = HwAddressSize;
1276 CopyMem (&NewNetworkInterface->MacAddress.Addr, &MacAddress.Addr, NewNetworkInterface->HwAddressSize);
1277 NetLibGetMacString (ControllerHandle, NULL, &NewNetworkInterface->StrMacAddr);
1278 NewNetworkInterface->VlanId = NetLibGetVlanId (ControllerHandle);
1279 }
1280 *NetworkInterface = NewNetworkInterface;
1281 return EFI_SUCCESS;
1282 }
1283
1284 /**
1285 This function destory network interface
1286
1287
1288 @param[in] ThisNetworkInterface EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL instance.
1289
1290 @retval EFI_STATUS
1291 **/
1292 EFI_STATUS
1293 DestroyRedfishNetwrokInterface (
1294 IN EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface
1295 )
1296 {
1297 EFI_STATUS Status;
1298
1299 Status = gBS->UninstallProtocolInterface(
1300 ThisNetworkInterface->OpenDriverControllerHandle,
1301 gRequiredProtocol [ThisNetworkInterface->NetworkProtocolType].DiscoveredProtocolGuid,
1302 &ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolDiscoverId
1303 );
1304 RemoveEntryList (&ThisNetworkInterface->Entry);
1305 mNumNetworkInterface --;
1306 FreePool (ThisNetworkInterface);
1307 return Status;
1308 }
1309
1310 /**
1311 Tests to see if the required protocols are provided on the given
1312 controller handle.
1313
1314 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1315 @param[in] ControllerHandle The handle of the controller to test. This handle
1316 must support a protocol interface that supplies
1317 an I/O abstraction to the driver.
1318 @retval EFI_SUCCESS One of required protocol is found.
1319 @retval EFI_UNSUPPORTED None of required protocol is found.
1320 **/
1321 EFI_STATUS
1322 TestForRequiredProtocols (
1323 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1324 IN EFI_HANDLE ControllerHandle
1325 )
1326 {
1327 UINT32 Id;
1328 UINTN Index;
1329 EFI_STATUS Status;
1330
1331 for (Index = 0; Index < (sizeof (gRequiredProtocol) / sizeof (REDFISH_DISCOVER_REQUIRED_PROTOCOL)); Index ++) {
1332 Status = gBS->OpenProtocol (
1333 ControllerHandle,
1334 gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid,
1335 NULL,
1336 This->DriverBindingHandle,
1337 ControllerHandle,
1338 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
1339 );
1340 if (!EFI_ERROR (Status)) {
1341 Status = gBS->OpenProtocol (
1342 ControllerHandle,
1343 gRequiredProtocol [Index].DiscoveredProtocolGuid,
1344 (VOID **) &Id,
1345 This->DriverBindingHandle,
1346 ControllerHandle,
1347 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1348 );
1349 if (EFI_ERROR (Status)) {
1350 DEBUG((DEBUG_ERROR, "%a: %s is found on this controller handle.\n", __FUNCTION__, gRequiredProtocol [Index].ProtocolName));
1351 return EFI_SUCCESS;
1352 }
1353 }
1354 }
1355 return EFI_UNSUPPORTED;
1356 }
1357
1358 /**
1359 Build up network interface and create corresponding service through the given
1360 controller handle.
1361
1362 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1363 @param[in] ControllerHandle The handle of the controller to test. This handle
1364 must support a protocol interface that supplies
1365 an I/O abstraction to the driver.
1366 @retval EFI_SUCCESS One of required protocol is found.
1367 @retval EFI_UNSUPPORTED None of required protocol is found.
1368 @retval EFI_UNSUPPORTED Failed to build up network interface.
1369 **/
1370 EFI_STATUS
1371 BuildupNetworkInterface (
1372 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1373 IN EFI_HANDLE ControllerHandle
1374 )
1375 {
1376 UINT32 Id;
1377 UINT32 Index;
1378 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *NetworkInterface;
1379 BOOLEAN IsNew;
1380 EFI_STATUS Status;
1381 VOID *TempInterface;
1382 VOID **Interface;
1383 UINT32 *ProtocolDiscoverIdPtr;
1384 EFI_HANDLE OpenDriverAgentHandle;
1385 EFI_HANDLE OpenDriverControllerHandle;
1386 EFI_HANDLE *HandleOfProtocolInterfacePtr;
1387 EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *RestExInstance;
1388 EFI_TPL OldTpl;
1389 BOOLEAN NewNetworkInterfaceInstalled;
1390
1391 NewNetworkInterfaceInstalled = FALSE;
1392 Index = 0;
1393 do {
1394 Status = gBS->OpenProtocol ( // Already in list?
1395 ControllerHandle,
1396 gRequiredProtocol [Index].DiscoveredProtocolGuid,
1397 (VOID **) &Id,
1398 This->DriverBindingHandle,
1399 ControllerHandle,
1400 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1401 );
1402 if (!EFI_ERROR (Status)) {
1403 Index ++;
1404 if (Index == (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
1405 break;
1406 }
1407 continue;
1408 }
1409
1410 Status = gBS->OpenProtocol (
1411 ControllerHandle,
1412 gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid,
1413 &TempInterface,
1414 This->DriverBindingHandle,
1415 ControllerHandle,
1416 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1417 );
1418 if (EFI_ERROR (Status)) {
1419 Index ++;
1420 if (Index == (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
1421 break;
1422 }
1423 continue;
1424 }
1425 if (gRequiredProtocol [Index].ProtocolType != ProtocolTypeRestEx) {
1426 OldTpl = gBS->RaiseTPL (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
1427 Status = CreateRedfishDiscoverNetworkInterface(ControllerHandle, gRequiredProtocol [Index].ProtocolType, &IsNew, &NetworkInterface);
1428 if (EFI_ERROR (Status)) {
1429 gBS->RestoreTPL (OldTpl);
1430 return Status;
1431 }
1432 NetworkInterface->NetworkProtocolType = gRequiredProtocol [Index].ProtocolType;
1433 NetworkInterface->OpenDriverAgentHandle = This->DriverBindingHandle;
1434 NetworkInterface->OpenDriverControllerHandle = ControllerHandle;
1435 NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolGuid = \
1436 *gRequiredProtocol [Index].RequiredProtocolGuid;
1437 NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolServiceGuid = \
1438 *gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid;
1439 ProtocolDiscoverIdPtr = &NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolDiscoverId;
1440 OpenDriverAgentHandle = NetworkInterface->OpenDriverAgentHandle;
1441 OpenDriverControllerHandle = NetworkInterface->OpenDriverControllerHandle;
1442 HandleOfProtocolInterfacePtr = &NetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle;
1443 Interface = &NetworkInterface->NetworkInterfaceProtocolInfo.NetworkProtocolInterface;
1444 NewNetworkInterfaceInstalled = TRUE;
1445 if (IsNew) {
1446 InsertTailList (&mEfiRedfishDiscoverNetworkInterface, &NetworkInterface->Entry);
1447 mNumNetworkInterface ++;
1448 }
1449 gBS->RestoreTPL (OldTpl);
1450 } else {
1451 // Record REST_EX instance. REST_EX is created when clinet asks for Redfish service discovery.
1452 // Redfish Service Discover protocol will match REST EX to the corresponding EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL
1453 // when discovery.
1454
1455 RestExInstance = (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)AllocateZeroPool (sizeof (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL));
1456 if (RestExInstance == NULL) {
1457 return EFI_OUT_OF_RESOURCES;
1458 }
1459 RestExInstance->OpenDriverAgentHandle = This->DriverBindingHandle;
1460 RestExInstance->OpenDriverControllerHandle = ControllerHandle;
1461 RestExInstance->RestExControllerHandle = ControllerHandle;
1462 InitializeListHead (&RestExInstance->Entry);
1463 InsertTailList (&mEfiRedfishDiscoverRestExInstance, &RestExInstance->Entry);
1464 mNumRestExInstance ++;
1465 ProtocolDiscoverIdPtr = &RestExInstance->RestExId;
1466 OpenDriverAgentHandle = RestExInstance->OpenDriverAgentHandle;
1467 OpenDriverControllerHandle = RestExInstance->OpenDriverControllerHandle;
1468 HandleOfProtocolInterfacePtr = &RestExInstance->RestExChildHandle;
1469 Interface = (VOID **)&RestExInstance->RestExProtocolInterface;
1470 }
1471 Status = gBS->InstallProtocolInterface (
1472 &ControllerHandle,
1473 gRequiredProtocol [Index].DiscoveredProtocolGuid,
1474 EFI_NATIVE_INTERFACE,
1475 ProtocolDiscoverIdPtr
1476 );
1477 if (EFI_ERROR (Status)) {
1478 Index ++;
1479 if (Index == (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
1480 break;
1481 }
1482 continue;
1483 }
1484 //
1485 // Create service binding child and open it BY_DRIVER.
1486 //
1487 Status = NetLibCreateServiceChild (
1488 ControllerHandle,
1489 This->ImageHandle,
1490 gRequiredProtocol [Index].RequiredServiceBindingProtocolGuid,
1491 HandleOfProtocolInterfacePtr
1492 );
1493 if (!EFI_ERROR (Status)) {
1494 Status = gBS->OpenProtocol (
1495 *HandleOfProtocolInterfacePtr,
1496 gRequiredProtocol [Index].RequiredProtocolGuid,
1497 Interface,
1498 OpenDriverAgentHandle,
1499 OpenDriverControllerHandle,
1500 EFI_OPEN_PROTOCOL_BY_DRIVER
1501 );
1502 if (!EFI_ERROR (Status)) {
1503 if (EfiRedfishDiscoverProtocolHandle == NULL &&
1504 (gRequiredProtocol [Index].ProtocolType == ProtocolTypeRestEx) &&
1505 !IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)
1506 ) {
1507 // Install the fisrt Redfish Discover Protocol when EFI REST EX protcol is discovered.
1508 // This ensures EFI REST EX is ready while EFI_REDFISH_DISCOVER_PROTOCOL consumer acquires
1509 // Redfish serivce over network interface.
1510
1511 Status = gBS->InstallProtocolInterface (
1512 &EfiRedfishDiscoverProtocolHandle,
1513 &gEfiRedfishDiscoverProtocolGuid,
1514 EFI_NATIVE_INTERFACE,
1515 (VOID *)&mRedfishDiscover
1516 );
1517 } else if (EfiRedfishDiscoverProtocolHandle != NULL && NewNetworkInterfaceInstalled) {
1518 Status = gBS->ReinstallProtocolInterface (
1519 EfiRedfishDiscoverProtocolHandle,
1520 &gEfiRedfishDiscoverProtocolGuid,
1521 (VOID *)&mRedfishDiscover,
1522 (VOID *)&mRedfishDiscover
1523 );
1524 NewNetworkInterfaceInstalled = FALSE;
1525 }
1526 }
1527 return Status;
1528 } else {
1529 Index ++;
1530 if (Index == (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL))) {
1531 break;
1532 }
1533 continue;
1534 }
1535 } while (Index < (sizeof(gRequiredProtocol) / sizeof(REDFISH_DISCOVER_REQUIRED_PROTOCOL)));
1536 return EFI_UNSUPPORTED;
1537 }
1538 /**
1539 Close the protocol opened for Redfish discovery. This function also destories
1540 the network services.
1541
1542 @param[in] ThisBindingProtocol A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1543 @param[in] ControllerHandle The handle of the controller to test. This handle
1544 must support a protocol interface that supplies
1545 an I/O abstraction to the driver.
1546 @param[in] ThisRequiredProtocol Pointer to the instance of REDFISH_DISCOVER_REQUIRED_PROTOCOL.
1547 @param[in] DriverAgentHandle Driver agent handle which used to open protocol earlier.
1548 @param[in] DriverControllerHandle Driver controller handle which used to open protocol earlier.
1549
1550 @retval EFI_SUCCESS Prorocol is closed successfully.
1551 @retval Others Prorocol is closed unsuccessfully.
1552
1553 **/
1554 EFI_STATUS
1555 CloseProtocolService (
1556 IN EFI_DRIVER_BINDING_PROTOCOL *ThisBindingProtocol,
1557 IN EFI_HANDLE ControllerHandle,
1558 IN REDFISH_DISCOVER_REQUIRED_PROTOCOL *ThisRequiredProtocol,
1559 IN EFI_HANDLE DriverAgentHandle,
1560 IN EFI_HANDLE DriverControllerHandle
1561 )
1562 {
1563 EFI_STATUS Status;
1564
1565 Status = gBS->CloseProtocol (
1566 ControllerHandle,
1567 ThisRequiredProtocol->RequiredProtocolGuid,
1568 DriverAgentHandle,
1569 DriverControllerHandle
1570 );
1571 if (!EFI_ERROR (Status)) {
1572 NetLibDestroyServiceChild(
1573 ControllerHandle,
1574 ThisBindingProtocol->ImageHandle,
1575 ThisRequiredProtocol->RequiredServiceBindingProtocolGuid,
1576 ControllerHandle
1577 );
1578 }
1579 return Status;
1580 }
1581 /**
1582 Stop the services on network interface.
1583
1584 @param[in] ThisBindingProtocol A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1585 @param[in] ControllerHandle The handle of the controller to test. This handle
1586 must support a protocol interface that supplies
1587 an I/O abstraction to the driver.
1588 @retval EFI_SUCCESS One of required protocol is found.
1589 @retval Others Faile to stop the services on network interface.
1590 **/
1591 EFI_STATUS
1592 StopServiceOnNetworkInterface (
1593 IN EFI_DRIVER_BINDING_PROTOCOL *ThisBindingProtocol,
1594 IN EFI_HANDLE ControllerHandle
1595 )
1596 {
1597 UINT32 Index;
1598 EFI_STATUS Status;
1599 VOID *Interface;
1600 EFI_TPL OldTpl;
1601 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
1602 EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *RestExInstance;
1603
1604 for (Index = 0; Index < (sizeof (gRequiredProtocol) / sizeof (REDFISH_DISCOVER_REQUIRED_PROTOCOL)); Index ++) {
1605 Status = gBS->HandleProtocol (
1606 ControllerHandle,
1607 gRequiredProtocol [Index].RequiredProtocolGuid,
1608 (VOID **)&Interface
1609 );
1610 if (!EFI_ERROR (Status)) {
1611 if (gRequiredProtocol [Index].ProtocolType != ProtocolTypeRestEx) {
1612 if (IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
1613 return EFI_NOT_FOUND;
1614 }
1615 OldTpl = gBS->RaiseTPL (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
1616 ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
1617 while (TRUE) {
1618 if (ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle == ControllerHandle) {
1619
1620 Status = CloseProtocolService ( // Close protocol and destroy service.
1621 ThisBindingProtocol,
1622 ControllerHandle,
1623 &gRequiredProtocol [Index],
1624 ThisNetworkInterface->OpenDriverAgentHandle,
1625 ThisNetworkInterface->OpenDriverControllerHandle
1626 );
1627 if (!EFI_ERROR (Status)) {
1628 Status = DestroyRedfishNetwrokInterface (ThisNetworkInterface);
1629 }
1630 gBS->RestoreTPL (OldTpl);
1631 // Reinstall Redfish Discover protocol to notify network
1632 // interface change.
1633
1634 Status = gBS->ReinstallProtocolInterface (
1635 EfiRedfishDiscoverProtocolHandle,
1636 &gEfiRedfishDiscoverProtocolGuid,
1637 (VOID *)&mRedfishDiscover,
1638 (VOID *)&mRedfishDiscover
1639 );
1640 if (EFI_ERROR (Status)) {
1641 DEBUG((DEBUG_ERROR, "%a: Reinstall gEfiRedfishDiscoverProtocolGuid fail.", __FUNCTION__));
1642 }
1643 return Status;
1644 }
1645 if (IsNodeAtEnd (&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry)) {
1646 break;
1647 }
1648 ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverNetworkInterface, &ThisNetworkInterface->Entry);
1649 };
1650 gBS->RestoreTPL (OldTpl);
1651 } else {
1652 if (IsListEmpty (&mEfiRedfishDiscoverRestExInstance)) {
1653 return EFI_NOT_FOUND;
1654 }
1655 OldTpl = gBS->RaiseTPL (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_TPL);
1656 RestExInstance = (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverRestExInstance);
1657 while (TRUE) {
1658 if (RestExInstance->RestExChildHandle == ControllerHandle) {
1659 Status = CloseProtocolService ( // Close REST_EX protocol.
1660 ThisBindingProtocol,
1661 ControllerHandle,
1662 &gRequiredProtocol [Index],
1663 RestExInstance->OpenDriverAgentHandle,
1664 RestExInstance->OpenDriverControllerHandle
1665 );
1666 RemoveEntryList (&RestExInstance->Entry);
1667 FreePool ((VOID *)RestExInstance);
1668 mNumRestExInstance --;
1669 gBS->RestoreTPL (OldTpl);
1670 return Status;
1671 }
1672 if (IsNodeAtEnd (&mEfiRedfishDiscoverRestExInstance, &RestExInstance->Entry)) {
1673 break;
1674 }
1675 RestExInstance = (EFI_REDFISH_DISCOVER_REST_EX_INSTANCE_INTERNAL *)GetNextNode(&mEfiRedfishDiscoverRestExInstance, &RestExInstance->Entry);
1676 };
1677 gBS->RestoreTPL (OldTpl);
1678 }
1679 }
1680 }
1681 return EFI_NOT_FOUND;
1682 }
1683 /**
1684 Tests to see if this driver supports a given controller. If a child device is provided,
1685 it further tests to see if this driver supports creating a handle for the specified child device.
1686
1687 This function checks to see if the driver specified by This supports the device specified by
1688 ControllerHandle. Drivers will typically use the device path attached to
1689 ControllerHandle and/or the services from the bus I/O abstraction attached to
1690 ControllerHandle to determine if the driver supports ControllerHandle. This function
1691 may be called many times during platform initialization. In order to reduce boot times, the tests
1692 performed by this function must be very small, and take as little time as possible to execute. This
1693 function must not change the state of any hardware devices, and this function must be aware that the
1694 device specified by ControllerHandle may already be managed by the same driver or a
1695 different driver. This function must match its calls to AllocatePages() with FreePages(),
1696 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
1697 Because ControllerHandle may have been previously started by the same driver, if a protocol is
1698 already in the opened state, then it must not be closed with CloseProtocol(). This is required
1699 to guarantee the state of ControllerHandle is not modified by this function.
1700
1701 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1702 @param[in] ControllerHandle The handle of the controller to test. This handle
1703 must support a protocol interface that supplies
1704 an I/O abstraction to the driver.
1705 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
1706 parameter is ignored by device drivers, and is optional for bus
1707 drivers. For bus drivers, if this parameter is not NULL, then
1708 the bus driver must determine if the bus controller specified
1709 by ControllerHandle and the child controller specified
1710 by RemainingDevicePath are both supported by this
1711 bus driver.
1712
1713 @retval EFI_SUCCESS The device specified by ControllerHandle and
1714 RemainingDevicePath is supported by the driver specified by This.
1715 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
1716 RemainingDevicePath is already being managed by the driver
1717 specified by This.
1718 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
1719 RemainingDevicePath is already being managed by a different
1720 driver or an application that requires exclusive access.
1721 Currently not implemented.
1722 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
1723 RemainingDevicePath is not supported by the driver specified by This.
1724 **/
1725 EFI_STATUS
1726 EFIAPI
1727 RedfishDiscoverDriverBindingSupported (
1728 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1729 IN EFI_HANDLE ControllerHandle,
1730 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1731 )
1732 {
1733 return TestForRequiredProtocols (This, ControllerHandle);
1734 }
1735
1736 /**
1737 Starts a device controller or a bus controller.
1738
1739 The Start() function is designed to be invoked from the EFI boot service ConnectController().
1740 As a result, much of the error checking on the parameters to Start() has been moved into this
1741 common boot service. It is legal to call Start() from other locations,
1742 but the following calling restrictions must be followed, or the system behavior will not be deterministic.
1743 1. ControllerHandle must be a valid EFI_HANDLE.
1744 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
1745 EFI_DEVICE_PATH_PROTOCOL.
1746 3. Prior to calling Start(), the Supported() function for the driver specified by This must
1747 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
1748
1749 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1750 @param[in] ControllerHandle The handle of the controller to start. This handle
1751 must support a protocol interface that supplies
1752 an I/O abstraction to the driver.
1753 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
1754 parameter is ignored by device drivers, and is optional for bus
1755 drivers. For a bus driver, if this parameter is NULL, then handles
1756 for all the children of Controller are created by this driver.
1757 If this parameter is not NULL and the first Device Path Node is
1758 not the End of Device Path Node, then only the handle for the
1759 child device specified by the first Device Path Node of
1760 RemainingDevicePath is created by this driver.
1761 If the first Device Path Node of RemainingDevicePath is
1762 the End of Device Path Node, no child handle is created by this
1763 driver.
1764
1765 @retval EFI_SUCCESS The device was started.
1766 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
1767 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1768 @retval Others The driver failded to start the device.
1769
1770 **/
1771 EFI_STATUS
1772 EFIAPI
1773 RedfishDiscoverDriverBindingStart (
1774 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1775 IN EFI_HANDLE ControllerHandle,
1776 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
1777 )
1778 {
1779 return BuildupNetworkInterface (This, ControllerHandle);
1780 }
1781
1782 /**
1783 Stops a device controller or a bus controller.
1784
1785 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
1786 As a result, much of the error checking on the parameters to Stop() has been moved
1787 into this common boot service. It is legal to call Stop() from other locations,
1788 but the following calling restrictions must be followed, or the system behavior will not be deterministic.
1789 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
1790 same driver's Start() function.
1791 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
1792 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
1793 Start() function, and the Start() function must have called OpenProtocol() on
1794 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
1795
1796 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1797 @param[in] ControllerHandle A handle to the device being stopped. The handle must
1798 support a bus specific I/O protocol for the driver
1799 to use to stop the device.
1800 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
1801 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
1802 if NumberOfChildren is 0.
1803
1804 @retval EFI_SUCCESS The device was stopped.
1805 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
1806
1807 **/
1808 EFI_STATUS
1809 EFIAPI
1810 RedfishDiscoverDriverBindingStop (
1811 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1812 IN EFI_HANDLE ControllerHandle,
1813 IN UINTN NumberOfChildren,
1814 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
1815 )
1816 {
1817 return StopServiceOnNetworkInterface (This, ControllerHandle);
1818 }
1819
1820 EFI_DRIVER_BINDING_PROTOCOL gRedfishDiscoverDriverBinding = {
1821 RedfishDiscoverDriverBindingSupported,
1822 RedfishDiscoverDriverBindingStart,
1823 RedfishDiscoverDriverBindingStop,
1824 REDFISH_DISCOVER_VERSION,
1825 NULL,
1826 NULL
1827 };
1828
1829 /**
1830 This is the declaration of an EFI image entry point.
1831
1832 @param ImageHandle The firmware allocated handle for the UEFI image.
1833 @param SystemTable A pointer to the EFI System Table.
1834
1835 @retval EFI_SUCCESS The operation completed successfully.
1836 @retval Others An unexpected error occurred.
1837 **/
1838 EFI_STATUS
1839 EFIAPI
1840 RedfishDiscoverEntryPoint (
1841 IN EFI_HANDLE ImageHandle,
1842 IN EFI_SYSTEM_TABLE *SystemTable
1843 )
1844 {
1845 EFI_STATUS Status;
1846
1847 Status = EFI_SUCCESS;
1848 InitializeListHead (&mRedfishDiscoverList);
1849 InitializeListHead (&mRedfishInstanceList);
1850 InitializeListHead (&mEfiRedfishDiscoverNetworkInterface);
1851 InitializeListHead (&mEfiRedfishDiscoverRestExInstance);
1852 //
1853 // Install binding protoocl to obtain UDP and REST EX protocol.
1854 //
1855 Status = EfiLibInstallDriverBindingComponentName2 (
1856 ImageHandle,
1857 SystemTable,
1858 &gRedfishDiscoverDriverBinding,
1859 ImageHandle,
1860 &gRedfishDiscoverComponentName,
1861 &gRedfishDiscoverComponentName2
1862 );
1863 return Status;
1864 }
1865
1866 /**
1867 This is the unload handle for Redfish discover module.
1868
1869 Disconnect the driver specified by ImageHandle from all the devices in the handle database.
1870 Uninstall all the protocols installed in the driver entry point.
1871
1872 @param[in] ImageHandle The drivers' driver image.
1873
1874 @retval EFI_SUCCESS The image is unloaded.
1875 @retval Others Failed to unload the image.
1876
1877 **/
1878 EFI_STATUS
1879 EFIAPI
1880 RedfishDiscoverUnload (
1881 IN EFI_HANDLE ImageHandle
1882 )
1883 {
1884 EFI_STATUS Status;
1885 EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *ThisNetworkInterface;
1886
1887 Status = EFI_SUCCESS;
1888 // Destroy all network interfaces found by EFI Redfish Discover driver and
1889 // stop services created for Redfish Discover.
1890
1891 while (!IsListEmpty (&mEfiRedfishDiscoverNetworkInterface)) {
1892 ThisNetworkInterface = (EFI_REDFISH_DISCOVER_NETWORK_INTERFACE_INTERNAL *)GetFirstNode (&mEfiRedfishDiscoverNetworkInterface);
1893 StopServiceOnNetworkInterface (&gRedfishDiscoverDriverBinding, ThisNetworkInterface->NetworkInterfaceProtocolInfo.ProtocolControllerHandle);
1894 };
1895 // Disconnect EFI Redfish discover driver controller to notify the
1896 // clinet which uses .EFI Redfish discover protocol.
1897
1898 if (EfiRedfishDiscoverProtocolHandle != NULL) {
1899 //
1900 // Notify user EFI_REDFISH_DISCOVER_PROTOCOL is unloaded.
1901 //
1902 gBS->DisconnectController (EfiRedfishDiscoverProtocolHandle, NULL, NULL);
1903 Status = gBS->UninstallProtocolInterface(
1904 EfiRedfishDiscoverProtocolHandle,
1905 &gEfiRedfishDiscoverProtocolGuid,
1906 (VOID *)&mRedfishDiscover
1907 );
1908 }
1909 return Status;
1910 }