VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/RedfishPkg/Library/PlatformHostInterfaceBmcUsbNicLib/PlatformHostInterfaceBmcUsbNicLib.c

Last change on this file was 105670, checked in by vboxsync, 8 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 50.9 KB
Line 
1/** @file
2 Source file to provide the platform Redfish Host Interface information
3 of USB NIC Device exposed by BMC.
4
5 Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9**/
10
11#include "PlatformHostInterfaceBmcUsbNicLib.h"
12
13static EFI_GUID mPlatformHostInterfaceBmcUsbNicReadinessGuid =
14 BMC_USB_NIC_HOST_INTERFASCE_READINESS_GUID;
15static EFI_EVENT mPlatformHostInterfaceSnpEvent = NULL;
16static VOID *mPlatformHostInterfaceSnpRegistration = NULL;
17
18static LIST_ENTRY mBmcUsbNic;
19static LIST_ENTRY mBmcIpmiLan;
20
21/**
22 Probe if the system supports Redfish Host Interface Credentail
23 Bootstrapping.
24
25 @retval TRUE Yes, it is supported.
26 TRUE No, it is not supported.
27
28**/
29BOOLEAN
30ProbeRedfishCredentialBootstrap (
31 VOID
32 )
33{
34 EFI_STATUS Status;
35 IPMI_BOOTSTRAP_CREDENTIALS_COMMAND_DATA CommandData;
36 IPMI_BOOTSTRAP_CREDENTIALS_RESULT_RESPONSE ResponseData;
37 UINT32 ResponseSize;
38 BOOLEAN ReturnBool;
39
40 DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry\n", __func__));
41
42 //
43 // IPMI callout to NetFn 2C, command 02
44 // Request data:
45 // Byte 1: REDFISH_IPMI_GROUP_EXTENSION
46 // Byte 2: DisableBootstrapControl
47 //
48 CommandData.GroupExtensionId = REDFISH_IPMI_GROUP_EXTENSION;
49 CommandData.DisableBootstrapControl = REDFISH_IPMI_BOOTSTRAP_CREDENTIAL_ENABLE;
50 ResponseData.CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
51 ResponseSize = sizeof (ResponseData);
52 //
53 // Response data: Ignored.
54 //
55 Status = IpmiSubmitCommand (
56 IPMI_NETFN_GROUP_EXT,
57 REDFISH_IPMI_GET_BOOTSTRAP_CREDENTIALS_CMD,
58 (UINT8 *)&CommandData,
59 sizeof (CommandData),
60 (UINT8 *)&ResponseData,
61 &ResponseSize
62 );
63 if (!EFI_ERROR (Status) &&
64 ((ResponseData.CompletionCode == IPMI_COMP_CODE_NORMAL) ||
65 (ResponseData.CompletionCode == REDFISH_IPMI_COMP_CODE_BOOTSTRAP_CREDENTIAL_DISABLED)
66 ))
67 {
68 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Redfish Credential Bootstrapping is supported\n"));
69 ReturnBool = TRUE;
70 } else {
71 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Redfish Credential Bootstrapping is not supported\n"));
72 ReturnBool = FALSE;
73 }
74
75 return ReturnBool;
76}
77
78/**
79 Get platform Redfish host interface device descriptor.
80
81 @param[in] DeviceType Pointer to retrieve device type.
82 @param[out] DeviceDescriptor Pointer to retrieve REDFISH_INTERFACE_DATA, caller has to free
83 this memory using FreePool().
84
85 @retval EFI_NOT_FOUND No Redfish host interface descriptor provided on this platform.
86
87**/
88EFI_STATUS
89RedfishPlatformHostInterfaceDeviceDescriptor (
90 IN UINT8 *DeviceType,
91 OUT REDFISH_INTERFACE_DATA **DeviceDescriptor
92 )
93{
94 HOST_INTERFACE_BMC_USB_NIC_INFO *ThisInstance;
95 REDFISH_INTERFACE_DATA *InterfaceData;
96
97 DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry\n", __func__));
98
99 if (IsListEmpty (&mBmcUsbNic)) {
100 return EFI_NOT_FOUND;
101 }
102
103 // Check if BMC exposed USB NIC is found and ready for using.
104 ThisInstance = (HOST_INTERFACE_BMC_USB_NIC_INFO *)GetFirstNode (&mBmcUsbNic);
105 while (TRUE) {
106 if (ThisInstance->IsExposedByBmc && ThisInstance->IsSuppportedHostInterface) {
107 *DeviceType = REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2;
108
109 // Fill up REDFISH_INTERFACE_DATA defined in Redfish host interface spec v1.3
110 InterfaceData = (REDFISH_INTERFACE_DATA *)AllocateZeroPool (USB_INTERFACE_DEVICE_DESCRIPTOR_V2_SIZE_1_3);
111 if (InterfaceData == NULL) {
112 DEBUG ((DEBUG_ERROR, "Failed to allocate memory for REDFISH_INTERFACE_DATA\n"));
113 return EFI_OUT_OF_RESOURCES;
114 }
115
116 InterfaceData->DeviceType = REDFISH_HOST_INTERFACE_DEVICE_TYPE_USB_V2;
117 InterfaceData->DeviceDescriptor.UsbDeviceV2.Length = USB_INTERFACE_DEVICE_DESCRIPTOR_V2_SIZE_1_3;
118 InterfaceData->DeviceDescriptor.UsbDeviceV2.IdVendor = ThisInstance->UsbVendorId;
119 InterfaceData->DeviceDescriptor.UsbDeviceV2.IdProduct = ThisInstance->UsbProductId;
120 InterfaceData->DeviceDescriptor.UsbDeviceV2.SerialNumberStr = 0;
121 CopyMem (
122 (VOID *)&InterfaceData->DeviceDescriptor.UsbDeviceV2.MacAddress,
123 (VOID *)ThisInstance->MacAddress,
124 sizeof (InterfaceData->DeviceDescriptor.UsbDeviceV2.MacAddress)
125 );
126 InterfaceData->DeviceDescriptor.UsbDeviceV2.Characteristics |= (UINT16)ThisInstance->CredentialBootstrapping;
127 InterfaceData->DeviceDescriptor.UsbDeviceV2.CredentialBootstrappingHandle = 0;
128 *DeviceDescriptor = InterfaceData;
129 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " REDFISH_INTERFACE_DATA is returned successfully.\n"));
130 return EFI_SUCCESS;
131 }
132
133 if (IsNodeAtEnd (&mBmcUsbNic, &ThisInstance->NextInstance)) {
134 break;
135 }
136
137 ThisInstance = (HOST_INTERFACE_BMC_USB_NIC_INFO *)
138 GetNextNode (&mBmcUsbNic, &ThisInstance->NextInstance);
139 }
140
141 return EFI_NOT_FOUND;
142}
143
144/**
145 Get platform Redfish host interface protocol data.
146 Caller should pass NULL in ProtocolRecord to retrive the first protocol record.
147 Then continuously pass previous ProtocolRecord for retrieving the next ProtocolRecord.
148
149 @param[in, out] ProtocolRecord Pointer to retrieve the first or the next protocol record.
150 caller has to free the new protocol record returned from
151 this function using FreePool().
152 @param[in] IndexOfProtocolData The index of protocol data.
153
154 @retval EFI_NOT_FOUND No more protocol records.
155
156**/
157EFI_STATUS
158RedfishPlatformHostInterfaceProtocolData (
159 IN OUT MC_HOST_INTERFACE_PROTOCOL_RECORD **ProtocolRecord,
160 IN UINT8 IndexOfProtocolData
161 )
162{
163 HOST_INTERFACE_BMC_USB_NIC_INFO *ThisInstance;
164 MC_HOST_INTERFACE_PROTOCOL_RECORD *ThisProtocolRecord;
165 REDFISH_OVER_IP_PROTOCOL_DATA *RedfishOverIpData;
166 UINT8 HostNameLength;
167 CHAR8 *HostNameString;
168
169 DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry\n", __func__));
170
171 if (IsListEmpty (&mBmcUsbNic) || (IndexOfProtocolData > 0)) {
172 return EFI_NOT_FOUND;
173 }
174
175 ThisInstance = (HOST_INTERFACE_BMC_USB_NIC_INFO *)GetFirstNode (&mBmcUsbNic);
176 while (TRUE) {
177 if (ThisInstance->IsExposedByBmc && ThisInstance->IsSuppportedHostInterface) {
178 // Get the host name before allocating memory.
179 HostNameString = (CHAR8 *)PcdGetPtr (PcdRedfishHostName);
180 HostNameLength = (UINT8)AsciiStrSize (HostNameString);
181 ThisProtocolRecord = (MC_HOST_INTERFACE_PROTOCOL_RECORD *)AllocateZeroPool (
182 sizeof (MC_HOST_INTERFACE_PROTOCOL_RECORD) - 1 +
183 sizeof (REDFISH_OVER_IP_PROTOCOL_DATA) - 1 +
184 HostNameLength
185 );
186 if (ThisProtocolRecord == NULL) {
187 DEBUG ((DEBUG_ERROR, " Allocate memory fail for MC_HOST_INTERFACE_PROTOCOL_RECORD.\n"));
188 return EFI_OUT_OF_RESOURCES;
189 }
190
191 ThisProtocolRecord->ProtocolType = MCHostInterfaceProtocolTypeRedfishOverIP;
192 ThisProtocolRecord->ProtocolTypeDataLen = sizeof (REDFISH_OVER_IP_PROTOCOL_DATA) -1 + HostNameLength;
193 RedfishOverIpData = (REDFISH_OVER_IP_PROTOCOL_DATA *)&ThisProtocolRecord->ProtocolTypeData[0];
194 //
195 // Fill up REDFISH_OVER_IP_PROTOCOL_DATA
196 //
197
198 // Service UUID
199 ZeroMem ((VOID *)&RedfishOverIpData->ServiceUuid, sizeof (EFI_GUID));
200 if (StrLen ((CONST CHAR16 *)PcdGetPtr (PcdRedfishServiceUuid)) != 0) {
201 StrToGuid ((CONST CHAR16 *)PcdGetPtr (PcdRedfishServiceUuid), &RedfishOverIpData->ServiceUuid);
202 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Service UUID: %g", &RedfishOverIpData->ServiceUuid));
203 }
204
205 // HostIpAddressFormat and RedfishServiceIpDiscoveryType
206 RedfishOverIpData->HostIpAssignmentType = RedfishHostIpAssignmentUnknown;
207 RedfishOverIpData->RedfishServiceIpDiscoveryType = RedfishHostIpAssignmentUnknown;
208 if (ThisInstance->IpAssignedType == IpmiStaticAddrsss) {
209 RedfishOverIpData->HostIpAssignmentType = RedfishHostIpAssignmentStatic;
210 RedfishOverIpData->RedfishServiceIpDiscoveryType = RedfishHostIpAssignmentStatic;
211 } else if (ThisInstance->IpAssignedType == IpmiDynamicAddressBmcDhcp) {
212 RedfishOverIpData->HostIpAssignmentType = RedfishHostIpAssignmentDhcp;
213 RedfishOverIpData->RedfishServiceIpDiscoveryType = RedfishHostIpAssignmentDhcp;
214 }
215
216 // HostIpAddressFormat and RedfishServiceIpAddressFormat, only support IPv4 for now.
217 RedfishOverIpData->HostIpAddressFormat = REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP4;
218 RedfishOverIpData->RedfishServiceIpAddressFormat = REDFISH_HOST_INTERFACE_HOST_IP_ADDRESS_FORMAT_IP4;
219
220 // HostIpAddress
221 CopyMem (
222 (VOID *)RedfishOverIpData->HostIpAddress,
223 (VOID *)ThisInstance->HostIpAddressIpv4,
224 sizeof (ThisInstance->HostIpAddressIpv4)
225 );
226
227 // HostIpMask and RedfishServiceIpMask
228 CopyMem (
229 (VOID *)RedfishOverIpData->HostIpMask,
230 (VOID *)ThisInstance->SubnetMaskIpv4,
231 sizeof (ThisInstance->SubnetMaskIpv4)
232 );
233 CopyMem (
234 (VOID *)RedfishOverIpData->RedfishServiceIpMask,
235 (VOID *)ThisInstance->SubnetMaskIpv4,
236 sizeof (ThisInstance->SubnetMaskIpv4)
237 );
238
239 // RedfishServiceIpAddress
240 CopyMem (
241 (VOID *)RedfishOverIpData->RedfishServiceIpAddress,
242 (VOID *)ThisInstance->RedfishIpAddressIpv4,
243 sizeof (ThisInstance->RedfishIpAddressIpv4)
244 );
245
246 // RedfishServiceIpPort
247 RedfishOverIpData->RedfishServiceIpPort = PcdGet16 (PcdRedfishServicePort);
248
249 // RedfishServiceVlanId
250 RedfishOverIpData->RedfishServiceVlanId = ThisInstance->VLanId;
251
252 // RedfishServiceHostnameLength
253 RedfishOverIpData->RedfishServiceHostnameLength = HostNameLength;
254
255 // Redfish host name.
256 CopyMem (
257 (VOID *)&RedfishOverIpData->RedfishServiceHostname,
258 (VOID *)HostNameString,
259 HostNameLength
260 );
261
262 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " MC_HOST_INTERFACE_PROTOCOL_RECORD is returned successfully.\n"));
263 *ProtocolRecord = ThisProtocolRecord;
264 return EFI_SUCCESS;
265 }
266
267 if (IsNodeAtEnd (&mBmcUsbNic, &ThisInstance->NextInstance)) {
268 break;
269 }
270
271 ThisInstance = (HOST_INTERFACE_BMC_USB_NIC_INFO *)
272 GetNextNode (&mBmcUsbNic, &ThisInstance->NextInstance);
273 }
274
275 return EFI_NOT_FOUND;
276}
277
278/**
279 This function retrieve the information of BMC USB NIC.
280
281 @retval EFI_SUCCESS All necessary information is retrieved.
282 @retval EFI_NOT_FOUND There is no BMC exposed USB NIC.
283 @retval Others Other errors.
284
285**/
286EFI_STATUS
287RetrievedBmcUsbNicInfo (
288 VOID
289 )
290{
291 EFI_STATUS Status;
292 UINT32 ResponseDataSize;
293 HOST_INTERFACE_BMC_USB_NIC_INFO *ThisInstance;
294 IPMI_GET_LAN_CONFIGURATION_PARAMETERS_REQUEST GetLanConfigReq;
295 IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *GetLanConfigReps;
296 IPMI_LAN_IP_ADDRESS_SRC *IpAddressSrc;
297 IPMI_LAN_IP_ADDRESS *DestIpAddress;
298 IPMI_LAN_SUBNET_MASK *SubnetMask;
299 IPMI_LAN_DEFAULT_GATEWAY *DefaultGateway;
300 IPMI_LAN_VLAN_ID *LanVlanId;
301 EFI_USB_DEVICE_DESCRIPTOR UsbDeviceDescriptor;
302
303 DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry\n", __func__));
304
305 if (IsListEmpty (&mBmcUsbNic)) {
306 return EFI_NOT_FOUND;
307 }
308
309 ThisInstance = (HOST_INTERFACE_BMC_USB_NIC_INFO *)GetFirstNode (&mBmcUsbNic);
310 while (TRUE) {
311 if (ThisInstance->IsExposedByBmc) {
312 ThisInstance->IsSuppportedHostInterface = FALSE;
313
314 // Probe if Redfish Host Interface Credential Bootstrapping is supported.
315 ThisInstance->CredentialBootstrapping = ProbeRedfishCredentialBootstrap ();
316
317 // Get IP address source
318 GetLanConfigReq.SetSelector = 0;
319 GetLanConfigReq.BlockSelector = 0;
320 GetLanConfigReq.ChannelNumber.Bits.ChannelNo = ThisInstance->IpmiLanChannelNumber;
321 GetLanConfigReq.ChannelNumber.Bits.GetParameter = 0;
322 GetLanConfigReq.ChannelNumber.Bits.Reserved = 0;
323 GetLanConfigReq.ParameterSelector = IpmiLanIpAddressSource;
324 ResponseDataSize = sizeof (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE) + sizeof (IPMI_LAN_IP_ADDRESS_SRC);
325 GetLanConfigReps = (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *)AllocateZeroPool (ResponseDataSize);
326 GetLanConfigReps->CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
327 Status = IpmiGetLanConfigurationParameters (
328 &GetLanConfigReq,
329 GetLanConfigReps,
330 &ResponseDataSize
331 );
332 if (EFI_ERROR (Status) || (GetLanConfigReps->CompletionCode != IPMI_COMP_CODE_NORMAL)) {
333 DEBUG ((DEBUG_ERROR, " Failed to get IP address source at channel %d: %r, 0x%02x.\n", ThisInstance->IpmiLanChannelNumber, Status, GetLanConfigReps->CompletionCode));
334 FreePool (GetLanConfigReps);
335 return Status;
336 }
337
338 IpAddressSrc = (IPMI_LAN_IP_ADDRESS_SRC *)(GetLanConfigReps + 1);
339 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " IP address source at channel %d: %x\n", ThisInstance->IpmiLanChannelNumber, IpAddressSrc->Bits.AddressSrc));
340 ThisInstance->IpAssignedType = IpAddressSrc->Bits.AddressSrc;
341 FreePool (GetLanConfigReps);
342
343 // Get LAN IPv4 IP address
344 GetLanConfigReq.ParameterSelector = IpmiLanIpAddress;
345 ResponseDataSize = sizeof (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE) + sizeof (IPMI_LAN_IP_ADDRESS);
346 GetLanConfigReps = (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *)AllocateZeroPool (ResponseDataSize);
347 GetLanConfigReps->CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
348 Status = IpmiGetLanConfigurationParameters (
349 &GetLanConfigReq,
350 GetLanConfigReps,
351 &ResponseDataSize
352 );
353 if (EFI_ERROR (Status) || (GetLanConfigReps->CompletionCode != IPMI_COMP_CODE_NORMAL)) {
354 DEBUG ((DEBUG_ERROR, " Failed to get Dest IP address at channel %d: %r, 0x%02x.\n", ThisInstance->IpmiLanChannelNumber, Status, GetLanConfigReps->CompletionCode));
355 FreePool (GetLanConfigReps);
356 return Status;
357 }
358
359 DestIpAddress = (IPMI_LAN_IP_ADDRESS *)(GetLanConfigReps + 1);
360 DEBUG ((
361 DEBUG_REDFISH_HOST_INTERFACE,
362 " Dest IP address at channel %d: %d.%d.%d.%d\n",
363 ThisInstance->IpmiLanChannelNumber,
364 DestIpAddress->IpAddress[0],
365 DestIpAddress->IpAddress[1],
366 DestIpAddress->IpAddress[2],
367 DestIpAddress->IpAddress[3]
368 ));
369 CopyMem ((VOID *)&ThisInstance->RedfishIpAddressIpv4, (VOID *)&DestIpAddress->IpAddress, sizeof (DestIpAddress->IpAddress));
370 //
371 // According to the design spec:
372 // https://github.com/tianocore/edk2/tree/master/RedfishPkg#platform-with-bmc-and-the-bmc-exposed-usb-network-device
373 // The IP address at BMC USB NIC host end is the IP address at BMC end minus 1.
374 //
375 CopyMem ((VOID *)&ThisInstance->HostIpAddressIpv4, (VOID *)&DestIpAddress->IpAddress, sizeof (DestIpAddress->IpAddress));
376 ThisInstance->HostIpAddressIpv4[sizeof (ThisInstance->HostIpAddressIpv4) - 1] -= 1;
377 FreePool (GetLanConfigReps);
378 DEBUG ((
379 DEBUG_REDFISH_HOST_INTERFACE,
380 " Host IP address at channel %d: %d.%d.%d.%d\n",
381 ThisInstance->IpmiLanChannelNumber,
382 ThisInstance->HostIpAddressIpv4[0],
383 ThisInstance->HostIpAddressIpv4[1],
384 ThisInstance->HostIpAddressIpv4[2],
385 ThisInstance->HostIpAddressIpv4[3]
386 ));
387
388 // Get IPv4 subnet mask
389 GetLanConfigReq.ParameterSelector = IpmiLanSubnetMask;
390 ResponseDataSize = sizeof (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE) + sizeof (IPMI_LAN_SUBNET_MASK);
391 GetLanConfigReps = (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *)AllocateZeroPool (ResponseDataSize);
392 GetLanConfigReps->CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
393 Status = IpmiGetLanConfigurationParameters (
394 &GetLanConfigReq,
395 GetLanConfigReps,
396 &ResponseDataSize
397 );
398 if ((EFI_ERROR (Status)) || (GetLanConfigReps->CompletionCode != IPMI_COMP_CODE_NORMAL)) {
399 DEBUG ((DEBUG_ERROR, " Failed to get subnet mask at channel %d: %r, 0x%02x.\n", ThisInstance->IpmiLanChannelNumber, Status, GetLanConfigReps->CompletionCode));
400 FreePool (GetLanConfigReps);
401 return Status;
402 }
403
404 SubnetMask = (IPMI_LAN_SUBNET_MASK *)(GetLanConfigReps + 1);
405 DEBUG ((
406 DEBUG_REDFISH_HOST_INTERFACE,
407 " Subnet mask at channel %d: %d.%d.%d.%d\n",
408 ThisInstance->IpmiLanChannelNumber,
409 SubnetMask->IpAddress[0],
410 SubnetMask->IpAddress[1],
411 SubnetMask->IpAddress[2],
412 SubnetMask->IpAddress[3]
413 ));
414 CopyMem ((VOID *)&ThisInstance->SubnetMaskIpv4, (VOID *)&SubnetMask->IpAddress, sizeof (SubnetMask->IpAddress));
415 FreePool (GetLanConfigReps);
416
417 // Get Gateway IP address.
418 GetLanConfigReq.ParameterSelector = IpmiLanDefaultGateway;
419 ResponseDataSize = sizeof (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE) + sizeof (IPMI_LAN_DEFAULT_GATEWAY);
420 GetLanConfigReps = (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *)AllocateZeroPool (ResponseDataSize);
421 GetLanConfigReps->CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
422 Status = IpmiGetLanConfigurationParameters (
423 &GetLanConfigReq,
424 GetLanConfigReps,
425 &ResponseDataSize
426 );
427 if ((EFI_ERROR (Status)) || (GetLanConfigReps->CompletionCode != IPMI_COMP_CODE_NORMAL)) {
428 DEBUG ((DEBUG_ERROR, " Failed to get default gateway at channel %d: %r, 0x%02x.\n", ThisInstance->IpmiLanChannelNumber, Status, GetLanConfigReps->CompletionCode));
429 FreePool (GetLanConfigReps);
430 return Status;
431 }
432
433 DefaultGateway = (IPMI_LAN_DEFAULT_GATEWAY *)(GetLanConfigReps + 1);
434 DEBUG ((
435 DEBUG_REDFISH_HOST_INTERFACE,
436 " Gateway at channel %d: %d.%d.%d.%d\n",
437 ThisInstance->IpmiLanChannelNumber,
438 DefaultGateway->IpAddress[0],
439 DefaultGateway->IpAddress[1],
440 DefaultGateway->IpAddress[2],
441 DefaultGateway->IpAddress[3]
442 ));
443 CopyMem ((VOID *)&ThisInstance->GatewayIpv4, (VOID *)&DefaultGateway->IpAddress, sizeof (DefaultGateway->IpAddress));
444 FreePool (GetLanConfigReps);
445
446 // Get VLAN ID
447 GetLanConfigReq.ParameterSelector = IpmiLanVlanId;
448 ResponseDataSize = sizeof (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE) + sizeof (IPMI_LAN_VLAN_ID);
449 GetLanConfigReps = (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *)AllocateZeroPool (ResponseDataSize);
450 GetLanConfigReps->CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
451 Status = IpmiGetLanConfigurationParameters (
452 &GetLanConfigReq,
453 GetLanConfigReps,
454 &ResponseDataSize
455 );
456 if ((EFI_ERROR (Status)) || (GetLanConfigReps->CompletionCode != IPMI_COMP_CODE_NORMAL)) {
457 DEBUG ((DEBUG_ERROR, " Failed to get VLAN ID at channel %d: %r, 0x%02x.\n", ThisInstance->IpmiLanChannelNumber, Status, GetLanConfigReps->CompletionCode));
458 FreePool (GetLanConfigReps);
459 return Status;
460 }
461
462 LanVlanId = (IPMI_LAN_VLAN_ID *)(GetLanConfigReps + 1);
463 ThisInstance->VLanId = 0;
464 if (LanVlanId->Data2.Bits.Enabled == 1) {
465 ThisInstance->VLanId = LanVlanId->Data1.VanIdLowByte | (LanVlanId->Data2.Bits.VanIdHighByte << 8);
466 }
467
468 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " VLAN ID %x\n", ThisInstance->VLanId));
469
470 FreePool (GetLanConfigReps);
471
472 //
473 // Read USB device information.
474 //
475 if (ThisInstance->ThisUsbIo != NULL) {
476 Status = ThisInstance->ThisUsbIo->UsbGetDeviceDescriptor (ThisInstance->ThisUsbIo, &UsbDeviceDescriptor);
477 if (!EFI_ERROR (Status)) {
478 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " USB NIC Vendor ID: 0x%04x, Device ID: 0x%04x\n", UsbDeviceDescriptor.IdVendor, UsbDeviceDescriptor.IdProduct));
479 ThisInstance->UsbVendorId = UsbDeviceDescriptor.IdVendor;
480 ThisInstance->UsbProductId = UsbDeviceDescriptor.IdProduct;
481 } else {
482 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Fail to get USB device descriptor.\n"));
483 }
484 }
485
486 // All information is retrieved.
487 ThisInstance->IsSuppportedHostInterface = TRUE;
488 return EFI_SUCCESS;
489 }
490
491 if (IsNodeAtEnd (&mBmcUsbNic, &ThisInstance->NextInstance)) {
492 break;
493 }
494
495 ThisInstance = (HOST_INTERFACE_BMC_USB_NIC_INFO *)
496 GetNextNode (&mBmcUsbNic, &ThisInstance->NextInstance);
497 }
498
499 return EFI_NOT_FOUND;
500}
501
502/**
503 This function caches the found IPMI LAN channel. So we
504 don't have to sedn IPMI commands again if the USB NIC is
505 connected later.
506
507 @param[in] ChannelNum The IPMI channel number.
508 @param[in] IpmiLanChannelMacAddress Pointer to EFI_MAC_ADDRESS.
509 @param[in] IpmiLanMacAddressSize The MAC address size.
510
511 @retval EFI_SUCCESS IPMI LAN channel is cached.
512 @retval EFI_OUT_OF_RESOURCE Memory allocated failed.
513 @retval Others Other errors.
514
515**/
516EFI_STATUS
517CacheIpmiLanMac (
518 IN UINT8 ChannelNum,
519 IN EFI_MAC_ADDRESS *IpmiLanChannelMacAddress,
520 IN UINT8 IpmiLanMacAddressSize
521 )
522{
523 BMC_IPMI_LAN_CHANNEL_INFO *ChannelInfo;
524
525 ChannelInfo = (BMC_IPMI_LAN_CHANNEL_INFO *)AllocateZeroPool (sizeof (BMC_IPMI_LAN_CHANNEL_INFO));
526 if (ChannelInfo == NULL) {
527 return EFI_OUT_OF_RESOURCES;
528 }
529
530 ChannelInfo->Channel = ChannelNum;
531 CopyMem ((VOID *)&ChannelInfo->MacAddress.Addr, (VOID *)IpmiLanChannelMacAddress->Addr, IpmiLanMacAddressSize);
532 ChannelInfo->MacAddressSize = IpmiLanMacAddressSize;
533 InitializeListHead (&ChannelInfo->NextInstance);
534 InsertTailList (&mBmcIpmiLan, &ChannelInfo->NextInstance);
535 return EFI_SUCCESS;
536}
537
538/**
539 This function checks if the IPMI channel already identified
540 previously.
541
542 @param[in] ChannelNum The IPMI channel number.
543 @param[out] CachedIpmiLanChannel Pointer to retrieve the cached
544 BMC_IPMI_LAN_CHANNEL_INFO.
545
546 @retval EFI_SUCCESS IPMI LAN channel is found.
547 @retval Others Other errors.
548
549**/
550EFI_STATUS
551CheckCachedIpmiLanMac (
552 IN UINT8 ChannelNum,
553 OUT BMC_IPMI_LAN_CHANNEL_INFO **CachedIpmiLanChannel
554 )
555{
556 BMC_IPMI_LAN_CHANNEL_INFO *ThisInstance;
557
558 if (IsListEmpty (&mBmcIpmiLan)) {
559 return EFI_NOT_FOUND;
560 }
561
562 ThisInstance = (BMC_IPMI_LAN_CHANNEL_INFO *)GetFirstNode (&mBmcIpmiLan);
563 while (TRUE) {
564 if (ThisInstance->Channel == ChannelNum) {
565 *CachedIpmiLanChannel = ThisInstance;
566 return EFI_SUCCESS;
567 }
568
569 if (IsNodeAtEnd (&mBmcIpmiLan, &ThisInstance->NextInstance)) {
570 break;
571 }
572
573 ThisInstance = (BMC_IPMI_LAN_CHANNEL_INFO *)
574 GetNextNode (&mBmcIpmiLan, &ThisInstance->NextInstance);
575 }
576
577 return EFI_NOT_FOUND;
578}
579
580/**
581 This function goes through IPMI channels to find the
582 mactched MAC addrss of BMC USB NIC endpoint.
583
584 @param[in] UsbNicInfo The instance of HOST_INTERFACE_BMC_USB_NIC_INFO.
585
586 @retval EFI_SUCCESS Yes, USB NIC exposed by BMC is found.
587 @retval EFI_NOT_FOUND No, USB NIC exposed by BMC is not found
588 on the existing SNP handle.
589 @retval Others Other errors.
590
591**/
592EFI_STATUS
593HostInterfaceIpmiCheckMacAddress (
594 IN HOST_INTERFACE_BMC_USB_NIC_INFO *UsbNicInfo
595 )
596{
597 EFI_STATUS Status;
598 EFI_STATUS ExitStatus;
599 UINTN ChannelNum;
600 UINT32 ResponseDataSize;
601 IPMI_GET_CHANNEL_INFO_REQUEST GetChanelInfoRequest;
602 IPMI_GET_CHANNEL_INFO_RESPONSE GetChanelInfoResponse;
603 IPMI_GET_LAN_CONFIGURATION_PARAMETERS_REQUEST GetLanConfigReq;
604 IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *GetLanConfigReps;
605 BMC_IPMI_LAN_CHANNEL_INFO *CachedIpmiLanChannel;
606 UINT8 IpmiLanMacAddressSize;
607 EFI_MAC_ADDRESS IpmiLanChannelMacAddress;
608 BOOLEAN AlreadyCached;
609
610 DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry.\n", __func__));
611
612 GetLanConfigReps = NULL;
613 AlreadyCached = FALSE;
614 if (!IsListEmpty (&mBmcIpmiLan)) {
615 AlreadyCached = TRUE;
616 }
617
618 // Initial the get MAC address request.
619 GetLanConfigReq.ChannelNumber.Uint8 = 0;
620 GetLanConfigReq.SetSelector = 0;
621 GetLanConfigReq.BlockSelector = 0;
622 GetLanConfigReq.ParameterSelector = IpmiLanMacAddress;
623
624 ExitStatus = EFI_NOT_FOUND;
625 for (ChannelNum = IPMI_CHANNEL_NUMBER_IMPLEMENTATION_SPECIFIC_1;
626 ChannelNum <= IPMI_CHANNEL_NUMBER_IMPLEMENTATION_SPECIFIC_11;
627 ChannelNum++)
628 {
629 IpmiLanMacAddressSize = 0;
630
631 // Check if the IPMI channel information is already cached.
632 Status = EFI_NOT_FOUND;
633 if (AlreadyCached) {
634 Status = CheckCachedIpmiLanMac ((UINT8)ChannelNum, &CachedIpmiLanChannel);
635 }
636
637 if (Status == EFI_SUCCESS) {
638 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Got cached IPMI LAN info.\n"));
639 IpmiLanMacAddressSize = sizeof (IPMI_LAN_MAC_ADDRESS);
640 CopyMem ((VOID *)&IpmiLanChannelMacAddress.Addr, (VOID *)&CachedIpmiLanChannel->MacAddress.Addr, IpmiLanMacAddressSize);
641 } else {
642 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " No cached IPMI LAN info\n"));
643 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Send NetFn = App, Command = 0x42 to channel %d\n", ChannelNum));
644 GetChanelInfoRequest.ChannelNumber.Uint8 = 0;
645 GetChanelInfoRequest.ChannelNumber.Bits.ChannelNo = (UINT8)ChannelNum;
646 Status = IpmiGetChannelInfo (
647 &GetChanelInfoRequest,
648 &GetChanelInfoResponse,
649 &ResponseDataSize
650 );
651 if (EFI_ERROR (Status)) {
652 DEBUG ((DEBUG_ERROR, " - Channel %d fails to send command.\n", ChannelNum));
653 continue;
654 }
655
656 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " - Response data size = 0x%x\n", ResponseDataSize));
657 if ((GetChanelInfoResponse.CompletionCode != IPMI_COMP_CODE_NORMAL) || (ResponseDataSize == 0)) {
658 DEBUG ((DEBUG_ERROR, " - Command returned fail: 0x%x.\n", GetChanelInfoResponse.CompletionCode));
659 continue;
660 }
661
662 DEBUG ((
663 DEBUG_REDFISH_HOST_INTERFACE,
664 " - Channel protocol = 0x%x, Media = 0x%x\n",
665 GetChanelInfoResponse.ProtocolType.Bits.ChannelProtocolType,
666 GetChanelInfoResponse.MediumType.Bits.ChannelMediumType
667 ));
668
669 if (GetChanelInfoResponse.ChannelNumber.Bits.ChannelNo != ChannelNum) {
670 DEBUG ((
671 DEBUG_ERROR,
672 " - ChannelNumber = %d in the response which is not macthed to the request.\n",
673 GetChanelInfoResponse.ChannelNumber.Bits.ChannelNo
674 ));
675 continue;
676 }
677
678 if ((GetChanelInfoResponse.MediumType.Bits.ChannelMediumType == IPMI_CHANNEL_MEDIA_TYPE_802_3_LAN) &&
679 (GetChanelInfoResponse.ProtocolType.Bits.ChannelProtocolType == IPMI_CHANNEL_PROTOCOL_TYPE_IPMB_1_0))
680 {
681 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " - Channel %d is a LAN device!\n", ChannelNum));
682
683 ResponseDataSize = sizeof (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE) +
684 sizeof (IPMI_LAN_MAC_ADDRESS);
685 if (GetLanConfigReps == NULL) {
686 GetLanConfigReps =
687 (IPMI_GET_LAN_CONFIGURATION_PARAMETERS_RESPONSE *)AllocateZeroPool (ResponseDataSize);
688 if (GetLanConfigReps == NULL) {
689 DEBUG ((DEBUG_ERROR, " Allocate memory failed for getting MAC address.\n"));
690 continue;
691 }
692 }
693
694 GetLanConfigReq.ChannelNumber.Bits.ChannelNo = (UINT8)ChannelNum;
695 GetLanConfigReps->CompletionCode = IPMI_COMP_CODE_UNSPECIFIED;
696 Status = IpmiGetLanConfigurationParameters (
697 &GetLanConfigReq,
698 GetLanConfigReps,
699 &ResponseDataSize
700 );
701 if (EFI_ERROR (Status) || (GetLanConfigReps->CompletionCode != IPMI_COMP_CODE_NORMAL)) {
702 DEBUG ((
703 DEBUG_ERROR,
704 " Fails to get MAC address of channel %d, CompletionCode = %02x.\n",
705 ChannelNum,
706 GetLanConfigReps->CompletionCode
707 ));
708 continue;
709 } else {
710 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " The MAC address of channel %d.\n", ChannelNum));
711 DEBUG ((
712 DEBUG_REDFISH_HOST_INTERFACE,
713 " %02x:%02x:%02x:%02x:%02x:%02x\n",
714 *((UINT8 *)(GetLanConfigReps + 1) + 0),
715 *((UINT8 *)(GetLanConfigReps + 1) + 1),
716 *((UINT8 *)(GetLanConfigReps + 1) + 2),
717 *((UINT8 *)(GetLanConfigReps + 1) + 3),
718 *((UINT8 *)(GetLanConfigReps + 1) + 4),
719 *((UINT8 *)(GetLanConfigReps + 1) + 5)
720 ));
721 IpmiLanMacAddressSize = sizeof (IPMI_LAN_MAC_ADDRESS);
722 CopyMem ((VOID *)&IpmiLanChannelMacAddress.Addr, (VOID *)(GetLanConfigReps + 1), IpmiLanMacAddressSize);
723 }
724 }
725 }
726
727 if (IpmiLanMacAddressSize != 0) {
728 if (!AlreadyCached) {
729 // Cache this IPMI LAN channel.
730 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Cache this IPMI LAN channel.\n"));
731 CacheIpmiLanMac ((UINT8)ChannelNum, &IpmiLanChannelMacAddress, IpmiLanMacAddressSize);
732 }
733
734 //
735 // According to design spec in Readme file under RedfishPkg.
736 // https://github.com/tianocore/edk2/tree/master/RedfishPkg#platform-with-bmc-and-the-bmc-exposed-usb-network-device
737 // Compare the first five elements of MAC address and the 6th element of MAC address.
738 // The 6th element of MAC address must be the 6th element of
739 // IPMI channel MAC address minus 1.
740 //
741 if ((IpmiLanMacAddressSize != UsbNicInfo->MacAddressSize) ||
742 (CompareMem (
743 (VOID *)UsbNicInfo->MacAddress,
744 (VOID *)&IpmiLanChannelMacAddress.Addr,
745 IpmiLanMacAddressSize - 1
746 ) != 0) ||
747 ((IpmiLanChannelMacAddress.Addr[IpmiLanMacAddressSize - 1] - 1) !=
748 *(UsbNicInfo->MacAddress + IpmiLanMacAddressSize - 1))
749 )
750 {
751 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " MAC address is not matched.\n"));
752 continue;
753 }
754
755 // This is the NIC exposed by BMC.
756 UsbNicInfo->IpmiLanChannelNumber = (UINT8)ChannelNum;
757 UsbNicInfo->IsExposedByBmc = TRUE;
758 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " MAC address is matched.\n"));
759 ExitStatus = EFI_SUCCESS;
760 break;
761 }
762 }
763
764 if (GetLanConfigReps != NULL) {
765 FreePool (GetLanConfigReps);
766 }
767
768 return ExitStatus;
769}
770
771/**
772 This function searches the next MSG_USB_DP device path node.
773
774 @param[in] ThisDevicePath Device path to search.
775
776 @retval NULL MSG_USB_DP is not found.
777 Otherwise MSG_USB_DP is found.
778
779**/
780EFI_DEVICE_PATH_PROTOCOL *
781UsbNicGetNextMsgUsbDp (
782 IN EFI_DEVICE_PATH_PROTOCOL *ThisDevicePath
783 )
784{
785 if (ThisDevicePath == NULL) {
786 return NULL;
787 }
788
789 while (TRUE) {
790 ThisDevicePath = NextDevicePathNode (ThisDevicePath);
791 if (IsDevicePathEnd (ThisDevicePath)) {
792 return NULL;
793 }
794
795 if ((ThisDevicePath->Type == MESSAGING_DEVICE_PATH) && (ThisDevicePath->SubType == MSG_USB_DP)) {
796 return ThisDevicePath;
797 }
798 }
799
800 return NULL;
801}
802
803/**
804 This function search the UsbIo handle that matches the UsbDevicePath.
805
806 @param[in] UsbDevicePath Device path of this SNP handle.
807 @param[out] UsbIo Return the UsbIo protocol.
808
809 @retval EFI_SUCCESS Yes, UsbIo protocl is found.
810 @retval EFI_NOT_FOUND No, UsbIo protocl is not found
811 @retval Others Other errors.
812
813**/
814EFI_STATUS
815UsbNicSearchUsbIo (
816 IN EFI_DEVICE_PATH_PROTOCOL *UsbDevicePath,
817 OUT EFI_USB_IO_PROTOCOL **UsbIo
818 )
819{
820 EFI_STATUS Status;
821 UINTN BufferSize;
822 EFI_HANDLE *HandleBuffer;
823 UINT16 Length;
824 UINTN Index;
825 CHAR16 *DevicePathStr;
826 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
827 EFI_DEVICE_PATH_PROTOCOL *ThisDevicePath;
828 EFI_DEVICE_PATH_PROTOCOL *ThisDevicePathEnd;
829 EFI_DEVICE_PATH_PROTOCOL *ThisUsbDevicePath;
830 EFI_DEVICE_PATH_PROTOCOL *ThisUsbDevicePathEnd;
831
832 DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry.\n", __func__));
833 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "Device path on the EFI handle which has UsbIo and SNP instaleld on it.\n"));
834 DevicePathStr = ConvertDevicePathToText (UsbDevicePath, FALSE, FALSE);
835 if (DevicePathStr != NULL) {
836 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "%s\n", DevicePathStr));
837 FreePool (DevicePathStr);
838 } else {
839 DEBUG ((DEBUG_ERROR, "Failed to convert device path.\n"));
840 return EFI_INVALID_PARAMETER;
841 }
842
843 BufferSize = 0;
844 HandleBuffer = NULL;
845 *UsbIo = NULL;
846 Status = gBS->LocateHandle (
847 ByProtocol,
848 &gEfiUsbIoProtocolGuid,
849 NULL,
850 &BufferSize,
851 NULL
852 );
853 if (Status == EFI_BUFFER_TOO_SMALL) {
854 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " %d UsbIo protocol instances.\n", BufferSize/sizeof (EFI_HANDLE)));
855 HandleBuffer = AllocateZeroPool (BufferSize);
856 if (HandleBuffer == NULL) {
857 DEBUG ((DEBUG_ERROR, " Falied to allocate buffer for the handles.\n"));
858 return EFI_OUT_OF_RESOURCES;
859 }
860
861 Status = gBS->LocateHandle (
862 ByProtocol,
863 &gEfiUsbIoProtocolGuid,
864 NULL,
865 &BufferSize,
866 HandleBuffer
867 );
868 if (EFI_ERROR (Status)) {
869 DEBUG ((DEBUG_ERROR, " Falied to locate UsbIo protocol handles.\n"));
870 FreePool (HandleBuffer);
871 return Status;
872 }
873 } else {
874 return Status;
875 }
876
877 for (Index = 0; Index < (BufferSize/sizeof (EFI_HANDLE)); Index++) {
878 Status = gBS->HandleProtocol (
879 *(HandleBuffer + Index),
880 &gEfiDevicePathProtocolGuid,
881 (VOID **)&ThisDevicePath
882 );
883 if (EFI_ERROR (Status)) {
884 continue;
885 }
886
887 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "Device path on #%d instance of UsbIo.\n", Index));
888 DevicePathStr = ConvertDevicePathToText (ThisDevicePath, FALSE, FALSE);
889 if (DevicePathStr != NULL) {
890 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "%s\n", DevicePathStr));
891 FreePool (DevicePathStr);
892 } else {
893 DEBUG ((DEBUG_ERROR, "Failed to convert device path on #%d instance of UsbIo.\n", Index));
894 continue;
895 }
896
897 Status = EFI_NOT_FOUND;
898
899 // Search for the starting MSG_USB_DP node.
900 ThisUsbDevicePath = UsbDevicePath;
901 if ((DevicePathType (ThisUsbDevicePath) != MESSAGING_DEVICE_PATH) ||
902 (DevicePathSubType (ThisUsbDevicePath) != MSG_USB_DP))
903 {
904 ThisUsbDevicePath = UsbNicGetNextMsgUsbDp (ThisUsbDevicePath);
905 if (ThisUsbDevicePath == NULL) {
906 continue;
907 }
908 }
909
910 if ((DevicePathType (ThisDevicePath) != MESSAGING_DEVICE_PATH) ||
911 (DevicePathSubType (ThisDevicePath) != MSG_USB_DP))
912 {
913 ThisDevicePath = UsbNicGetNextMsgUsbDp (ThisDevicePath);
914 if (ThisDevicePath == NULL) {
915 continue;
916 }
917 }
918
919 // Search for the ending MSG_USB_DP node.
920 ThisDevicePathEnd = ThisDevicePath;
921 ThisUsbDevicePathEnd = ThisUsbDevicePath;
922 while (TRUE) {
923 TempDevicePath = UsbNicGetNextMsgUsbDp (ThisDevicePathEnd);
924 if (TempDevicePath == NULL) {
925 break;
926 }
927
928 ThisDevicePathEnd = TempDevicePath;
929 }
930
931 while (TRUE) {
932 TempDevicePath = UsbNicGetNextMsgUsbDp (ThisUsbDevicePathEnd);
933 if (TempDevicePath == NULL) {
934 break;
935 }
936
937 ThisUsbDevicePathEnd = TempDevicePath;
938 }
939
940 // Compare these two device paths
941 Length = (UINT16)((UINTN)(UINT8 *)ThisDevicePathEnd + DevicePathNodeLength (ThisDevicePathEnd) - (UINTN)(UINT8 *)ThisDevicePath);
942 if (Length != ((UINTN)(UINT8 *)ThisUsbDevicePathEnd + DevicePathNodeLength (ThisUsbDevicePathEnd) - (UINTN)(UINT8 *)ThisUsbDevicePath)) {
943 continue;
944 }
945
946 if (CompareMem (
947 (VOID *)ThisDevicePath,
948 (VOID *)ThisUsbDevicePath,
949 Length
950 ) == 0)
951 {
952 Status = EFI_SUCCESS;
953 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "EFI handle with the correct UsbIo is found at #%d instance of UsbIo.\n", Index));
954 break;
955 }
956 }
957
958 if (Status == EFI_SUCCESS) {
959 // Locate UsbIo from this handle.
960 Status = gBS->HandleProtocol (
961 *(HandleBuffer + Index),
962 &gEfiUsbIoProtocolGuid,
963 (VOID **)UsbIo
964 );
965 return Status;
966 }
967
968 return EFI_NOT_FOUND;
969}
970
971/**
972 This function identifies if the USB NIC has MAC address and internet
973 protocol device path installed. (Only support IPv4)
974
975 @param[in] UsbDevicePath USB device path.
976
977 @retval EFI_SUCCESS Yes, this is IPv4 SNP handle
978 @retval EFI_NOT_FOUND No, this is not IPv4 SNP handle
979
980**/
981EFI_STATUS
982IdentifyNetworkMessageDevicePath (
983 IN EFI_DEVICE_PATH_PROTOCOL *UsbDevicePath
984 )
985{
986 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
987
988 DevicePath = UsbDevicePath;
989 while (TRUE) {
990 DevicePath = NextDevicePathNode (DevicePath);
991 if (IsDevicePathEnd (DevicePath)) {
992 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "MAC address device path is not found on this handle.\n"));
993 break;
994 }
995
996 if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_MAC_ADDR_DP)) {
997 DevicePath = NextDevicePathNode (DevicePath); // Advance to next device path protocol.
998 if (IsDevicePathEnd (DevicePath)) {
999 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "IPv4 device path is not found on this handle.\n"));
1000 break;
1001 }
1002
1003 if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_IPv4_DP)) {
1004 return EFI_SUCCESS;
1005 }
1006
1007 break;
1008 }
1009 }
1010
1011 return EFI_NOT_FOUND;
1012}
1013
1014/**
1015 This function identifies if the USB NIC is exposed by BMC as
1016 the host-BMC channel.
1017
1018 @param[in] Handle This is the EFI handle with SNP installed.
1019 @param[in] UsbDevicePath USB device path.
1020
1021 @retval EFI_SUCCESS Yes, USB NIC exposed by BMC is found.
1022 @retval EFI_NOT_FOUND No, USB NIC exposed by BMC is not found
1023 on the existing SNP handle.
1024 @retval Others Other errors.
1025
1026**/
1027EFI_STATUS
1028IdentifyUsbNicBmcChannel (
1029 IN EFI_HANDLE Handle,
1030 IN EFI_DEVICE_PATH_PROTOCOL *UsbDevicePath
1031 )
1032{
1033 UINTN Index;
1034 EFI_STATUS Status;
1035 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
1036 EFI_USB_IO_PROTOCOL *UsbIo;
1037 HOST_INTERFACE_BMC_USB_NIC_INFO *BmcUsbNic;
1038
1039 DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry.\n", __func__));
1040 Status = gBS->HandleProtocol (
1041 Handle,
1042 &gEfiSimpleNetworkProtocolGuid,
1043 (VOID **)&Snp
1044 );
1045 if (EFI_ERROR (Status)) {
1046 DEBUG ((DEBUG_ERROR, " Failed to locate SNP.\n"));
1047 return Status;
1048 }
1049
1050 Status = UsbNicSearchUsbIo (UsbDevicePath, &UsbIo);
1051 if (EFI_ERROR (Status)) {
1052 DEBUG ((DEBUG_ERROR, " Failed to find USBIO.\n"));
1053 return Status;
1054 }
1055
1056 // Get the MAC address of this SNP instance.
1057 BmcUsbNic = AllocateZeroPool (sizeof (HOST_INTERFACE_BMC_USB_NIC_INFO));
1058 if (BmcUsbNic == NULL) {
1059 DEBUG ((DEBUG_ERROR, " Failed to allocate memory for HOST_INTERFACE_BMC_USB_NIC_INFO.\n"));
1060 return EFI_OUT_OF_RESOURCES;
1061 }
1062
1063 InitializeListHead (&BmcUsbNic->NextInstance);
1064 BmcUsbNic->MacAddressSize = Snp->Mode->HwAddressSize;
1065 BmcUsbNic->MacAddress = AllocatePool (BmcUsbNic->MacAddressSize);
1066 if (BmcUsbNic->MacAddress == NULL) {
1067 DEBUG ((DEBUG_ERROR, " Failed to allocate memory for HW MAC addresss.\n"));
1068 FreePool (BmcUsbNic);
1069 return EFI_OUT_OF_RESOURCES;
1070 }
1071
1072 CopyMem (
1073 (VOID *)BmcUsbNic->MacAddress,
1074 (VOID *)&Snp->Mode->CurrentAddress,
1075 BmcUsbNic->MacAddressSize
1076 );
1077 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " MAC address (in size %d) for this SNP instance:\n", BmcUsbNic->MacAddressSize));
1078 for (Index = 0; Index < BmcUsbNic->MacAddressSize; Index++) {
1079 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "%02x ", *(BmcUsbNic->MacAddress + Index)));
1080 }
1081
1082 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "\n"));
1083 BmcUsbNic->ThisSnp = Snp;
1084 BmcUsbNic->ThisUsbIo = UsbIo;
1085
1086 Status = HostInterfaceIpmiCheckMacAddress (BmcUsbNic);
1087 if (Status == EFI_SUCCESS) {
1088 BmcUsbNic->IsExposedByBmc = TRUE;
1089 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " BMC exposed USB NIC is found.\n"));
1090 } else {
1091 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " BMC exposed USB NIC is not found.\n"));
1092 }
1093
1094 InsertTailList (&mBmcUsbNic, &BmcUsbNic->NextInstance);
1095 return Status;
1096}
1097
1098/**
1099 This function checks if the USB NIC exposed by BMC
1100 on each handle has SNP protocol installed on it.
1101
1102 @param[in] HandleNumer Number of handles to check.
1103 @param[in] HandleBuffer Handles buffer.
1104
1105 @retval EFI_SUCCESS Yes, USB NIC exposed by BMC is found.
1106 @retval EFI_NOT_FOUND No, USB NIC exposed by BMC is not found
1107 on the existing SNP handle.
1108 @retval Others Other errors.
1109
1110**/
1111EFI_STATUS
1112CheckBmcUsbNicOnHandles (
1113 IN UINTN HandleNumer,
1114 IN EFI_HANDLE *HandleBuffer
1115 )
1116{
1117 UINTN Index;
1118 EFI_STATUS Status;
1119 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1120 BOOLEAN GotBmcUsbNic;
1121 CHAR16 *DevicePathStr;
1122
1123 if ((HandleNumer == 0) || (HandleBuffer == NULL)) {
1124 return EFI_INVALID_PARAMETER;
1125 }
1126
1127 DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry, #%d SNP handle\n", __func__, HandleNumer));
1128
1129 GotBmcUsbNic = FALSE;
1130 for (Index = 0; Index < HandleNumer; Index++) {
1131 DEBUG ((DEBUG_MANAGEABILITY, " Locate device path on handle 0x%08x\n", *(HandleBuffer + Index)));
1132 Status = gBS->HandleProtocol (
1133 *(HandleBuffer + Index),
1134 &gEfiDevicePathProtocolGuid,
1135 (VOID **)&DevicePath
1136 );
1137 if (EFI_ERROR (Status)) {
1138 DEBUG ((DEBUG_ERROR, " Failed to locate device path on %d handle.\n", Index));
1139 continue;
1140 }
1141
1142 DevicePathStr = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
1143 if (DevicePathStr != NULL) {
1144 DEBUG ((DEBUG_MANAGEABILITY, " Device path: %s\n", DevicePathStr));
1145 FreePool (DevicePathStr);
1146 }
1147
1148 // Check if this is an BMC exposed USB NIC device.
1149 while (TRUE) {
1150 if ((DevicePath->Type == MESSAGING_DEVICE_PATH) && (DevicePath->SubType == MSG_USB_DP)) {
1151 Status = IdentifyNetworkMessageDevicePath (DevicePath);
1152 if (!EFI_ERROR (Status)) {
1153 Status = IdentifyUsbNicBmcChannel (*(HandleBuffer + Index), DevicePath);
1154 if (!EFI_ERROR (Status)) {
1155 GotBmcUsbNic = TRUE;
1156 }
1157 }
1158
1159 break; // Advance to next SNP handle.
1160 }
1161
1162 DevicePath = NextDevicePathNode (DevicePath);
1163 if (IsDevicePathEnd (DevicePath)) {
1164 break;
1165 }
1166 }
1167 }
1168
1169 if (GotBmcUsbNic) {
1170 return EFI_SUCCESS;
1171 }
1172
1173 DEBUG ((DEBUG_MANAGEABILITY, "No BMC USB NIC found on SNP handles\n"));
1174 return EFI_NOT_FOUND;
1175}
1176
1177/**
1178 This function checks if the USB NIC exposed by BMC
1179 is already connected.
1180
1181 @param[in] Registration Locate SNP protocol from the notification
1182 registeration key.
1183 NULL means locate SNP protocol from the existing
1184 handles.
1185
1186 @retval EFI_SUCCESS Yes, USB NIC exposed by BMC is found.
1187 @retval EFI_NOT_FOUND No, USB NIC exposed by BMC is not found
1188 on the existing SNP handle.
1189 @retval Others Other errors.
1190
1191**/
1192EFI_STATUS
1193CheckBmcUsbNic (
1194 VOID *Registration
1195 )
1196{
1197 EFI_STATUS Status;
1198 EFI_HANDLE Handle;
1199 UINTN BufferSize;
1200 EFI_HANDLE *HandleBuffer;
1201
1202 DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry, the registration key - 0x%08x.\n", __func__, Registration));
1203
1204 Handle = NULL;
1205 Status = EFI_SUCCESS;
1206
1207 do {
1208 BufferSize = 0;
1209 Status = gBS->LocateHandle (
1210 Registration == NULL ? ByProtocol : ByRegisterNotify,
1211 &gEfiSimpleNetworkProtocolGuid,
1212 Registration,
1213 &BufferSize,
1214 NULL
1215 );
1216 if (Status == EFI_BUFFER_TOO_SMALL) {
1217 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " %d SNP protocol instance(s).\n", BufferSize/sizeof (EFI_HANDLE)));
1218 HandleBuffer = AllocateZeroPool (BufferSize);
1219 if (HandleBuffer == NULL) {
1220 DEBUG ((DEBUG_ERROR, " Falied to allocate buffer for the handles.\n"));
1221 return EFI_OUT_OF_RESOURCES;
1222 }
1223
1224 Status = gBS->LocateHandle (
1225 Registration == NULL ? ByProtocol : ByRegisterNotify,
1226 &gEfiSimpleNetworkProtocolGuid,
1227 Registration,
1228 &BufferSize,
1229 HandleBuffer
1230 );
1231 if (EFI_ERROR (Status)) {
1232 DEBUG ((DEBUG_ERROR, " Falied to locate SNP protocol handles.\n"));
1233 FreePool (HandleBuffer);
1234 return Status;
1235 }
1236 } else if (EFI_ERROR (Status)) {
1237 if (Registration != NULL) {
1238 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " No more newly installed SNP protocol for this registration - %r.\n", Status));
1239 return EFI_SUCCESS;
1240 }
1241
1242 return Status;
1243 }
1244
1245 // Check USB NIC on handles.
1246 Status = CheckBmcUsbNicOnHandles (BufferSize/sizeof (EFI_HANDLE), HandleBuffer);
1247 if (!EFI_ERROR (Status)) {
1248 // Retrieve the rest of BMC USB NIC information for Redfish over IP information
1249 // and USB Network Interface V2.
1250 Status = RetrievedBmcUsbNicInfo ();
1251 if (!EFI_ERROR (Status)) {
1252 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, " Install protocol to notify the platform Redfish Host Interface information is ready.\n"));
1253 Status = gBS->InstallProtocolInterface (
1254 &Handle,
1255 &mPlatformHostInterfaceBmcUsbNicReadinessGuid,
1256 EFI_NATIVE_INTERFACE,
1257 NULL
1258 );
1259 if (EFI_ERROR (Status)) {
1260 DEBUG ((DEBUG_ERROR, " Install protocol fail %r.\n", Status));
1261 }
1262 }
1263 }
1264
1265 FreePool (HandleBuffer);
1266 } while (Registration != NULL);
1267
1268 return Status;
1269}
1270
1271/**
1272 Notification event of SNP readiness.
1273
1274 @param[in] Event Event whose notification function is being invoked.
1275 @param[in] Context The pointer to the notification function's context,
1276 which is implementation-dependent.
1277
1278**/
1279VOID
1280EFIAPI
1281PlatformHostInterfaceSnpCallback (
1282 IN EFI_EVENT Event,
1283 IN VOID *Context
1284 )
1285{
1286 DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry.\n", __func__));
1287
1288 CheckBmcUsbNic (mPlatformHostInterfaceSnpRegistration);
1289 return;
1290}
1291
1292/**
1293 Get the EFI protocol GUID installed by platform library which
1294 indicates the necessary information is ready for building
1295 SMBIOS 42h record.
1296
1297 @param[out] InformationReadinessGuid Pointer to retrive the protocol
1298 GUID.
1299
1300 @retval EFI_SUCCESS Notification is required for building up
1301 SMBIOS type 42h record.
1302 @retval EFI_UNSUPPORTED Notification is not required for building up
1303 SMBIOS type 42h record.
1304 @retval EFI_ALREADY_STARTED Platform host information is already ready.
1305 @retval Others Other errors.
1306**/
1307EFI_STATUS
1308RedfishPlatformHostInterfaceNotification (
1309 OUT EFI_GUID **InformationReadinessGuid
1310 )
1311{
1312 EFI_STATUS Status;
1313
1314 DEBUG ((DEBUG_MANAGEABILITY, "%a: Entry\n", __func__));
1315
1316 *InformationReadinessGuid = NULL;
1317 InitializeListHead (&mBmcUsbNic);
1318 InitializeListHead (&mBmcIpmiLan);
1319
1320 //
1321 // Check if USB NIC exposed by BMC is already
1322 // connected.
1323 //
1324 Status = CheckBmcUsbNic (NULL);
1325 if (!EFI_ERROR (Status)) {
1326 return EFI_ALREADY_STARTED;
1327 }
1328
1329 if (Status == EFI_NOT_FOUND) {
1330 DEBUG ((DEBUG_REDFISH_HOST_INTERFACE, "%a: BMC USB NIC is not found. Register the notification.\n", __func__));
1331
1332 // Register the notification of SNP installation.
1333 Status = gBS->CreateEvent (
1334 EVT_NOTIFY_SIGNAL,
1335 TPL_CALLBACK,
1336 PlatformHostInterfaceSnpCallback,
1337 NULL,
1338 &mPlatformHostInterfaceSnpEvent
1339 );
1340 if (EFI_ERROR (Status)) {
1341 DEBUG ((DEBUG_ERROR, "%a: Fail to create event for the installation of SNP protocol.", __func__));
1342 return Status;
1343 }
1344
1345 Status = gBS->RegisterProtocolNotify (
1346 &gEfiSimpleNetworkProtocolGuid,
1347 mPlatformHostInterfaceSnpEvent,
1348 &mPlatformHostInterfaceSnpRegistration
1349 );
1350 if (EFI_ERROR (Status)) {
1351 DEBUG ((DEBUG_ERROR, "%a: Fail to register event for the installation of SNP protocol.", __func__));
1352 return Status;
1353 }
1354
1355 *InformationReadinessGuid = &mPlatformHostInterfaceBmcUsbNicReadinessGuid;
1356 return EFI_SUCCESS;
1357 }
1358
1359 DEBUG ((DEBUG_ERROR, "%a: Something wrong when look for BMC USB NIC.\n", __func__));
1360 return Status;
1361}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette