blob: e0eeb9b95e2c5ed8e94e75226787e5cb880a94c4 [file] [log] [blame]
Hariharasubramanian R44473092015-10-15 08:25:28 -05001/*
2 * Copyright (C) 2003-2014 FreeIPMI Core Team
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05003 *
Hariharasubramanian R44473092015-10-15 08:25:28 -05004 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Hariharasubramanian Ra032c772015-10-20 07:28:19 -050016 *
Hariharasubramanian R44473092015-10-15 08:25:28 -050017 */
18/*****************************************************************************\
19 * Copyright (C) 2007-2014 Lawrence Livermore National Security, LLC.
20 * Copyright (C) 2007 The Regents of the University of California.
21 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
22 * Written by Albert Chu <chu11@llnl.gov>
23 * UCRL-CODE-232183
24 *
25 * This file is part of Ipmi-fru, a tool used for retrieving
26 * motherboard field replaceable unit (FRU) information. For details,
27 * see http://www.llnl.gov/linux/.
28 *
29 * Ipmi-fru is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by the
31 * Free Software Foundation; either version 3 of the License, or (at your
32 * option) any later version.
33 *
34 * Ipmi-fru is distributed in the hope that it will be useful, but
35 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
36 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
37 * for more details.
38 *
39 * You should have received a copy of the GNU General Public License along
40 * with Ipmi-fru. If not, see <http://www.gnu.org/licenses/>.
41\*****************************************************************************/
Ratan Gupta19c617b2017-02-10 15:39:40 +053042#include "frup.hpp"
Hariharasubramanian R44473092015-10-15 08:25:28 -050043
Patrick Venturec9508db2018-10-16 17:18:43 -070044#include <ctype.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <systemd/sd-bus.h>
49#include <time.h>
50#include <unistd.h>
Hariharasubramanian R44473092015-10-15 08:25:28 -050051
George Liu5b1725d2025-07-30 15:56:49 +080052#include <phosphor-logging/lg2.hpp>
53
Patrick Venturec9508db2018-10-16 17:18:43 -070054#define TEXTSTR(a) #a
55#define ASSERT(x) \
56 do \
57 { \
58 if (0 == (x)) \
59 { \
60 fprintf(stderr, \
61 "Assertion failed: %s, " \
62 "%d at \'%s\'\n", \
63 __FILE__, __LINE__, TEXTSTR(a)); \
64 return -1; \
65 } \
66 } while (0)
67
68#define IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX 512
69#define IPMI_FRU_SENTINEL_VALUE 0xC1
70#define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK 0xC0
71#define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT 0x06
Hariharasubramanian R44473092015-10-15 08:25:28 -050072#define IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK 0x3F
Patrick Venturec9508db2018-10-16 17:18:43 -070073#define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE 0x03
Hariharasubramanian R44473092015-10-15 08:25:28 -050074
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -050075/* OpenBMC defines for Parser */
Patrick Venturec9508db2018-10-16 17:18:43 -070076#define IPMI_FRU_AREA_INTERNAL_USE 0x00
77#define IPMI_FRU_AREA_CHASSIS_INFO 0x01
78#define IPMI_FRU_AREA_BOARD_INFO 0x02
79#define IPMI_FRU_AREA_PRODUCT_INFO 0x03
80#define IPMI_FRU_AREA_MULTI_RECORD 0x04
81#define IPMI_FRU_AREA_TYPE_MAX 0x05
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -050082
Patrick Venturec9508db2018-10-16 17:18:43 -070083#define OPENBMC_VPD_KEY_LEN 64
84#define OPENBMC_VPD_VAL_LEN 512
Hariharasubramanian R44473092015-10-15 08:25:28 -050085
Willy Tu9084f522022-11-03 08:17:54 +000086constexpr long fruEpochMinutes = 820454400;
87
Hariharasubramanian R44473092015-10-15 08:25:28 -050088struct ipmi_fru_field
89{
Patrick Venturec9508db2018-10-16 17:18:43 -070090 uint8_t type_length_field[IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX];
91 /* store length of data stored in buffer */
92 unsigned int type_length_field_length;
Hariharasubramanian R44473092015-10-15 08:25:28 -050093};
94
95typedef struct ipmi_fru_field ipmi_fru_field_t;
Hariharasubramanian Ra032c772015-10-20 07:28:19 -050096/*
97 * FRU Parser
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -050098 */
Hariharasubramanian R44473092015-10-15 08:25:28 -050099
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500100typedef struct ipmi_fru_area_info
101{
102 uint8_t off;
103 uint8_t len;
104} ipmi_fru_area_info_t;
105
106typedef struct ipmi_fru_common_hdr
107{
108 uint8_t fmtver;
109 uint8_t internal;
110 uint8_t chassis;
111 uint8_t board;
112 uint8_t product;
113 uint8_t multirec;
114} __attribute__((packed)) ipmi_fru_common_hdr_t;
115
Patrick Venturec9508db2018-10-16 17:18:43 -0700116const char* vpd_key_names[] = {
117 "Key Names Table Start",
118 "Type", /*OPENBMC_VPD_KEY_CHASSIS_TYPE*/
119 "Part Number", /*OPENBMC_VPD_KEY_CHASSIS_PART_NUM,*/
120 "Serial Number", /*OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,*/
121 "Custom Field 1", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM1,*/
122 "Custom Field 2", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM2,*/
123 "Custom Field 3", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM3,*/
124 "Custom Field 4", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM4,*/
125 "Custom Field 5", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM5,*/
126 "Custom Field 6", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM6,*/
127 "Custom Field 7", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM7,*/
128 "Custom Field 8", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM8,*/
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500129
Patrick Venturec9508db2018-10-16 17:18:43 -0700130 "Mfg Date",
131 /* OPENBMC_VPD_KEY_BOARD_MFG_DATE, */ /* not a type/len */
132 "Manufacturer", /* OPENBMC_VPD_KEY_BOARD_MFR, */
133 "Name", /* OPENBMC_VPD_KEY_BOARD_NAME, */
Patrick Williamscfa96af2023-05-10 07:50:26 -0500134 "Serial Number", /* OPENBMC_VPD_KEY_BOARD_SERIAL_NUM, */
135 "Part Number", /* OPENBMC_VPD_KEY_BOARD_PART_NUM, */
136 "FRU File ID", /* OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID, */
137 "Custom Field 1", /*OPENBMC_VPD_KEY_BOARD_CUSTOM1,*/
138 "Custom Field 2", /*OPENBMC_VPD_KEY_BOARD_CUSTOM2,*/
139 "Custom Field 3", /*OPENBMC_VPD_KEY_BOARD_CUSTOM3,*/
140 "Custom Field 4", /*OPENBMC_VPD_KEY_BOARD_CUSTOM4,*/
141 "Custom Field 5", /*OPENBMC_VPD_KEY_BOARD_CUSTOM5,*/
142 "Custom Field 6", /*OPENBMC_VPD_KEY_BOARD_CUSTOM6,*/
143 "Custom Field 7", /*OPENBMC_VPD_KEY_BOARD_CUSTOM7,*/
144 "Custom Field 8", /*OPENBMC_VPD_KEY_BOARD_CUSTOM8,*/
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500145
Patrick Williamscfa96af2023-05-10 07:50:26 -0500146 "Manufacturer", /* OPENBMC_VPD_KEY_PRODUCT_MFR, */
147 "Name", /* OPENBMC_VPD_KEY_PRODUCT_NAME, */
148 "Model Number", /* OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM, */
149 "Version", /* OPENBMC_VPD_KEY_PRODUCT_VER, */
150 "Serial Number", /* OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM, */
151 "Asset Tag", /* OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG, */
152 "FRU File ID", /* OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID, */
153 "Custom Field 1", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM1,*/
154 "Custom Field 2", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM2,*/
155 "Custom Field 3", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM3,*/
156 "Custom Field 4", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM4,*/
157 "Custom Field 5", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM5,*/
158 "Custom Field 6", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM6,*/
159 "Custom Field 7", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM7,*/
160 "Custom Field 8", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM8,*/
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500161
Patrick Venturec9508db2018-10-16 17:18:43 -0700162 "Key Names Table End" /*OPENBMC_VPD_KEY_MAX,*/
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500163};
164
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500165/*
166 * --------------------------------------------------------------------
167 *
168 * --------------------------------------------------------------------
169 */
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -0500170
Patrick Venturec9508db2018-10-16 17:18:43 -0700171static size_t _to_time_str(uint32_t mfg_date_time, char* timestr, uint32_t len)
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -0500172{
173 struct tm tm;
174 time_t t;
175 size_t s;
176
Patrick Venturec9508db2018-10-16 17:18:43 -0700177 ASSERT(timestr);
178 ASSERT(len);
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -0500179
Patrick Venturec9508db2018-10-16 17:18:43 -0700180 memset(&tm, '\0', sizeof(struct tm));
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -0500181
182 t = mfg_date_time;
Patrick Venturec9508db2018-10-16 17:18:43 -0700183 gmtime_r(&t, &tm);
Willy Tu9084f522022-11-03 08:17:54 +0000184 s = strftime(timestr, len, "%F - %H:%M:%S UTC", &tm);
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -0500185
186 return s;
187}
188
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500189/* private method to parse type/length */
Patrick Venturec9508db2018-10-16 17:18:43 -0700190static int _parse_type_length(const void* areabuf, unsigned int areabuflen,
191 unsigned int current_area_offset,
192 uint8_t* number_of_data_bytes,
193 ipmi_fru_field_t* field)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500194{
Jayanth Othayoth3ed31cb2025-06-07 02:10:57 -0500195 const uint8_t* areabufptr = static_cast<const uint8_t*>(areabuf);
Patrick Venturec9508db2018-10-16 17:18:43 -0700196 uint8_t type_length;
197 uint8_t type_code;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500198
Patrick Venturec9508db2018-10-16 17:18:43 -0700199 ASSERT(areabuf);
200 ASSERT(areabuflen);
201 ASSERT(number_of_data_bytes);
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500202
Patrick Venturec9508db2018-10-16 17:18:43 -0700203 type_length = areabufptr[current_area_offset];
Hariharasubramanian R44473092015-10-15 08:25:28 -0500204
Patrick Venturec9508db2018-10-16 17:18:43 -0700205 /* ipmi workaround
206 *
207 * dell p weredge r610
208 *
209 * my reading of the fru spec is that all non-custom fields are
210 * required to be listed by the vendor. however, on this
211 * motherboard, some areas list this, indicating that there is
212 * no more data to be parsed. so now, for "required" fields, i
213 * check to see if the type-length field is a sentinel before
214 * calling this function.
215 */
Hariharasubramanian R44473092015-10-15 08:25:28 -0500216
Patrick Venturec9508db2018-10-16 17:18:43 -0700217 ASSERT(type_length != IPMI_FRU_SENTINEL_VALUE);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500218
Patrick Venturec9508db2018-10-16 17:18:43 -0700219 type_code = (type_length & IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK) >>
220 IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT;
Patrick Williamsa3cc2282024-08-16 15:20:14 -0400221 (*number_of_data_bytes) =
222 type_length & IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500223
Patrick Venturec9508db2018-10-16 17:18:43 -0700224 /* special case: this shouldn't be a length of 0x01 (see type/length
225 * byte format in fru information storage definition).
226 */
227 if (type_code == IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE &&
228 (*number_of_data_bytes) == 0x01)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500229 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700230 return (-1);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500231 }
232
Patrick Venturec9508db2018-10-16 17:18:43 -0700233 if ((current_area_offset + 1 + (*number_of_data_bytes)) > areabuflen)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500234 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700235 return (-1);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500236 }
237
Patrick Venturec9508db2018-10-16 17:18:43 -0700238 if (field)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500239 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700240 memset(field->type_length_field, '\0',
241 IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
242 memcpy(field->type_length_field, &areabufptr[current_area_offset],
243 1 + (*number_of_data_bytes));
244 field->type_length_field_length = 1 + (*number_of_data_bytes);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500245 }
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500246
Patrick Venturec9508db2018-10-16 17:18:43 -0700247 return (0);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500248}
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500249
Patrick Williamsa3cc2282024-08-16 15:20:14 -0400250int ipmi_fru_chassis_info_area(
251 const void* areabuf, unsigned int areabuflen, uint8_t* chassis_type,
252 ipmi_fru_field_t* chassis_part_number,
253 ipmi_fru_field_t* chassis_serial_number,
254 ipmi_fru_field_t* chassis_custom_fields,
255 unsigned int chassis_custom_fields_len)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500256{
Jayanth Othayoth3ed31cb2025-06-07 02:10:57 -0500257 const uint8_t* areabufptr = static_cast<const uint8_t*>(areabuf);
Patrick Venturec9508db2018-10-16 17:18:43 -0700258 unsigned int area_offset = 0;
259 unsigned int custom_fields_index = 0;
260 uint8_t number_of_data_bytes;
261 int rv = -1;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500262
Patrick Venturec9508db2018-10-16 17:18:43 -0700263 if (!areabuf || !areabuflen)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500264 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700265 return (-1);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500266 }
267
Patrick Venturec9508db2018-10-16 17:18:43 -0700268 if (chassis_part_number)
269 memset(chassis_part_number, '\0', sizeof(ipmi_fru_field_t));
270 if (chassis_serial_number)
271 memset(chassis_serial_number, '\0', sizeof(ipmi_fru_field_t));
272 if (chassis_custom_fields && chassis_custom_fields_len)
273 memset(chassis_custom_fields, '\0',
274 sizeof(ipmi_fru_field_t) * chassis_custom_fields_len);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500275
Patrick Venturec9508db2018-10-16 17:18:43 -0700276 if (chassis_type)
277 (*chassis_type) = areabufptr[area_offset];
278 area_offset++;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500279
Patrick Venturec9508db2018-10-16 17:18:43 -0700280 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
281 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500282
Patrick Venturec9508db2018-10-16 17:18:43 -0700283 if (_parse_type_length(areabufptr, areabuflen, area_offset,
284 &number_of_data_bytes, chassis_part_number) < 0)
285 goto cleanup;
286 area_offset += 1; /* type/length byte */
287 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500288
Patrick Venturec9508db2018-10-16 17:18:43 -0700289 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
290 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500291
Patrick Venturec9508db2018-10-16 17:18:43 -0700292 if (_parse_type_length(areabufptr, areabuflen, area_offset,
293 &number_of_data_bytes, chassis_serial_number) < 0)
294 goto cleanup;
295 area_offset += 1; /* type/length byte */
296 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500297
Patrick Venturec9508db2018-10-16 17:18:43 -0700298 while (area_offset < areabuflen &&
299 areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500300 {
Jayanth Othayoth883aa422024-12-18 10:33:06 -0600301 ipmi_fru_field_t* field_ptr = nullptr;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500302
Patrick Venturec9508db2018-10-16 17:18:43 -0700303 if (chassis_custom_fields && chassis_custom_fields_len)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500304 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700305 if (custom_fields_index < chassis_custom_fields_len)
306 field_ptr = &chassis_custom_fields[custom_fields_index];
307 else
Hariharasubramanian R44473092015-10-15 08:25:28 -0500308 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700309 goto cleanup;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500310 }
311 }
312
Patrick Venturec9508db2018-10-16 17:18:43 -0700313 if (_parse_type_length(areabufptr, areabuflen, area_offset,
314 &number_of_data_bytes, field_ptr) < 0)
315 goto cleanup;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500316
Patrick Venturec9508db2018-10-16 17:18:43 -0700317 area_offset += 1; /* type/length byte */
318 area_offset += number_of_data_bytes;
319 custom_fields_index++;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500320 }
321
Patrick Venturec9508db2018-10-16 17:18:43 -0700322out:
323 rv = 0;
324cleanup:
325 return (rv);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500326}
327
Patrick Venturec9508db2018-10-16 17:18:43 -0700328int ipmi_fru_board_info_area(
329 const void* areabuf, unsigned int areabuflen, uint8_t* language_code,
330 uint32_t* mfg_date_time, ipmi_fru_field_t* board_manufacturer,
331 ipmi_fru_field_t* board_product_name, ipmi_fru_field_t* board_serial_number,
332 ipmi_fru_field_t* board_part_number, ipmi_fru_field_t* board_fru_file_id,
333 ipmi_fru_field_t* board_custom_fields, unsigned int board_custom_fields_len)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500334{
Jayanth Othayoth3ed31cb2025-06-07 02:10:57 -0500335 const uint8_t* areabufptr = static_cast<const uint8_t*>(areabuf);
Patrick Venturec9508db2018-10-16 17:18:43 -0700336 unsigned int area_offset = 0;
337 unsigned int custom_fields_index = 0;
338 uint8_t number_of_data_bytes;
339 int rv = -1;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500340
Patrick Venturec9508db2018-10-16 17:18:43 -0700341 if (!areabuf || !areabuflen)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500342 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700343 return (-1);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500344 }
345
Patrick Venturec9508db2018-10-16 17:18:43 -0700346 if (board_manufacturer)
347 memset(board_manufacturer, '\0', sizeof(ipmi_fru_field_t));
348 if (board_product_name)
349 memset(board_product_name, '\0', sizeof(ipmi_fru_field_t));
350 if (board_serial_number)
351 memset(board_serial_number, '\0', sizeof(ipmi_fru_field_t));
352 if (board_part_number)
353 memset(board_part_number, '\0', sizeof(ipmi_fru_field_t));
354 if (board_fru_file_id)
355 memset(board_fru_file_id, '\0', sizeof(ipmi_fru_field_t));
356 if (board_custom_fields && board_custom_fields_len)
357 memset(board_custom_fields, '\0',
358 sizeof(ipmi_fru_field_t) * board_custom_fields_len);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500359
Patrick Venturec9508db2018-10-16 17:18:43 -0700360 if (language_code)
361 (*language_code) = areabufptr[area_offset];
362 area_offset++;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500363
Patrick Venturec9508db2018-10-16 17:18:43 -0700364 if (mfg_date_time)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500365 {
Willy Tu9084f522022-11-03 08:17:54 +0000366 unsigned int minutes = areabufptr[area_offset];
Patrick Venturec9508db2018-10-16 17:18:43 -0700367 area_offset++;
Willy Tu9084f522022-11-03 08:17:54 +0000368 minutes |= (areabufptr[area_offset] << 8);
Patrick Venturec9508db2018-10-16 17:18:43 -0700369 area_offset++;
Willy Tu9084f522022-11-03 08:17:54 +0000370 minutes |= (areabufptr[area_offset] << 16);
Patrick Venturec9508db2018-10-16 17:18:43 -0700371 area_offset++;
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500372
Willy Tu9084f522022-11-03 08:17:54 +0000373 /* In fru, epoch is 0:00 hrs 1/1/96 == 820454400
374 * Remove it directly and remove the time conversion.
Patrick Venturec9508db2018-10-16 17:18:43 -0700375 */
Willy Tu9084f522022-11-03 08:17:54 +0000376 (*mfg_date_time) = fruEpochMinutes + static_cast<long>(minutes) * 60;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500377 }
Patrick Venturec9508db2018-10-16 17:18:43 -0700378 else
379 area_offset += 3;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500380
Patrick Venturec9508db2018-10-16 17:18:43 -0700381 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
382 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500383
Patrick Venturec9508db2018-10-16 17:18:43 -0700384 if (_parse_type_length(areabufptr, areabuflen, area_offset,
385 &number_of_data_bytes, board_manufacturer) < 0)
386 goto cleanup;
387 area_offset += 1; /* type/length byte */
388 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500389
Patrick Venturec9508db2018-10-16 17:18:43 -0700390 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
391 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500392
Patrick Venturec9508db2018-10-16 17:18:43 -0700393 if (_parse_type_length(areabufptr, areabuflen, area_offset,
394 &number_of_data_bytes, board_product_name) < 0)
395 goto cleanup;
396 area_offset += 1; /* type/length byte */
397 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500398
Patrick Venturec9508db2018-10-16 17:18:43 -0700399 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
400 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500401
Patrick Venturec9508db2018-10-16 17:18:43 -0700402 if (_parse_type_length(areabufptr, areabuflen, area_offset,
403 &number_of_data_bytes, board_serial_number) < 0)
404 goto cleanup;
405 area_offset += 1; /* type/length byte */
406 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500407
Patrick Venturec9508db2018-10-16 17:18:43 -0700408 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
409 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500410
Patrick Venturec9508db2018-10-16 17:18:43 -0700411 if (_parse_type_length(areabufptr, areabuflen, area_offset,
412 &number_of_data_bytes, board_part_number) < 0)
413 goto cleanup;
414 area_offset += 1; /* type/length byte */
415 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500416
Patrick Venturec9508db2018-10-16 17:18:43 -0700417 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
418 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500419
Patrick Venturec9508db2018-10-16 17:18:43 -0700420 if (_parse_type_length(areabufptr, areabuflen, area_offset,
421 &number_of_data_bytes, board_fru_file_id) < 0)
422 goto cleanup;
423 area_offset += 1; /* type/length byte */
424 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500425
Patrick Venturec9508db2018-10-16 17:18:43 -0700426 while (area_offset < areabuflen &&
427 areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500428 {
Jayanth Othayoth883aa422024-12-18 10:33:06 -0600429 ipmi_fru_field_t* field_ptr = nullptr;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500430
Patrick Venturec9508db2018-10-16 17:18:43 -0700431 if (board_custom_fields && board_custom_fields_len)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500432 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700433 if (custom_fields_index < board_custom_fields_len)
434 field_ptr = &board_custom_fields[custom_fields_index];
435 else
Hariharasubramanian R44473092015-10-15 08:25:28 -0500436 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700437 goto cleanup;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500438 }
439 }
440
Patrick Venturec9508db2018-10-16 17:18:43 -0700441 if (_parse_type_length(areabufptr, areabuflen, area_offset,
442 &number_of_data_bytes, field_ptr) < 0)
443 goto cleanup;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500444
Patrick Venturec9508db2018-10-16 17:18:43 -0700445 area_offset += 1; /* type/length byte */
446 area_offset += number_of_data_bytes;
447 custom_fields_index++;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500448 }
449
Patrick Venturec9508db2018-10-16 17:18:43 -0700450out:
451 rv = 0;
452cleanup:
453 return (rv);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500454}
455
Patrick Venturec9508db2018-10-16 17:18:43 -0700456int ipmi_fru_product_info_area(
457 const void* areabuf, unsigned int areabuflen, uint8_t* language_code,
458 ipmi_fru_field_t* product_manufacturer_name, ipmi_fru_field_t* product_name,
459 ipmi_fru_field_t* product_part_model_number,
460 ipmi_fru_field_t* product_version, ipmi_fru_field_t* product_serial_number,
461 ipmi_fru_field_t* product_asset_tag, ipmi_fru_field_t* product_fru_file_id,
462 ipmi_fru_field_t* product_custom_fields,
463 unsigned int product_custom_fields_len)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500464{
Jayanth Othayoth3ed31cb2025-06-07 02:10:57 -0500465 const uint8_t* areabufptr = static_cast<const uint8_t*>(areabuf);
Patrick Venturec9508db2018-10-16 17:18:43 -0700466 unsigned int area_offset = 0;
467 unsigned int custom_fields_index = 0;
468 uint8_t number_of_data_bytes;
469 int rv = -1;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500470
Patrick Venturec9508db2018-10-16 17:18:43 -0700471 if (!areabuf || !areabuflen)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500472 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700473 return (-1);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500474 }
475
Patrick Venturec9508db2018-10-16 17:18:43 -0700476 if (product_manufacturer_name)
477 memset(product_manufacturer_name, '\0', sizeof(ipmi_fru_field_t));
478 if (product_name)
479 memset(product_name, '\0', sizeof(ipmi_fru_field_t));
480 if (product_part_model_number)
481 memset(product_part_model_number, '\0', sizeof(ipmi_fru_field_t));
482 if (product_version)
483 memset(product_version, '\0', sizeof(ipmi_fru_field_t));
484 if (product_serial_number)
485 memset(product_serial_number, '\0', sizeof(ipmi_fru_field_t));
486 if (product_asset_tag)
487 memset(product_asset_tag, '\0', sizeof(ipmi_fru_field_t));
488 if (product_fru_file_id)
489 memset(product_fru_file_id, '\0', sizeof(ipmi_fru_field_t));
490 if (product_custom_fields && product_custom_fields_len)
491 memset(product_custom_fields, '\0',
492 sizeof(ipmi_fru_field_t) * product_custom_fields_len);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500493
Patrick Venturec9508db2018-10-16 17:18:43 -0700494 if (language_code)
495 (*language_code) = areabufptr[area_offset];
496 area_offset++;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500497
Patrick Venturec9508db2018-10-16 17:18:43 -0700498 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
499 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500500
Patrick Venturec9508db2018-10-16 17:18:43 -0700501 if (_parse_type_length(areabufptr, areabuflen, area_offset,
Patrick Williamsa3cc2282024-08-16 15:20:14 -0400502 &number_of_data_bytes, product_manufacturer_name) <
503 0)
Patrick Venturec9508db2018-10-16 17:18:43 -0700504 goto cleanup;
505 area_offset += 1; /* type/length byte */
506 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500507
Patrick Venturec9508db2018-10-16 17:18:43 -0700508 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
509 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500510
Patrick Venturec9508db2018-10-16 17:18:43 -0700511 if (_parse_type_length(areabufptr, areabuflen, area_offset,
512 &number_of_data_bytes, product_name) < 0)
513 goto cleanup;
514 area_offset += 1; /* type/length byte */
515 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500516
Patrick Venturec9508db2018-10-16 17:18:43 -0700517 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
518 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500519
Patrick Venturec9508db2018-10-16 17:18:43 -0700520 if (_parse_type_length(areabufptr, areabuflen, area_offset,
Patrick Williamsa3cc2282024-08-16 15:20:14 -0400521 &number_of_data_bytes, product_part_model_number) <
522 0)
Patrick Venturec9508db2018-10-16 17:18:43 -0700523 goto cleanup;
524 area_offset += 1; /* type/length byte */
525 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500526
Patrick Venturec9508db2018-10-16 17:18:43 -0700527 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
528 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500529
Patrick Venturec9508db2018-10-16 17:18:43 -0700530 if (_parse_type_length(areabufptr, areabuflen, area_offset,
531 &number_of_data_bytes, product_version) < 0)
532 goto cleanup;
533 area_offset += 1; /* type/length byte */
534 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500535
Patrick Venturec9508db2018-10-16 17:18:43 -0700536 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
537 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500538
Patrick Venturec9508db2018-10-16 17:18:43 -0700539 if (_parse_type_length(areabufptr, areabuflen, area_offset,
540 &number_of_data_bytes, product_serial_number) < 0)
541 goto cleanup;
542 area_offset += 1; /* type/length byte */
543 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500544
Patrick Venturec9508db2018-10-16 17:18:43 -0700545 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
546 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500547
Patrick Venturec9508db2018-10-16 17:18:43 -0700548 if (_parse_type_length(areabufptr, areabuflen, area_offset,
549 &number_of_data_bytes, product_asset_tag) < 0)
550 goto cleanup;
551 area_offset += 1; /* type/length byte */
552 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500553
Patrick Venturec9508db2018-10-16 17:18:43 -0700554 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
555 goto out;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500556
Patrick Venturec9508db2018-10-16 17:18:43 -0700557 if (_parse_type_length(areabufptr, areabuflen, area_offset,
558 &number_of_data_bytes, product_fru_file_id) < 0)
559 goto cleanup;
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500560
Patrick Venturec9508db2018-10-16 17:18:43 -0700561 area_offset += 1; /* type/length byte */
562 area_offset += number_of_data_bytes;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500563
Patrick Venturec9508db2018-10-16 17:18:43 -0700564 while (area_offset < areabuflen &&
565 areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500566 {
Jayanth Othayoth883aa422024-12-18 10:33:06 -0600567 ipmi_fru_field_t* field_ptr = nullptr;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500568
Patrick Venturec9508db2018-10-16 17:18:43 -0700569 if (product_custom_fields && product_custom_fields_len)
Hariharasubramanian R44473092015-10-15 08:25:28 -0500570 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700571 if (custom_fields_index < product_custom_fields_len)
572 field_ptr = &product_custom_fields[custom_fields_index];
573 else
Hariharasubramanian R44473092015-10-15 08:25:28 -0500574 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700575 goto cleanup;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500576 }
577 }
578
Patrick Venturec9508db2018-10-16 17:18:43 -0700579 if (_parse_type_length(areabufptr, areabuflen, area_offset,
580 &number_of_data_bytes, field_ptr) < 0)
581 goto cleanup;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500582
Patrick Venturec9508db2018-10-16 17:18:43 -0700583 area_offset += 1; /* type/length byte */
584 area_offset += number_of_data_bytes;
585 custom_fields_index++;
Hariharasubramanian R44473092015-10-15 08:25:28 -0500586 }
587
Patrick Venturec9508db2018-10-16 17:18:43 -0700588out:
589 rv = 0;
590cleanup:
591 return (rv);
Hariharasubramanian R44473092015-10-15 08:25:28 -0500592}
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500593
Patrick Venturec9508db2018-10-16 17:18:43 -0700594void _append_to_dict(uint8_t vpd_key_id, uint8_t* vpd_key_val,
595 IPMIFruInfo& info)
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500596{
597 int type_length = vpd_key_val[0];
Deepak Kodihalli8a2a6752017-02-11 03:04:38 -0600598 int type_code = (type_length & IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK) >>
599 IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT;
Patrick Williamscfa96af2023-05-10 07:50:26 -0500600 int vpd_val_len = type_length &
601 IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK;
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500602
vishwa24afbb92016-06-10 06:08:56 -0500603 /* Needed to convert each uint8_t byte to a ascii */
604 char bin_byte[3] = {0};
605
606 /*
607 * Max number of characters needed to represent 1 unsigned byte in string
Gunnar Millsc19b8132018-06-14 08:56:17 -0500608 * is number of bytes multiplied by 2. Extra 3 for 0x and a ending '\0';
vishwa24afbb92016-06-10 06:08:56 -0500609 */
610 char bin_in_ascii_len = vpd_val_len * 2 + 3;
611
612 /* Binary converted to ascii in array */
Jayanth Othayoth3ed31cb2025-06-07 02:10:57 -0500613 char* bin_in_ascii = static_cast<char*>(malloc(bin_in_ascii_len));
vishwa24afbb92016-06-10 06:08:56 -0500614
615 /* For reading byte from the area */
Ratan Guptacb0d4e52016-12-22 19:05:57 +0530616 int val = 0;
vishwa24afbb92016-06-10 06:08:56 -0500617
Jayanth Othayoth3ed31cb2025-06-07 02:10:57 -0500618 char* bin_copy = &(static_cast<char*>(bin_in_ascii)[2]);
vishwa24afbb92016-06-10 06:08:56 -0500619
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500620 switch (type_code)
621 {
622 case 0:
vishwa24afbb92016-06-10 06:08:56 -0500623 memset(bin_in_ascii, 0x0, bin_in_ascii_len);
624
625 /* Offset 1 is where actual data starts */
Patrick Venturec9508db2018-10-16 17:18:43 -0700626 for (val = 1; val <= vpd_val_len; val++)
vishwa24afbb92016-06-10 06:08:56 -0500627 {
628 /* 2 bytes for data and 1 for terminating '\0' */
629 snprintf(bin_byte, 3, "%02x", vpd_key_val[val]);
630
Patrick Williams6f47bee2023-07-19 11:06:21 -0500631#pragma GCC diagnostic push
Jayanth Othayoth4abe0ee2024-12-18 10:13:38 -0600632#ifdef __clang__
633#pragma clang diagnostic ignored "-Wdeprecated-declarations"
634#else
Patrick Williams6f47bee2023-07-19 11:06:21 -0500635#pragma GCC diagnostic ignored "-Wstringop-truncation"
Jayanth Othayoth4abe0ee2024-12-18 10:13:38 -0600636#endif
vishwa24afbb92016-06-10 06:08:56 -0500637 /* Its a running string so strip off the '\0' */
638 strncat(bin_copy, bin_byte, 2);
Patrick Williams6f47bee2023-07-19 11:06:21 -0500639#pragma GCC diagnostic pop
vishwa24afbb92016-06-10 06:08:56 -0500640 }
641
642 /* We need the data represented as 0x...... */
Patrick Venturec9508db2018-10-16 17:18:43 -0700643 if (vpd_val_len > 0)
vishwa24afbb92016-06-10 06:08:56 -0500644 {
Brad Bishopec73c952018-11-21 16:04:13 -0500645 memcpy(bin_in_ascii, "0x", 2);
vishwa24afbb92016-06-10 06:08:56 -0500646 }
George Liu5b1725d2025-07-30 15:56:49 +0800647
648 lg2::debug(
649 "_append_to_dict: VPD Key = [{KEY}] : Type Code = [BINARY] : Len = [{LEN}] : Val = [{VAL}]",
650 "KEY", vpd_key_names[vpd_key_id], "LEN", vpd_val_len, "VAL",
651 bin_in_ascii);
652
Patrick Williamsa3cc2282024-08-16 15:20:14 -0400653 info[vpd_key_id] =
654 std::make_pair(vpd_key_names[vpd_key_id], bin_in_ascii);
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500655 break;
vishwa24afbb92016-06-10 06:08:56 -0500656
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500657 case 3:
George Liu5b1725d2025-07-30 15:56:49 +0800658 lg2::debug(
659 "_append_to_dict: VPD Key = [{KEY}] : Type Code = [ASCII+Latin] : Len = [{LEN}] : Val = [{VAL}]",
660 "KEY", vpd_key_names[vpd_key_id], "LEN", vpd_val_len, "VAL",
661 &vpd_key_val[1]);
Deepak Kodihalli8a2a6752017-02-11 03:04:38 -0600662 info[vpd_key_id] = std::make_pair(
Patrick Venturec9508db2018-10-16 17:18:43 -0700663 vpd_key_names[vpd_key_id],
664 std::string(vpd_key_val + 1, vpd_key_val + 1 + type_length));
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500665 break;
666 }
667
Patrick Venturec9508db2018-10-16 17:18:43 -0700668 if (bin_in_ascii)
vishwa24afbb92016-06-10 06:08:56 -0500669 {
670 free(bin_in_ascii);
Jayanth Othayoth883aa422024-12-18 10:33:06 -0600671 bin_in_ascii = nullptr;
vishwa24afbb92016-06-10 06:08:56 -0500672 }
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500673}
674
Patrick Venturec9508db2018-10-16 17:18:43 -0700675int parse_fru_area(const uint8_t area, const void* msgbuf, const size_t len,
676 IPMIFruInfo& info)
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500677{
Patrick Venturec9508db2018-10-16 17:18:43 -0700678 int rv = -1;
679 int i = 0;
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500680
Patrick Venturec9508db2018-10-16 17:18:43 -0700681 /* Chassis */
682 uint8_t chassis_type;
683 /* Board */
684 uint32_t mfg_date_time;
685 /* Product */
686 // unsigned int product_custom_fields_len;
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500687
Patrick Venturec9508db2018-10-16 17:18:43 -0700688 // ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ];
689 ipmi_fru_field_t vpd_info[OPENBMC_VPD_KEY_MAX];
690 char timestr[OPENBMC_VPD_VAL_LEN];
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500691
Patrick Venturec9508db2018-10-16 17:18:43 -0700692 // uint8_t* ipmi_fru_field_str=NULL;
693 // ipmi_fru_common_hdr_t* chdr = NULL;
694 // uint8_t* hdr = NULL;
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500695
Patrick Venturec9508db2018-10-16 17:18:43 -0700696 ASSERT(msgbuf);
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500697
Patrick Venturec9508db2018-10-16 17:18:43 -0700698 for (i = 0; i < OPENBMC_VPD_KEY_MAX; i++)
699 {
700 memset(vpd_info[i].type_length_field, '\0',
701 IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
702 vpd_info[i].type_length_field_length = 0;
703 }
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500704
Patrick Venturec9508db2018-10-16 17:18:43 -0700705 switch (area)
706 {
707 case IPMI_FRU_AREA_CHASSIS_INFO:
George Liu5b1725d2025-07-30 15:56:49 +0800708 lg2::debug("Chassis : Buf len = [{LEN}]", "LEN", len);
Patrick Venturec9508db2018-10-16 17:18:43 -0700709 ipmi_fru_chassis_info_area(
Jayanth Othayoth3ed31cb2025-06-07 02:10:57 -0500710 static_cast<const uint8_t*>(msgbuf) + 2, len, &chassis_type,
Patrick Venturec9508db2018-10-16 17:18:43 -0700711 &vpd_info[OPENBMC_VPD_KEY_CHASSIS_PART_NUM],
712 &vpd_info[OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM],
713 &vpd_info[OPENBMC_VPD_KEY_CHASSIS_CUSTOM1],
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500714 OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500715
Patrick Venturec9508db2018-10-16 17:18:43 -0700716 /* Populate VPD Table */
717 for (i = 1; i <= OPENBMC_VPD_KEY_CHASSIS_MAX; i++)
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500718 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700719 if (i == OPENBMC_VPD_KEY_CHASSIS_TYPE)
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500720 {
George Liu5b1725d2025-07-30 15:56:49 +0800721 lg2::debug("Chassis : Appending [{KEY}] = [{TYPE}]", "KEY",
722 vpd_key_names[i], "TYPE", chassis_type);
Ratan Guptacb0d4e52016-12-22 19:05:57 +0530723 info[i] = std::make_pair(vpd_key_names[i],
Patrick Venturec9508db2018-10-16 17:18:43 -0700724 std::to_string(chassis_type));
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500725 continue;
726 }
Patrick Venturec9508db2018-10-16 17:18:43 -0700727 _append_to_dict(i, vpd_info[i].type_length_field, info);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500728 }
729 break;
Patrick Venturec9508db2018-10-16 17:18:43 -0700730 case IPMI_FRU_AREA_BOARD_INFO:
George Liu5b1725d2025-07-30 15:56:49 +0800731 lg2::debug("Board : Buf len = [{LEN}]", "LEN", len);
Patrick Venturec9508db2018-10-16 17:18:43 -0700732 ipmi_fru_board_info_area(
Jayanth Othayoth3ed31cb2025-06-07 02:10:57 -0500733 static_cast<const uint8_t*>(msgbuf) + 2, len, nullptr,
734 &mfg_date_time, &vpd_info[OPENBMC_VPD_KEY_BOARD_MFR],
Patrick Venturec9508db2018-10-16 17:18:43 -0700735 &vpd_info[OPENBMC_VPD_KEY_BOARD_NAME],
736 &vpd_info[OPENBMC_VPD_KEY_BOARD_SERIAL_NUM],
737 &vpd_info[OPENBMC_VPD_KEY_BOARD_PART_NUM],
738 &vpd_info[OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID],
739 &vpd_info[OPENBMC_VPD_KEY_BOARD_CUSTOM1],
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500740 OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
741
Patrick Venturec9508db2018-10-16 17:18:43 -0700742 /* Populate VPD Table */
743 for (i = OPENBMC_VPD_KEY_BOARD_MFG_DATE;
744 i <= OPENBMC_VPD_KEY_BOARD_MAX; i++)
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500745 {
Patrick Venturec9508db2018-10-16 17:18:43 -0700746 if (i == OPENBMC_VPD_KEY_BOARD_MFG_DATE)
747 {
748 _to_time_str(mfg_date_time, timestr, OPENBMC_VPD_VAL_LEN);
George Liu5b1725d2025-07-30 15:56:49 +0800749 lg2::debug("Board : Appending [{KEY}] = [{VAL}]", "KEY",
750 vpd_key_names[i], "VAL", timestr);
Patrick Williamsa3cc2282024-08-16 15:20:14 -0400751 info[i] =
752 std::make_pair(vpd_key_names[i], std::string(timestr));
Patrick Venturec9508db2018-10-16 17:18:43 -0700753 continue;
754 }
755 _append_to_dict(i, vpd_info[i].type_length_field, info);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500756 }
757 break;
Patrick Venturec9508db2018-10-16 17:18:43 -0700758 case IPMI_FRU_AREA_PRODUCT_INFO:
George Liu5b1725d2025-07-30 15:56:49 +0800759 lg2::debug("Product : Buf len = [{LEN}]", "LEN", len);
Patrick Venturec9508db2018-10-16 17:18:43 -0700760 ipmi_fru_product_info_area(
Jayanth Othayoth3ed31cb2025-06-07 02:10:57 -0500761 static_cast<const uint8_t*>(msgbuf) + 2, len, nullptr,
Patrick Venturec9508db2018-10-16 17:18:43 -0700762 &vpd_info[OPENBMC_VPD_KEY_PRODUCT_MFR],
763 &vpd_info[OPENBMC_VPD_KEY_PRODUCT_NAME],
764 &vpd_info[OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM],
765 &vpd_info[OPENBMC_VPD_KEY_PRODUCT_VER],
766 &vpd_info[OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM],
767 &vpd_info[OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG],
768 &vpd_info[OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID],
769 &vpd_info[OPENBMC_VPD_KEY_PRODUCT_CUSTOM1],
770 OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
771
772 for (i = OPENBMC_VPD_KEY_PRODUCT_MFR;
773 i <= OPENBMC_VPD_KEY_PRODUCT_MAX; ++i)
774 {
775 _append_to_dict(i, vpd_info[i].type_length_field, info);
776 }
777 break;
778 default:
779 /* TODO: Parse Multi Rec / Internal use area */
780 break;
781 }
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500782
George Liu5b1725d2025-07-30 15:56:49 +0800783 lg2::debug("parse_fru_area : Dictionary Packing Complete");
Patrick Venturec9508db2018-10-16 17:18:43 -0700784 rv = 0;
785 return (rv);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500786}