/** @file PCI/PCIe network interface instace of RedfishPlatformHostInterfaceLib Copyright (c) 2019, Intel Corporation. All rights reserved.
(C) Copyright 2020 Hewlett Packard Enterprise Development LP
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #define VERBOSE_COLUME_SIZE (16) REDFISH_OVER_IP_PROTOCOL_DATA *mRedfishOverIpProtocolData; UINT8 mRedfishProtocolDataSize; /** Get the MAC address of NIC. @param[out] MacAddress Pointer to retrieve MAC address @retval EFI_SUCCESS MAC address is returned in MacAddress **/ EFI_STATUS GetMacAddressInformation ( OUT EFI_MAC_ADDRESS *MacAddress ) { MAC_ADDR_DEVICE_PATH *Mac; REST_EX_SERVICE_DEVICE_PATH_DATA *RestExServiceDevicePathData; EFI_DEVICE_PATH_PROTOCOL *RestExServiceDevicePath; MAC_ADDR_DEVICE_PATH *MacAddressDevicePath; Mac = NULL; RestExServiceDevicePathData = NULL; RestExServiceDevicePath = NULL; RestExServiceDevicePathData = (REST_EX_SERVICE_DEVICE_PATH_DATA *)PcdGetPtr(PcdRedfishRestExServiceDevicePath); if (RestExServiceDevicePathData == NULL || RestExServiceDevicePathData->DevicePathNum == 0 || !IsDevicePathValid (RestExServiceDevicePathData->DevicePath, 0)) { return EFI_NOT_FOUND; } RestExServiceDevicePath = RestExServiceDevicePathData->DevicePath; if (RestExServiceDevicePathData->DevicePathMatchMode != DEVICE_PATH_MATCH_MAC_NODE) { return EFI_NOT_FOUND; } // // Find Mac DevicePath Node. // while (!IsDevicePathEnd (RestExServiceDevicePath) && ((DevicePathType (RestExServiceDevicePath) != MESSAGING_DEVICE_PATH) || (DevicePathSubType (RestExServiceDevicePath) != MSG_MAC_ADDR_DP))) { RestExServiceDevicePath = NextDevicePathNode (RestExServiceDevicePath); } if (!IsDevicePathEnd (RestExServiceDevicePath)) { MacAddressDevicePath = (MAC_ADDR_DEVICE_PATH *)RestExServiceDevicePath; CopyMem ((VOID *)MacAddress, (VOID *)&MacAddressDevicePath->MacAddress, sizeof (EFI_MAC_ADDRESS)); return EFI_SUCCESS; } return EFI_NOT_FOUND; } /** Get platform Redfish host interface device descriptor. @param[out] DeviceType Pointer to retrieve device type. @param[out] DeviceDescriptor Pointer to retrieve REDFISH_INTERFACE_DATA, caller has to free this memory using FreePool(). @retval EFI_SUCCESS Device descriptor is returned successfully in DeviceDescriptor. @retval EFI_NOT_FOUND No Redfish host interface descriptor provided on this platform. @retval Others Fail to get device descriptor. **/ EFI_STATUS RedfishPlatformHostInterfaceDeviceDescriptor ( OUT UINT8 *DeviceType, OUT REDFISH_INTERFACE_DATA **DeviceDescriptor ) { EFI_STATUS Status; EFI_MAC_ADDRESS MacAddress; REDFISH_INTERFACE_DATA *RedfishInterfaceData; PCI_OR_PCIE_INTERFACE_DEVICE_DESCRIPTOR_V2 *ThisDeviceDescriptor; RedfishInterfaceData = AllocateZeroPool (sizeof (PCI_OR_PCIE_INTERFACE_DEVICE_DESCRIPTOR_V2) + 1); if (RedfishInterfaceData == NULL) { return EFI_OUT_OF_RESOURCES; } RedfishInterfaceData->DeviceType = REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2; // // Fill up device type information. // ThisDeviceDescriptor = (PCI_OR_PCIE_INTERFACE_DEVICE_DESCRIPTOR_V2 *)((UINT8 *)RedfishInterfaceData + 1); ThisDeviceDescriptor->Length = sizeof (PCI_OR_PCIE_INTERFACE_DEVICE_DESCRIPTOR_V2) + 1; Status = GetMacAddressInformation (&MacAddress); if (EFI_ERROR (Status)) { FreePool (RedfishInterfaceData); return EFI_NOT_FOUND; } CopyMem ((VOID *)&ThisDeviceDescriptor->MacAddress, (VOID *)&MacAddress, sizeof (ThisDeviceDescriptor->MacAddress)); *DeviceType = REDFISH_HOST_INTERFACE_DEVICE_TYPE_PCI_PCIE_V2; *DeviceDescriptor = RedfishInterfaceData; return EFI_SUCCESS; } /** Get platform Redfish host interface protocol data. Caller should pass NULL in ProtocolRecord to retrive the first protocol record. Then continuously pass previous ProtocolRecord for retrieving the next ProtocolRecord. @param[out] ProtocolRecord Pointer to retrieve the protocol record. caller has to free the new protocol record returned from this function using FreePool(). @param[in] IndexOfProtocolData The index of protocol data. @retval EFI_SUCCESS Protocol records are all returned. @retval EFI_NOT_FOUND No more protocol records. @retval Others Fail to get protocol records. **/ EFI_STATUS RedfishPlatformHostInterfaceProtocolData ( OUT MC_HOST_INTERFACE_PROTOCOL_RECORD **ProtocolRecord, IN UINT8 IndexOfProtocolData ) { MC_HOST_INTERFACE_PROTOCOL_RECORD *ThisProtocolRecord; if (mRedfishOverIpProtocolData == 0) { return EFI_NOT_FOUND; } if (IndexOfProtocolData == 0) { // // Return the first Redfish protocol data to caller. We only have // one protocol data in this case. // ThisProtocolRecord = (MC_HOST_INTERFACE_PROTOCOL_RECORD *) AllocatePool (mRedfishProtocolDataSize + sizeof (MC_HOST_INTERFACE_PROTOCOL_RECORD) - 1); ThisProtocolRecord->ProtocolType = MCHostInterfaceProtocolTypeRedfishOverIP; ThisProtocolRecord->ProtocolTypeDataLen = mRedfishProtocolDataSize; CopyMem ((VOID *)&ThisProtocolRecord->ProtocolTypeData, (VOID *)mRedfishOverIpProtocolData, mRedfishProtocolDataSize); *ProtocolRecord = ThisProtocolRecord; return EFI_SUCCESS; } return EFI_NOT_FOUND; } /** Dump IPv4 address. @param[in] Ip IPv4 address **/ VOID InternalDumpIp4Addr ( IN EFI_IPv4_ADDRESS *Ip ) { UINTN Index; for (Index = 0; Index < 4; Index++) { DEBUG ((DEBUG_VERBOSE, "%d", Ip->Addr[Index])); if (Index < 3) { DEBUG ((DEBUG_VERBOSE, ".")); } } DEBUG ((DEBUG_VERBOSE, "\n")); } /** Dump IPv6 address. @param[in] Ip IPv6 address **/ VOID InternalDumpIp6Addr ( IN EFI_IPv6_ADDRESS *Ip ) { UINTN Index; for (Index = 0; Index < 16; Index++) { if (Ip->Addr[Index] != 0) { DEBUG ((DEBUG_VERBOSE, "%x", Ip->Addr[Index])); } Index++; if (Index > 15) { return; } if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) { DEBUG ((DEBUG_VERBOSE, "0")); } DEBUG ((DEBUG_VERBOSE, "%x", Ip->Addr[Index])); if (Index < 15) { DEBUG ((DEBUG_VERBOSE, ":")); } } DEBUG ((DEBUG_VERBOSE, "\n")); } /** Dump data @param[in] Data Pointer to data. @param[in] Size size of data to dump. **/ VOID InternalDumpData ( IN UINT8 *Data, IN UINTN Size ) { UINTN Index; for (Index = 0; Index < Size; Index++) { DEBUG ((DEBUG_VERBOSE, "%02x ", (UINTN)Data[Index])); } } /** Dump hex data @param[in] Data Pointer to hex data. @param[in] Size size of hex data to dump. **/ VOID InternalDumpHex ( IN UINT8 *Data, IN UINTN Size ) { UINTN Index; UINTN Count; UINTN Left; Count = Size / VERBOSE_COLUME_SIZE; Left = Size % VERBOSE_COLUME_SIZE; for (Index = 0; Index < Count; Index++) { InternalDumpData (Data + Index * VERBOSE_COLUME_SIZE, VERBOSE_COLUME_SIZE); DEBUG ((DEBUG_VERBOSE, "\n")); } if (Left != 0) { InternalDumpData (Data + Index * VERBOSE_COLUME_SIZE, Left); DEBUG ((DEBUG_VERBOSE, "\n")); } DEBUG ((DEBUG_VERBOSE, "\n")); } /** Dump Redfish over IP protocol data @param[in] RedfishProtocolData Pointer to REDFISH_OVER_IP_PROTOCOL_DATA @param[in] RedfishProtocolDataSize size of data to dump. **/ VOID DumpRedfishIpProtocolData ( IN REDFISH_OVER_IP_PROTOCOL_DATA *RedfishProtocolData, IN UINT8 RedfishProtocolDataSize ) { CHAR16 Hostname[16]; DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData: \n")); InternalDumpHex ((UINT8 *) RedfishProtocolData, RedfishProtocolDataSize); DEBUG ((DEBUG_VERBOSE, "Parsing as below: \n")); DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData->ServiceUuid - %g\n", &(RedfishProtocolData->ServiceUuid))); DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData->HostIpAssignmentType - %d\n", RedfishProtocolData->HostIpAssignmentType)); DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData->HostIpAddressFormat - %d\n", RedfishProtocolData->HostIpAddressFormat)); DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData->HostIpAddress: \n")); if (RedfishProtocolData->HostIpAddressFormat == 0x01) { InternalDumpIp4Addr ((EFI_IPv4_ADDRESS *) (RedfishProtocolData->HostIpAddress)); } else { InternalDumpIp6Addr ((EFI_IPv6_ADDRESS *) (RedfishProtocolData->HostIpAddress)); } DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData->HostIpMask: \n")); if (RedfishProtocolData->HostIpAddressFormat == 0x01) { InternalDumpIp4Addr ((EFI_IPv4_ADDRESS *) (RedfishProtocolData->HostIpMask)); } else { InternalDumpIp6Addr ((EFI_IPv6_ADDRESS *) (RedfishProtocolData->HostIpMask)); } DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData->RedfishServiceIpDiscoveryType - %d\n", RedfishProtocolData->RedfishServiceIpDiscoveryType)); DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData->RedfishServiceIpAddressFormat - %d\n", RedfishProtocolData->RedfishServiceIpAddressFormat)); DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData->RedfishServiceIpAddress: \n")); if (RedfishProtocolData->RedfishServiceIpAddressFormat == 0x01) { InternalDumpIp4Addr ((EFI_IPv4_ADDRESS *) (RedfishProtocolData->RedfishServiceIpAddress)); } else { InternalDumpIp6Addr ((EFI_IPv6_ADDRESS *) (RedfishProtocolData->RedfishServiceIpAddress)); } DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData->RedfishServiceIpMask: \n")); if (RedfishProtocolData->RedfishServiceIpAddressFormat == 0x01) { InternalDumpIp4Addr ((EFI_IPv4_ADDRESS *) (RedfishProtocolData->RedfishServiceIpMask)); } else { InternalDumpIp6Addr ((EFI_IPv6_ADDRESS *) (RedfishProtocolData->RedfishServiceIpMask)); } DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData->RedfishServiceIpPort - %d\n", RedfishProtocolData->RedfishServiceIpPort)); DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData->RedfishServiceVlanId - %d\n", RedfishProtocolData->RedfishServiceVlanId)); DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData->RedfishServiceHostnameLength - %d\n", RedfishProtocolData->RedfishServiceHostnameLength)); AsciiStrToUnicodeStrS((CHAR8 *) RedfishProtocolData->RedfishServiceHostname, Hostname, sizeof (Hostname) / sizeof (Hostname[0])); DEBUG ((DEBUG_VERBOSE, "RedfishProtocolData->RedfishServiceHostname - %s\n", Hostname)); } /** Get Redfish host interface protocol data from variale. @param[out] RedfishProtocolData Pointer to retrieve REDFISH_OVER_IP_PROTOCOL_DATA. @param[out] RedfishProtocolDataSize Size of REDFISH_OVER_IP_PROTOCOL_DATA. @retval EFI_SUCESS REDFISH_OVER_IP_PROTOCOL_DATA is returned successfully. **/ EFI_STATUS GetRedfishRecordFromVariable ( OUT REDFISH_OVER_IP_PROTOCOL_DATA **RedfishProtocolData, OUT UINT8 *RedfishProtocolDataSize ) { EFI_STATUS Status; UINT8 HostIpAssignmentType; UINTN HostIpAssignmentTypeSize; EFI_IPv4_ADDRESS HostIpAddress; UINTN IPv4DataSize; EFI_IPv4_ADDRESS HostIpMask; EFI_IPv4_ADDRESS RedfishServiceIpAddress; EFI_IPv4_ADDRESS RedfishServiceIpMask; UINT16 RedfishServiceIpPort; UINTN IpPortDataSize; UINT8 HostNameSize; CHAR8 RedfishHostName[20]; if (RedfishProtocolData == NULL || RedfishProtocolDataSize == NULL) { return EFI_INVALID_PARAMETER; } // // 1. Retrieve Address Information from variable. // Status = gRT->GetVariable ( L"HostIpAssignmentType", &gEmuRedfishServiceGuid, NULL, &HostIpAssignmentTypeSize, &HostIpAssignmentType ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "RedfishPlatformDxe: GetVariable HostIpAssignmentType - %r\n", Status)); return Status; } IPv4DataSize = sizeof (EFI_IPv4_ADDRESS); if (HostIpAssignmentType == 1 ) { Status = gRT->GetVariable ( L"HostIpAddress", &gEmuRedfishServiceGuid, NULL, &IPv4DataSize, &HostIpAddress ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "RedfishPlatformDxe: GetVariable HostIpAddress - %r\n", Status)); return Status; } Status = gRT->GetVariable ( L"HostIpMask", &gEmuRedfishServiceGuid, NULL, &IPv4DataSize, &HostIpMask ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "RedfishPlatformDxe: GetVariable HostIpMask - %r\n", Status)); return Status; } } Status = gRT->GetVariable ( L"RedfishServiceIpAddress", &gEmuRedfishServiceGuid, NULL, &IPv4DataSize, &RedfishServiceIpAddress ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "RedfishPlatformDxe: GetVariable RedfishServiceIpAddress - %r\n", Status)); return Status; } Status = gRT->GetVariable ( L"RedfishServiceIpMask", &gEmuRedfishServiceGuid, NULL, &IPv4DataSize, &RedfishServiceIpMask ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "RedfishPlatformDxe: GetVariable RedfishServiceIpMask - %r\n", Status)); return Status; } Status = gRT->GetVariable ( L"RedfishServiceIpPort", &gEmuRedfishServiceGuid, NULL, &IpPortDataSize, &RedfishServiceIpPort ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "RedfishPlatformDxe: GetVariable RedfishServiceIpPort - %r\n", Status)); return Status; } AsciiSPrint ( RedfishHostName, sizeof (RedfishHostName), "%d.%d.%d.%d", RedfishServiceIpAddress.Addr[0], RedfishServiceIpAddress.Addr[1], RedfishServiceIpAddress.Addr[2], RedfishServiceIpAddress.Addr[3] ); HostNameSize = (UINT8) AsciiStrLen (RedfishHostName) + 1; // // 2. Protocol Data Size. // *RedfishProtocolDataSize = sizeof (REDFISH_OVER_IP_PROTOCOL_DATA) - 1 + HostNameSize; // // 3. Protocol Data. // *RedfishProtocolData = (REDFISH_OVER_IP_PROTOCOL_DATA *) AllocateZeroPool (*RedfishProtocolDataSize); if (*RedfishProtocolData == NULL) { return EFI_OUT_OF_RESOURCES; } CopyGuid (&(*RedfishProtocolData)->ServiceUuid, &gEmuRedfishServiceGuid); (*RedfishProtocolData)->HostIpAssignmentType = HostIpAssignmentType; (*RedfishProtocolData)->HostIpAddressFormat = 1; // Only support IPv4 if (HostIpAssignmentType == 1 ) { (*RedfishProtocolData)->HostIpAddress[0] = HostIpAddress.Addr[0]; (*RedfishProtocolData)->HostIpAddress[1] = HostIpAddress.Addr[1]; (*RedfishProtocolData)->HostIpAddress[2] = HostIpAddress.Addr[2]; (*RedfishProtocolData)->HostIpAddress[3] = HostIpAddress.Addr[3]; (*RedfishProtocolData)->HostIpMask[0] = HostIpMask.Addr[0]; (*RedfishProtocolData)->HostIpMask[1] = HostIpMask.Addr[1]; (*RedfishProtocolData)->HostIpMask[2] = HostIpMask.Addr[2]; (*RedfishProtocolData)->HostIpMask[3] = HostIpMask.Addr[3]; } (*RedfishProtocolData)->RedfishServiceIpDiscoveryType = 1; // Use static IP address (*RedfishProtocolData)->RedfishServiceIpAddressFormat = 1; // Only support IPv4 (*RedfishProtocolData)->RedfishServiceIpAddress[0] = RedfishServiceIpAddress.Addr[0]; (*RedfishProtocolData)->RedfishServiceIpAddress[1] = RedfishServiceIpAddress.Addr[1]; (*RedfishProtocolData)->RedfishServiceIpAddress[2] = RedfishServiceIpAddress.Addr[2]; (*RedfishProtocolData)->RedfishServiceIpAddress[3] = RedfishServiceIpAddress.Addr[3]; (*RedfishProtocolData)->RedfishServiceIpMask[0] = RedfishServiceIpMask.Addr[0]; (*RedfishProtocolData)->RedfishServiceIpMask[1] = RedfishServiceIpMask.Addr[1]; (*RedfishProtocolData)->RedfishServiceIpMask[2] = RedfishServiceIpMask.Addr[2]; (*RedfishProtocolData)->RedfishServiceIpMask[3] = RedfishServiceIpMask.Addr[3]; (*RedfishProtocolData)->RedfishServiceIpPort = RedfishServiceIpPort; (*RedfishProtocolData)->RedfishServiceVlanId = 0xffffffff; (*RedfishProtocolData)->RedfishServiceHostnameLength = HostNameSize; AsciiStrCpyS ((CHAR8 *) ((*RedfishProtocolData)->RedfishServiceHostname), HostNameSize, RedfishHostName); return Status; } /** Construct Redfish host interface protocol data. @param ImageHandle The image handle. @param SystemTable The system table. @retval EFI_SUCEESS Install Boot manager menu success. @retval Other Return error status. **/ EFI_STATUS EFIAPI RedfishPlatformHostInterfaceConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; Status = GetRedfishRecordFromVariable (&mRedfishOverIpProtocolData, &mRedfishProtocolDataSize); DEBUG ((DEBUG_INFO, "%a: GetRedfishRecordFromVariable() - %r\n", __FUNCTION__, Status)); if (!EFI_ERROR (Status)) { DumpRedfishIpProtocolData (mRedfishOverIpProtocolData, mRedfishProtocolDataSize); } return EFI_SUCCESS; }