/* * nbft.c -- command line utility to decode nBFT table * * Copyright (c) 2021, Dell Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_NBFT_PATH "/sys/firmware/acpi/tables/NBFT" /* * TO DO: * - more verification (structure IDs, versions, string offsets & lengths in heap, etc) * - print flags as text rather than a number (?) */ /* * NBFT table structures (Table 1) */ enum sub_structure_type { NBFT_HEADER, NBFT_CONTROL, NBFT_HOST, NBFT_HFI, NBFT_NAMESPACE, NBFT_SECURITY, NBFT_DISCOVERY, NBFT_HFI_INFO, }; /* * HEADER (Table 3) */ struct __attribute__((__packed__)) acpi_nbft_table_header { char signature[4]; /* ASCII table signature */ __u32 length; /* Length of table in bytes, including this header */ __u8 revision; /* ACPI Specification minor version number */ __u8 checksum; /* To make sum of entire table == 0 */ char oem_id[6]; /* ASCII OEM identification */ char oem_table_id[8]; /* ASCII OEM table identification */ __u32 oem_revision; /* OEM revision number */ __u32 creator_id; __u32 creator_revision; __u16 heap_length; __u16 heap_offset; __u8 reserved[8]; }; /* * CONTROL (Table 4) */ struct __attribute__((__packed__)) acpi_nbft_control { __u8 structure_id; __u8 version; __u16 length; __u8 flags; __u8 num_hfi; // must be >1 (??) __u16 number_of_namespaces; // must be >=1 __u8 num_security_profiles; // >=0 __u16 host_structure_offset; __u16 hfi_1_offset; __u16 namespace_1_offset; __u16 security_profile_1_offset; __u16 discovery_structure_offset; __u8 reserved2[13]; }; enum control_flags { CONTROLFLAG_BLOCK_VALID, CONTROLFLAG_BOOT_FAILOVER_MULTIPATH_FEATURE, }; /* * HOST (Table 6) */ struct __attribute__((__packed__)) acpi_nbft_host { __u8 structure_id; __u8 version; __u16 length; __u8 host_flags; __u8 host_identifier[16]; __u16 host_nqn_length; __u16 host_nqn_offset; __u8 reserved[7]; }; enum host_flags { HOSTFLAG_BLOCK_VALID, }; /* * HFI (Table 8) */ struct __attribute__((__packed__)) acpi_nbft_hfi { __u8 structure_id; __u8 version; __u8 index; __u8 hfi_flags; __u8 hfi_transport_type; __u8 reserved; __u16 hostid_offset; __u16 hostid_length; __u16 hostnqn_offset; __u16 hostnqn_length; __u16 info_structure_length; __u16 info_structure_offset; // THIS OFFSET/LENGTH ARE BACKWARD FROM THE SPEC! }; enum hfi_flags { HFIFLAG_BLOCK_VALID, HFIFLAG_DEVICE_ADVANCED_CAPABILITIES, HFIFLAG_HOSTID_OVERRIDE, HFIFLAG_HOSTNQN_OVERRIDE, }; /* * HFI INFO (Table 10) */ struct __attribute__((__packed__)) acpi_nbft_hfi_info { __u8 structure_id; __u8 hfi_transport_type; __u8 version; __u16 hfi_index; __u8 transport_flags; __u32 pci_sbdf; __u8 mac_addr[6]; __u16 vlan; // 4096 if unset __u8 origin; __u8 ip_address[16]; __u8 subnet_mask_prefix; __u8 ip_gateway[16]; __u16 route_metric; __u8 primary_dns[16]; __u8 secondary_dns[16]; __u8 dhcp_server[16]; __u16 host_name_offset; __u16 host_name_length; __u16 extended_adapter_info_offset; __u16 extended_adapter_info_length; }; enum hfi_info_flags { HFIINFOFLAG_BLOCK_VALID, HFIINFOFLAG_GLOBAL_ROUTE_VS_LINK_LOCAL_OVERRIDE, HFIINFOFLAG_DHCP_OVERRIDE, HFIINFOFLAG_OEM_EXTENDED_ADAPTER_INFO, }; struct __attribute__((__packed__)) acpi_nbft_hfi_info_extended_adapter_info { __u8 structure_id; __u8 version; __u16 hfi_index; __u8 extended_capabilities; }; enum hfi_info_extended_adapter_info_flags { HFIINFOEXTADAPTERINFOFLAG_TRANSPORT_OFFLOAD, }; /* * SUBSYSTEM NAMESPACE (Table 14) */ struct __attribute__((__packed__)) acpi_nbft_namespace { __u8 structure_id; __u8 version; __u16 length; __u16 index; __u16 subsystem_namespace_flags; __u8 transport_type; // 1 = nvme-of TCP __u8 primary_discovery_ctrl_offset; __u8 subsystem_transport_address[16]; __u16 subsystem_transport_port; __u8 mp_group; // 0 = not part of a multipath group __u16 subsystem_port_id; __u16 controller_id; __u32 nsid; __u8 nid_type; // leave 0 __u8 nid[16]; __u8 security_struct_index; // 0 for none __u16 hfi_association_length; __u16 hfi_association_offset; __u16 subsystem_namespace_nqn_length; __u16 subsystem_namespace_nqn_offset; __u8 reserved[1]; }; enum namespace_flags { NSFLAG_BLOCK_VALID, NSFLAG_NON_BOOTABLE_ENTRY, NSFLAG_USE_SECURITY_FIELD, NSFLAG_DHCP_ROOT_PATH_OVERRIDE, NSFLAG_MULTIPATH_VOLUME_MEMBER_ENABLED, NSFLAG_SEPARATE_DISCOVERY_CONTROLLER, NSFLAG_PDU_HEADER_DIGEST, NSFLAG_DATA_DIGEST, }; /* * SECURITY (Table 16) */ struct __attribute__((__packed__)) acpi_nbft_security { __u8 structure_id; __u8 version; __u16 length; __u8 index; __u16 security_structure_flags; __u8 secret_type; __u16 secure_channel_allowed_algorithms_length; __u16 secure_channel_allowed_algorithms_offset; __u16 authentication_protocols_allowed_length; __u16 authentication_protocols_allowed_offset; __u16 cipher_suite_name_length; __u16 cipher_suite_name_offset; __u16 supported_dh_groups_length; __u16 supported_dh_groups_offset; __u16 secure_hash_functions_length; __u16 secure_hash_functions_offset; __u16 secret_keypath_length; __u16 secret_keypath_offset; __u16 extended_authentication_length; __u16 extended_authentication_offset; }; enum security_profile_flags { /* 0 */ SECFLAG_BLOCK_VALID, /* 1 */ SECFLAG_IN_BAND_AUTHENTICATION_REQUIRED, /* 2 */ SECFLAG_AUTHENTICATION_POLICY_LIST, /* 3 */ SECFLAG_SECURE_CHANNEL_NEGOTIATION_REQUIRED, /* 4 */ SECFLAG_SECURITY_POLICY_LIST, /* 5 */ SECFLAG_CIPHER_SUITES_RESTRICTED_BY_POLICY, /* 6 */ SECFLAG_AUTHENTICATION_PARAMETERS_RESTRICTED_BY_POLICY, /* 7 */ SECFLAG_EXTENDED_AUTHENTICATION_PARAMETERS_PRESENT, /* 8 */ SECFLAG_AUTHENTICATION_VERIFICATION_ENTITY_REQUIRED, /* 9 */ SECFLAG_AUTHENTICATION_DH_GROUPS_RESTRICTED_BY_POLICY_LIST, /* 10 */ SECFLAG_SECURE_HASH_FUNCTIONS_POLICY_LIST, }; enum secret_type { SECRET_TYPE_NONE, SECRET_TYPE_REDFISH_HOST_INTERFACE_URI, SECRET_TYPE_OEM_URI, }; /* * DISCOVERY (Table 19) */ struct __attribute__((__packed__)) discovery_record { __u8 discovery_record_hfi; __u8 discovery_record_security_profile; __u16 discovery_ctrl_addr_length; __u16 discovery_ctrl_addr_offset; __u16 discovery_controller_nqn_length; __u16 discovery_controller_nqn_offset; }; struct __attribute__((__packed__)) acpi_nbft_discovery { __u8 structure_id; __u8 version; __u16 length; __u8 discovery_structure_flags; __u8 number_of_records; struct discovery_record record[]; }; enum discovery_flags { DISCOVERYFLAGS_BLOCK_VALID, }; /* * Make table & header global to simplify error checking in helper functions */ __u8 *raw_nbft; struct acpi_nbft_table_header *header; /* * helper functions */ __u8 csum(void *buffer, int length) { int n; __u8 sum = 0; for (n = 0; n < length; n++) { sum = (__u8)(sum + ((__u8 *)buffer)[n]); } return sum; } /* * COPIED FROM iasl (in acpi-tools): */ /* UUID constants */ #define UUID_BUFFER_LENGTH 16 /* Length of UUID in memory */ #define UUID_STRING_LENGTH 36 /* Total length of a UUID string */ /* Positions for required hyphens (dashes) in UUID strings */ #define UUID_HYPHEN1_OFFSET 8 #define UUID_HYPHEN2_OFFSET 13 #define UUID_HYPHEN3_OFFSET 18 #define UUID_HYPHEN4_OFFSET 23 const __u8 AcpiGbl_MapToUuidOffset[UUID_BUFFER_LENGTH] = { 6,4,2,0,11,9,16,14,19,21,24,26,28,30,32,34 }; /* Hex to ASCII conversion table */ static const char AcpiGbl_HexToAscii[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; /******************************************************************************* * * FUNCTION: AcpiUtShortShiftRight * * PARAMETERS: See function headers above * * DESCRIPTION: Native version of the UtShortShiftRight function. * ******************************************************************************/ void AcpiUtShortShiftRight ( __u64 Operand, __u32 Count, __u64 *OutResult) { *OutResult = Operand >> Count; } /******************************************************************************* * * FUNCTION: AcpiUtHexToAsciiChar * * PARAMETERS: Integer - Contains the hex digit * Position - bit position of the digit within the * integer (multiple of 4) * * RETURN: The converted Ascii character * * DESCRIPTION: Convert a hex digit to an Ascii character * ******************************************************************************/ char AcpiUtHexToAsciiChar ( __u64 Integer, __u32 Position) { __u64 Index; AcpiUtShortShiftRight (Integer, Position, &Index); return (AcpiGbl_HexToAscii[Index & 0xF]); } /******************************************************************************* * * FUNCTION: AuConvertUuidToString * * PARAMETERS: UuidBuffer - 16-byte UUID buffer * OutString - 36-byte formatted UUID string * * RETURN: Status * * DESCRIPTION: Convert 16-byte UUID buffer to 36-byte formatted UUID string * OutString must be 37 bytes to include null terminator. * ******************************************************************************/ void AuConvertUuidToString ( char *UuidBuffer, char *OutString) { __u32 i; for (i = 0; i < UUID_BUFFER_LENGTH; i++) { OutString[AcpiGbl_MapToUuidOffset[i]] = AcpiUtHexToAsciiChar (UuidBuffer[i], 4); OutString[AcpiGbl_MapToUuidOffset[i] + 1] = AcpiUtHexToAsciiChar (UuidBuffer[i], 0); } /* Insert required hyphens (dashes) */ OutString[UUID_HYPHEN1_OFFSET] = OutString[UUID_HYPHEN2_OFFSET] = OutString[UUID_HYPHEN3_OFFSET] = OutString[UUID_HYPHEN4_OFFSET] = '-'; OutString[UUID_STRING_LENGTH] = 0; /* Null terminate */ } /* AcpiOsPrintf ( "\"%2.2x%2.2x%2.2x%2.2x-" "%2.2x%2.2x-" "%2.2x%2.2x-" "%2.2x%2.2x-" "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\")", Data[3], Data[2], Data[1], Data[0], Data[5], Data[4], Data[7], Data[6], Data[8], Data[9], Data[10], Data[11], Data[12], Data[13], Data[14], Data[15]); */ /* * end of code copied from iasl */ void format_ip_addr(char *buf, size_t buflen, __u8 *addr) { struct in6_addr *addr_ipv6; addr_ipv6 = (struct in6_addr *)addr; if ( addr_ipv6->s6_addr32[0] == 0 && addr_ipv6->s6_addr32[1] == 0 && (ntohl(addr_ipv6->s6_addr32[2]) == 0xffff) ) /* ipv4 */ inet_ntop(AF_INET, &(addr_ipv6->s6_addr32[3]), buf, buflen); else /* ipv6 */ inet_ntop(AF_INET6, addr_ipv6, buf, buflen); } void check_in_table(__u16 length, __u16 offset, const char *name) { if (offset + length > header->length) goto bad; return; bad: errx(1, "Error: length/offset of \"%s\" not within nBFT.\n", name); } void check_in_heap(__u16 length, __u16 offset, const char *name) { if (length == 0) return; if (offset < header->heap_offset) goto bad; if (offset > header->heap_offset + header->heap_length) goto bad; if (offset + length > header->heap_offset + header->heap_length) goto bad; return; bad: errx(1, "Error: length/offset of \"%s\" is not within heap.\n", name); } void add_string_from_heap(struct json_object *parent, const char *name, __u16 length, __u16 offset) { if (length == 0) return; /* check string is within heap -- add one to length for zero terminator */ check_in_heap(length, offset, name); /* check that string is zero terminated correctly */ if (strnlen(raw_nbft + offset, length + 1) < length) fprintf(stderr, "Warning: string \"%s\" is shorter than specified length\n", name); else if (strnlen(raw_nbft + offset, length + 1) > length) { fprintf(stderr, "Error: string \"%s\" is not zero terminated\n", name); return; } json_object_object_add(parent, name, json_object_new_string(raw_nbft + offset)); } /* * Return transport_type string (Table 2) */ char *tr_type_str(__u8 transport_type) { switch (transport_type) { case 0: //reserved break; case 1: // TCP return "tcp"; break; default: // Reserved break; } } /* * * MAIN * */ int main(int argc, char *argv[]) { struct acpi_nbft_control *control; struct acpi_nbft_host *host; struct acpi_nbft_hfi *hfi; struct acpi_nbft_namespace *namespace; struct acpi_nbft_security *security; struct acpi_nbft_discovery *discovery; char *heap; char raw_nbft_filename[PATH_MAX] = DEFAULT_NBFT_PATH; FILE *raw_nbft_fp; size_t raw_nbft_size; __u8 sum; struct json_object *nbft_json; int c; /* * get options */ while ((c = getopt (argc, argv, "f:")) != -1) switch (c) { case 'f': if (sizeof(optarg) < sizeof(raw_nbft_filename)) strcpy(raw_nbft_filename, optarg); else errx(1, "Filename is too long.\n"); break; case '?': return 1; default: abort(); } /* * read raw nbft */ raw_nbft_fp = fopen(raw_nbft_filename, "rb"); if (raw_nbft_fp == NULL) errx(1, "error opening %s\n", raw_nbft_filename); fseek(raw_nbft_fp, 0L, SEEK_END); raw_nbft_size = ftell(raw_nbft_fp); rewind(raw_nbft_fp); raw_nbft = malloc(raw_nbft_size); fread(raw_nbft, sizeof(*raw_nbft), raw_nbft_size, raw_nbft_fp); fclose(raw_nbft_fp); /* * check header & get pointers to structures within nBFT * nBFT consists of: * HEADER * CONTROL * HOST * HFI * HFI_INFO * SUBSYSTEM NAMESPACE * SECURITY * DISCOVERY * HEAP (which contains strings and HFI_INFO structures) */ /* get header */ header = (struct acpi_nbft_table_header *)raw_nbft; sum = csum(raw_nbft, raw_nbft_size); if (sum) errx(1, "ACPI table checksum invalid\n"); if (strncmp(header->signature, "NBFT", 4)) errx(1, "nBFT table signature invalid, strncmp returned %x\n", sum); /* get control */ check_in_table(sizeof(struct acpi_nbft_control), sizeof(struct acpi_nbft_table_header), "control structure"); control = (struct acpi_nbft_control *)(raw_nbft + sizeof(struct acpi_nbft_table_header)); if (control->flags & (1 << CONTROLFLAG_BLOCK_VALID) == 0) errx(1, "nBFT control structure flags indicate table is not valid\n"); if (control->structure_id != NBFT_CONTROL) { errx(1, "nBFT control structure has invalid id\n"); } host = (struct acpi_nbft_host *)(raw_nbft + control->host_structure_offset); hfi = (struct acpi_nbft_hfi *)(raw_nbft + control->hfi_1_offset); namespace = (struct acpi_nbft_namespace *)(raw_nbft + control->namespace_1_offset); security = (struct acpi_nbft_security *)(raw_nbft + control->security_profile_1_offset); discovery = (struct acpi_nbft_discovery *)(raw_nbft + control->discovery_structure_offset); heap = raw_nbft + header->heap_offset; /* * create json object to hold nBFT */ nbft_json = json_object_new_object(); /* * add HEADER to json */ { struct json_object *header_json; char buf[32]; header_json = json_object_new_object(); json_object_object_add(header_json, "revision", json_object_new_int(header->revision)); memset(buf, 0, sizeof(buf)); strncpy(buf, header->oem_id, 4); json_object_object_add(header_json, "oemid", json_object_new_string(buf)); memset(buf, 0, sizeof(buf)); strncpy(buf, header->oem_table_id, sizeof(header->oem_table_id)); json_object_object_add(header_json, "oem_table_id", json_object_new_string(buf)); json_object_object_add(header_json, "oem_revision", json_object_new_int(header->oem_revision)); json_object_object_add(header_json, "creator_id", json_object_new_int(header->creator_id)); json_object_object_add(header_json, "creator_revision", json_object_new_int(header->creator_revision)); json_object_object_add(nbft_json, "header", header_json); } /* * add CONTROL structure to json */ { struct json_object *control_json; control_json = json_object_new_object(); json_object_object_add(control_json, "version", json_object_new_int(control->version)); json_object_object_add(control_json, "flags", json_object_new_int(control->flags)); json_object_object_add(control_json, "num_hfi", json_object_new_int(control->num_hfi)); json_object_object_add(control_json, "number_of_namespaces", json_object_new_int(control->number_of_namespaces)); json_object_object_add(control_json, "num_security_profiles", json_object_new_int(control->num_security_profiles)); json_object_object_add(nbft_json, "control", control_json); } /* * add HOST structure to json */ if (host->host_flags & (1 << HOSTFLAG_BLOCK_VALID)) { struct json_object *host_json; char buf[40]; host_json = json_object_new_object(); json_object_object_add(host_json, "version", json_object_new_int(host->version)); json_object_object_add(host_json, "host_flags", json_object_new_int(host->host_flags)); memset(buf, 0, sizeof(buf)); AuConvertUuidToString(host->host_identifier, buf); json_object_object_add(host_json, "host_identifier", json_object_new_string(buf)); add_string_from_heap(host_json, "initiator_host_nqn", host->host_nqn_length, host->host_nqn_offset); json_object_object_add(nbft_json, "host", host_json); } /* * add HFI structure(s) to json */ { struct json_object *hfis_array; struct json_object *hfi_json; struct json_object *hfi_info_json; struct acpi_nbft_hfi_info *hfi_info; char buf[50]; __u32 subnet_mask; hfis_array = json_object_new_array(); for (c = 0; c < control->num_hfi; c++) { if (!(hfi[c].hfi_flags & (1 << HFIFLAG_BLOCK_VALID))) continue; hfi_json = json_object_new_object(); json_object_object_add(hfi_json, "version", json_object_new_int(hfi[c].version)); json_object_object_add(hfi_json, "index", json_object_new_int(hfi[c].index)); json_object_object_add(hfi_json, "hfi_flags", json_object_new_int(hfi[c].hfi_flags)); json_object_object_add(hfi_json, "transport_type", json_object_new_string(tr_type_str(hfi[c].hfi_transport_type))); if (hfi[c].hfi_flags & (1 << HFIFLAG_HOSTID_OVERRIDE)) if (hfi[c].hostid_length == 16) { AuConvertUuidToString(raw_nbft + hfi[c].hostid_offset, buf); json_object_object_add(hfi_json, "hostid", json_object_new_string(buf)); } if (hfi[c].hfi_flags & (1 << HFIFLAG_HOSTNQN_OVERRIDE)) if (hfi[c].hostnqn_length > 0) json_object_object_add(hfi_json, "hostnqn", json_object_new_string(raw_nbft + hfi[c].hostnqn_offset)); hfi_info = (struct acpi_nbft_hfi_info *)(raw_nbft + hfi[c].info_structure_offset); if (!(hfi_info->transport_flags & (1 << HFIINFOFLAG_BLOCK_VALID))) continue; hfi_info_json = json_object_new_object(); json_object_object_add(hfi_info_json, "transport_type", json_object_new_string(tr_type_str(hfi_info->hfi_transport_type))); json_object_object_add(hfi_info_json, "version", json_object_new_int(hfi_info->version)); json_object_object_add(hfi_info_json, "hfi_index", json_object_new_int(hfi_info->hfi_index)); json_object_object_add(hfi_info_json, "transport_flags", json_object_new_int(hfi_info->transport_flags)); snprintf(buf, sizeof(buf), "%02x:%02x.%01x", (hfi_info->pci_sbdf & 0xff00) >> 8, (hfi_info->pci_sbdf & 0xf8) >> 3, (hfi_info->pci_sbdf & 0x7)); json_object_object_add(hfi_info_json, "pci_sbdf", json_object_new_string(buf)); snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", (unsigned) (unsigned char) hfi_info->mac_addr[0], (unsigned) (unsigned char) hfi_info->mac_addr[1], (unsigned) (unsigned char) hfi_info->mac_addr[2], (unsigned) (unsigned char) hfi_info->mac_addr[3], (unsigned) (unsigned char) hfi_info->mac_addr[4], (unsigned) (unsigned char) hfi_info->mac_addr[5]); json_object_object_add(hfi_info_json, "mac_address", json_object_new_string(buf)); json_object_object_add(hfi_info_json, "vlan", json_object_new_int(hfi_info->vlan)); json_object_object_add(hfi_info_json, "origin", json_object_new_int(hfi_info->origin)); format_ip_addr(buf, sizeof(buf), hfi_info->ip_address); json_object_object_add(hfi_info_json, "ip_address", json_object_new_string(buf)); if (hfi_info->subnet_mask_prefix <= 32) subnet_mask = 0xffffffff << (32 - hfi_info->subnet_mask_prefix); else fprintf(stderr, "Error: Subnet mask prefix of %d is invalid\n", hfi_info->subnet_mask_prefix); snprintf(buf, sizeof(buf), "%d.%d.%d.%d", ((__u8 *)(&subnet_mask))[3], ((__u8 *)(&subnet_mask))[2], ((__u8 *)(&subnet_mask))[1], ((__u8 *)(&subnet_mask))[0]); json_object_object_add(hfi_info_json, "subnet_mask", json_object_new_string(buf)); format_ip_addr(buf, sizeof(buf), hfi_info->ip_gateway); json_object_object_add(hfi_info_json, "ip_gateway", json_object_new_string(buf)); json_object_object_add(hfi_info_json, "route_metric", json_object_new_int(hfi_info->route_metric)); format_ip_addr(buf, sizeof(buf), hfi_info->primary_dns); json_object_object_add(hfi_info_json, "primary_dns", json_object_new_string(buf)); format_ip_addr(buf, sizeof(buf), hfi_info->secondary_dns); json_object_object_add(hfi_info_json, "secondary_dns", json_object_new_string(buf)); format_ip_addr(buf, sizeof(buf), hfi_info->dhcp_server); json_object_object_add(hfi_info_json, "dhcp_server", json_object_new_string(buf)); //add_string_from_heap(hfi_info_json, "host_name", // hfi_info->host_name_length, hfi_info->host_name_offset); json_object_object_add(hfi_json, "hfi_info", hfi_info_json); json_object_array_add(hfis_array, hfi_json); } json_object_object_add(nbft_json, "hfi", hfis_array); } /* * add nBFT namespace structure(s) to json */ { struct json_object *namespaces_array; struct json_object *namespace_json; char buf[128]; char *bufp = buf; int i; namespaces_array = json_object_new_array(); for (c = 0; c < control->number_of_namespaces; c++) { namespace_json = json_object_new_object(); json_object_object_add(namespace_json, "version", json_object_new_int(namespace[c].version)); json_object_object_add(namespace_json, "index", json_object_new_int(namespace[c].index)); json_object_object_add(namespace_json, "subsystem_namespace_flags", json_object_new_int(namespace[c].subsystem_namespace_flags)); json_object_object_add(namespace_json, "transport_type", json_object_new_string(tr_type_str(namespace[c].transport_type))); json_object_object_add(namespace_json, "primary_discovery_ctrl_offset", json_object_new_int(namespace[c].primary_discovery_ctrl_offset)); format_ip_addr(buf, sizeof(buf), namespace[c].subsystem_transport_address); json_object_object_add(namespace_json, "subsystem_transport_address", json_object_new_string(buf)); json_object_object_add(namespace_json, "subsystem_transport_port", json_object_new_int(namespace[c].subsystem_transport_port)); json_object_object_add(namespace_json, "mp_group", json_object_new_int(namespace[c].mp_group)); json_object_object_add(namespace_json, "subsystem_port_id", json_object_new_int(namespace[c].subsystem_port_id)); json_object_object_add(namespace_json, "controller_id", json_object_new_int(namespace[c].controller_id)); json_object_object_add(namespace_json, "nsid", json_object_new_int(namespace[c].nsid)); memset(buf, 0, sizeof(buf)); switch (namespace[c].nid_type) { case 1: // IEEE EIU-64 (64 bits) json_object_object_add(namespace_json, "nid_type", json_object_new_string("ieee_eiu-64")); for (i = 0; i < 8; i++) bufp += sprintf(bufp, "%02x", (namespace[c].nid)[i]); json_object_object_add(namespace_json, "nid", json_object_new_string(buf)); break; case 2: // NGUID (128 bits) json_object_object_add(namespace_json, "nid_type", json_object_new_string("nguid")); for (i = 0; i < 16; i++) bufp += sprintf(bufp, "%02x", (namespace[c].nid)[i]); json_object_object_add(namespace_json, "nid", json_object_new_string(buf)); break; case 3: // NS UUID (128 bits) json_object_object_add(namespace_json, "nid_type", json_object_new_string("ns_uuid")); AuConvertUuidToString(namespace[c].nid, buf); json_object_object_add(namespace_json, "nid", json_object_new_string(buf)); break; case 0: // none default: break; } json_object_object_add(namespace_json, "security_structure_index", json_object_new_int(namespace[c].security_struct_index)); /* * HFI association is an array of 8-bit numbers... * add them to the JSON as an array */ { struct json_object *hfi_association_array; unsigned char *hfi_association_heap_address; int offset, val; hfi_association_array = json_object_new_array(); offset = namespace[c].hfi_association_offset; check_in_heap(namespace[c].hfi_association_length, offset, "hfi_association"); hfi_association_heap_address = (void *)(raw_nbft + offset); for (i = 0; i < namespace[c].hfi_association_length; i++) { val = hfi_association_heap_address[i]; json_object_array_add(hfi_association_array, json_object_new_int(val)); } json_object_object_add(namespace_json, "hfi_association", hfi_association_array); } add_string_from_heap(namespace_json, "subsystem_namespace_nqn", namespace[c].subsystem_namespace_nqn_length, namespace[c].subsystem_namespace_nqn_offset); json_object_array_add(namespaces_array, namespace_json); } json_object_object_add(nbft_json, "namespace", namespaces_array); } /* * add nBFT security structure(s) to json */ { struct json_object *security_profiles_array; struct json_object *security_profile_json; char buf[50]; security_profiles_array = json_object_new_array(); for (c = 0; c < control->num_security_profiles; c++) { if (!(security[c].security_structure_flags & (1 << SECFLAG_BLOCK_VALID))) continue; security_profile_json = json_object_new_object(); json_object_object_add(security_profile_json, "version", json_object_new_int(security[c].version)); json_object_object_add(security_profile_json, "index", json_object_new_int(security[c].index)); json_object_object_add(security_profile_json, "security_structure_flags", json_object_new_int(security[c].security_structure_flags)); if (security[c].security_structure_flags & (1 << SECFLAG_SECURITY_POLICY_LIST)) add_string_from_heap(security_profile_json, "secure_channel_allowed_algorithms", security[c].secure_channel_allowed_algorithms_length, security[c].secure_channel_allowed_algorithms_offset); if (security[c].security_structure_flags & (1 << SECFLAG_AUTHENTICATION_POLICY_LIST)) add_string_from_heap(security_profile_json, "authentication_protocols_allowed", security[c].authentication_protocols_allowed_length, security[c].authentication_protocols_allowed_offset); if (security[c].security_structure_flags & (1 << SECFLAG_CIPHER_SUITES_RESTRICTED_BY_POLICY)) add_string_from_heap(security_profile_json, "cipher_suite_name", security[c].cipher_suite_name_length, security[c].cipher_suite_name_offset); /* should be a DH groups restricted by policy flag?? */ if (security[c].supported_dh_groups_length > 0) add_string_from_heap(security_profile_json, "supported_dh_groups", security[c].supported_dh_groups_length, security[c].supported_dh_groups_offset); memset(buf, 0, sizeof(buf)); switch (security[c].secret_type) { case SECRET_TYPE_NONE: snprintf(buf, sizeof(buf), "none"); break; case SECRET_TYPE_REDFISH_HOST_INTERFACE_URI: snprintf(buf, sizeof(buf), "redfish_host_interface_uri"); break; case SECRET_TYPE_OEM_URI: snprintf(buf, sizeof(buf), "oem_uri"); break; default: snprintf(buf, sizeof(buf), "unknown"); } json_object_object_add(security_profile_json, "secret_type", json_object_new_string(buf)); add_string_from_heap(security_profile_json, "secure_hash_functions", security[c].secure_hash_functions_length, security[c].secure_hash_functions_offset); add_string_from_heap(security_profile_json, "secret_keypath", security[c].secret_keypath_length, security[c].secret_keypath_offset); add_string_from_heap(security_profile_json, "extended_authentication", security[c].extended_authentication_length, security[c].extended_authentication_offset); json_object_array_add(security_profiles_array, security_profile_json); } json_object_object_add(nbft_json, "security", security_profiles_array); } /* * add discovery structure to json */ { struct json_object *nbft_discovery_json; struct json_object *nbft_discovery_records_array; struct json_object *nbft_discovery_record_json; struct discovery_record *record; nbft_discovery_json = json_object_new_object(); json_object_object_add(nbft_discovery_json, "version", json_object_new_int(discovery->version)); json_object_object_add(nbft_discovery_json, "discovery_structure_flags", json_object_new_int(discovery->discovery_structure_flags)); json_object_object_add(nbft_discovery_json, "number_of_records", json_object_new_int(discovery->number_of_records)); nbft_discovery_records_array = json_object_new_array(); for (c = 0; c < discovery->number_of_records; c++) { nbft_discovery_record_json = json_object_new_object(); json_object_object_add(nbft_discovery_record_json, "discovery_record_hfi", json_object_new_int(discovery->record[c].discovery_record_hfi)); json_object_object_add(nbft_discovery_record_json, "discovery_record_security_profile", json_object_new_int(discovery->record[c].discovery_record_security_profile)); add_string_from_heap(nbft_discovery_record_json, "discovery_ctrl_addr", discovery->record[c].discovery_ctrl_addr_length, discovery->record[c].discovery_ctrl_addr_offset); add_string_from_heap(nbft_discovery_record_json, "discovery_controller_nqn", discovery->record[c].discovery_controller_nqn_length, discovery->record[c].discovery_controller_nqn_offset); json_object_array_add(nbft_discovery_records_array, nbft_discovery_record_json); } json_object_object_add(nbft_discovery_json, "records", nbft_discovery_records_array); json_object_object_add(nbft_json, "discovery", nbft_discovery_json); } /* * output JSON */ printf("%s\n", json_object_to_json_string(nbft_json)); json_object_put(nbft_json); free(raw_nbft); }