Skip to content

Commit 457bffe

Browse files
Matsievskiy S.VSergey Matsievskiy
authored andcommitted
Apply review edits
1 parent 8a11d16 commit 457bffe

File tree

3 files changed

+259
-150
lines changed

3 files changed

+259
-150
lines changed

fru.c

Lines changed: 111 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,29 @@
3939

4040
static bool autodetect = true;
4141

42+
const char* enc_names[TOTAL_FIELD_TYPES] = {
43+
[FIELD_TYPE_AUTO] = "auto",
44+
[FIELD_TYPE_BINARY] = "binary",
45+
[FIELD_TYPE_BCDPLUS] = "bcdplus",
46+
[FIELD_TYPE_SIXBITASCII] = "6bitascii",
47+
[FIELD_TYPE_TEXT] = "text"
48+
};
49+
4250
void fru_set_autodetect(bool enable)
4351
{
4452
autodetect = enable;
4553
}
4654

47-
static time_t epoch_seconds_1996() {
55+
/**
56+
* Get the FRU date/time base in seconds since UNIX Epoch
57+
*
58+
* According to IPMI FRU Information Storage Definition v1.0, rev 1.3,
59+
* the date/time encoded as zero designates "0:00 hrs 1/1/96",
60+
* see Table 11-1 "BOARD INFO AREA"
61+
*
62+
* @returns The number of seconds from UNIX Epoch to the FRU date/time base
63+
*/
64+
static time_t fru_datetime_base() {
4865
struct tm tm_1996 = {
4966
.tm_year = 96,
5067
.tm_mon = 0,
@@ -230,13 +247,18 @@ static fru_field_t *fru_encode_6bit(const unsigned char *s /**< [in] Input strin
230247
}
231248

232249
/**
233-
* Decode a 6-bit ASCII string
250+
* @brief Decode a 6-bit ASCII string.
234251
*
235-
* Return false if there were errors during decoding and true otherwise.
252+
* @param[in] field Field to decode.
253+
* @param[out] out Buffer to decode into.
254+
* @param[in] out_len Length of output buffer.
255+
* @retval true Success.
256+
* @retval false Failure.
236257
*/
237-
static bool fru_decode_6bit(const fru_field_t *field,
238-
uint8_t *out, //< [out] buffer to decode into
239-
size_t out_len) //< [in] length of output buffer
258+
static
259+
bool fru_decode_6bit(const fru_field_t *field,
260+
uint8_t *out,
261+
size_t out_len)
240262
{
241263
const unsigned char *s6;
242264
int len, len6bit;
@@ -251,7 +273,6 @@ static bool fru_decode_6bit(const fru_field_t *field,
251273
if (out_len < (len + 1)) {
252274
return false;
253275
}
254-
DEBUG("Allocated a destination buffer at %p\n", out);
255276

256277
for(i = 0, i6 = 0; i6 <= len6bit && i < len && s6[i6]; i++) {
257278
int base = i / 4;
@@ -290,16 +311,23 @@ static bool fru_decode_6bit(const fru_field_t *field,
290311
}
291312

292313
/**
293-
* Decode BCDPLUS string
314+
* @brief Decode BCDPLUS string.
294315
*
295-
* Return false if there were errors during decoding and true otherwise.
316+
* @param[in] field Field to decode.
317+
* @param[out] out Buffer to decode into.
318+
* @param[in] out_len Length of output buffer.
319+
* @retval true Success.
320+
* @retval false Failure.
296321
*/
297-
static bool fru_decode_bcdplus(const fru_field_t *field,
298-
uint8_t *out, //< [out] buffer to decode into
299-
size_t out_len) //< [in] length of output buffer
322+
static
323+
bool fru_decode_bcdplus(const fru_field_t *field,
324+
uint8_t *out,
325+
size_t out_len)
300326
{
301327
int i;
302328
uint8_t c;
329+
if (out_len < 2 * FRU_FIELDDATALEN(field->typelen) + 1)
330+
return false;
303331
/* Copy the data and pack it as BCD */
304332
for (i = 0; i < 2 * FRU_FIELDDATALEN(field->typelen); i++) {
305333
c = (field->data[i / 2] >> ((i % 2) ? 0 : 4)) & 0x0F;
@@ -313,12 +341,20 @@ static bool fru_decode_bcdplus(const fru_field_t *field,
313341
case 0xC:
314342
out[i] = '.';
315343
break;
344+
case 0xD:
345+
out[i] = '?';
346+
break;
347+
case 0xE:
348+
out[i] = '?';
349+
break;
350+
case 0xF:
351+
out[i] = '?';
352+
break;
316353
default: // Digits
317354
out[i] = c + '0';
318355
}
319356
}
320357
out[2 * FRU_FIELDDATALEN(field->typelen)] = 0; // Terminate the string
321-
out_len = 2 * FRU_FIELDDATALEN(field->typelen) + 1;
322358
// Strip trailing spaces that may have emerged when a string of odd
323359
// length was BCD-encoded.
324360
cut_tail(out);
@@ -327,13 +363,18 @@ static bool fru_decode_bcdplus(const fru_field_t *field,
327363
}
328364

329365
/**
330-
* Get binary value string representation
366+
* @brief Get a hex string representation of the supplied binary field.
331367
*
332-
* Return false if there were errors during decoding and true otherwise.
368+
* @param[in] field Field to decode.
369+
* @param[out] out Buffer to decode into.
370+
* @param[in] out_len Length of output buffer.
371+
* @retval true Success.
372+
* @retval false Failure.
333373
*/
334-
static bool fru_decode_binary(const fru_field_t *field,
335-
uint8_t *out, //< [out] buffer to decode into
336-
size_t out_len) //< [in] length of output buffer
374+
static
375+
bool fru_decode_binary(const fru_field_t *field,
376+
uint8_t *out,
377+
size_t out_len)
337378
{
338379
int i;
339380
uint8_t c;
@@ -343,17 +384,23 @@ static bool fru_decode_binary(const fru_field_t *field,
343384

344385
for (i = 0; i < FRU_FIELDDATALEN(field->typelen); i++) {
345386
c = (field->data[i] & 0xf0) >> 4;
346-
out[2 * i] = c > 9? c + 97 - 10: c + 48;
387+
out[2 * i] = c > 9? c - 10 + 'A': c + '0';
347388
c = field->data[i] & 0xf;
348-
out[2 * i + 1] = c > 9? c + 97 - 10: c + 48;
389+
out[2 * i + 1] = c > 9? c - 10 + 'A': c + '0';
349390
}
350391
out[i * 2 + 1] = '0';
351392

352393
return true;
353394
}
354395

355396
/**
356-
* Allocate a buffer and encode that data as per FRU specification
397+
* @brief Allocate a buffer and encode that data as per FRU specification
398+
*
399+
* @param[in] len Buffer length.
400+
* @param[in] data Binary buffer.
401+
* @param[in] out_len Length of output buffer.
402+
* @retval NULL Failure.
403+
* @return Encoded field.
357404
*/
358405
fru_field_t * fru_encode_data(int len, const uint8_t *data)
359406
{
@@ -542,7 +589,7 @@ fru_info_area_t *fru_create_info_area(fru_area_type_t atype, ///< [in] Area t
542589
fru_time = FRU_DATE_UNSPECIFIED;
543590
} else {
544591
// FRU time is in minutes and we don't care about microseconds
545-
fru_time = (tv->tv_sec - epoch_seconds_1996()) / 60;
592+
fru_time = (tv->tv_sec - fru_datetime_base()) / 60;
546593
}
547594
header.mfgdate[0] = fru_time & 0xFF;
548595
header.mfgdate[1] = (fru_time >> 8) & 0xFF;
@@ -647,19 +694,23 @@ static bool fru_decode_custom_fields(const uint8_t *data, fru_reclist_t **reclis
647694
size_t length = FRU_FIELDDATALEN(field->typelen);
648695
custom_field->rec = calloc(1, FRU_FIELDMAXARRAY);
649696
custom_field->rec->typelen = field->typelen;
650-
if (FRU_ISTYPE(field->typelen, BINARY)) {
651-
fru_decode_binary(field, custom_field->rec->data, FRU_FIELDMAXLEN);
652-
} else {
653-
if (FRU_ISTYPE(field->typelen, ASCII_6BIT)) {
697+
switch (FRU_TYPE(field->typelen)) {
698+
case __TYPE_BINARY: {
699+
fru_decode_binary(field, custom_field->rec->data, FRU_FIELDMAXLEN);
700+
break;
701+
}
702+
case __TYPE_ASCII_6BIT: {
654703
fru_decode_6bit(field, custom_field->rec->data, FRU_FIELDMAXLEN);
655-
} else {
656-
if (FRU_ISTYPE(field->typelen, BCDPLUS)) {
657-
fru_decode_bcdplus(field, custom_field->rec->data, FRU_FIELDMAXLEN);
658-
} else {
659-
memcpy(custom_field->rec->data, field->data, length);
660-
custom_field->rec->data[length] = 0; // Terminate the string
661-
}
704+
break;
662705
}
706+
case __TYPE_BCDPLUS: {
707+
fru_decode_bcdplus(field, custom_field->rec->data, FRU_FIELDMAXLEN);
708+
break;
709+
}
710+
default:
711+
memcpy(custom_field->rec->data, field->data, length);
712+
custom_field->rec->data[length] = 0; // Terminate the string
713+
break;
663714
}
664715
data += length + 1;
665716
}
@@ -715,8 +766,8 @@ fru_chassis_area_t * fru_encode_chassis_info(const fru_exploded_chassis_t *chass
715766
}
716767

717768
bool fru_decode_chassis_info(
718-
const fru_chassis_area_t *area, //< [in] encoded chassis
719-
fru_exploded_chassis_t *chassis_out //< [out]
769+
const fru_chassis_area_t *area,
770+
fru_exploded_chassis_t *chassis_out
720771
)
721772
{
722773
chassis_out->type = area->langtype;
@@ -785,28 +836,27 @@ fru_board_area_t * fru_encode_board_info(const fru_exploded_board_t *board) ///<
785836
}
786837

787838
bool fru_decode_board_info(
788-
const fru_board_area_t *area, //< [in] encoded board
789-
fru_exploded_board_t *board_out //< [out]
839+
const fru_board_area_t *area,
840+
fru_exploded_board_t *board_out
790841
)
791842
{
792843
fru_field_t *field;
793844
const uint8_t *data = area->data;
794845

795846
board_out->lang = area->langtype;
796847

797-
// NOTE: host is not always small endian! //
798-
uint32_t min_since_1996_big_endian = 0;
799-
((uint8_t*)&min_since_1996_big_endian)[1] = area->mfgdate[2];
800-
((uint8_t*)&min_since_1996_big_endian)[2] = area->mfgdate[1];
801-
((uint8_t*)&min_since_1996_big_endian)[3] = area->mfgdate[0];
802-
uint32_t min_since_1996 = be32toh(min_since_1996_big_endian);
803-
struct tm tm_1996 = {
804-
.tm_year = 96,
805-
.tm_mon = 0,
806-
.tm_mday = 1
807-
};
848+
// NOTE: host is not always little endian! //
849+
union {
850+
uint32_t val;
851+
uint8_t arr[4];
852+
} min_since_1996_big_endian = {0};
853+
min_since_1996_big_endian.val = 0;
854+
min_since_1996_big_endian.arr[1] = area->mfgdate[2];
855+
min_since_1996_big_endian.arr[2] = area->mfgdate[1];
856+
min_since_1996_big_endian.arr[3] = area->mfgdate[0];
857+
uint32_t min_since_1996 = be32toh(min_since_1996_big_endian.val);
808858
// The argument to mktime is zoneless
809-
board_out->tv.tv_sec = epoch_seconds_1996() + 60 * min_since_1996;
859+
board_out->tv.tv_sec = fru_datetime_base() + 60 * min_since_1996;
810860

811861
field = (fru_field_t*)data;
812862
if (!fru_decode_data(field, &board_out->mfg,
@@ -1073,8 +1123,8 @@ fru_mr_area_t *fru_mr_area(fru_mr_reclist_t *reclist, size_t *total)
10731123
}
10741124

10751125
bool fru_decode_product_info(
1076-
const fru_product_area_t *area, //< [in] encoded product
1077-
fru_exploded_product_t *product_out //< [out]
1126+
const fru_product_area_t *area,
1127+
fru_exploded_product_t *product_out
10781128
)
10791129
{
10801130
fru_field_t *field;
@@ -1234,27 +1284,23 @@ fru_t *find_fru_header(uint8_t *buffer, size_t size) {
12341284
return header;
12351285
}
12361286

1237-
#define AREAS \
1238-
X(chassis) \
1239-
X(board) \
1240-
X(product)
1241-
#define X(AREA) \
1242-
fru_##AREA##_area_t *find_fru_##AREA##_area(uint8_t *buffer, size_t size) { \
1287+
#define AREA(NAME) \
1288+
fru_##NAME##_area_t *find_fru_##NAME##_area(uint8_t *buffer, size_t size) { \
12431289
fru_t *header = find_fru_header(buffer, size); \
1244-
if ((header == NULL) || (header->AREA == 0)) { \
1290+
if ((header == NULL) || (header->NAME == 0)) { \
12451291
return NULL; \
12461292
} \
1247-
if ((header->AREA + 3) > size) { \
1293+
if ((header->NAME + 3) > size) { \
12481294
errno = ENOBUFS; \
12491295
return NULL; \
12501296
} \
1251-
fru_##AREA##_area_t *area = \
1252-
(fru_##AREA##_area_t *)(buffer + FRU_BYTES(header->AREA)); \
1297+
fru_##NAME##_area_t *area = \
1298+
(fru_##NAME##_area_t *)(buffer + FRU_BYTES(header->NAME)); \
12531299
if (area->ver != 1) { \
12541300
errno = EPROTO; \
12551301
return NULL; \
12561302
} \
1257-
if (FRU_BYTES(header->AREA) + FRU_BYTES(area->blocks) > size) { \
1303+
if (FRU_BYTES(header->NAME) + FRU_BYTES(area->blocks) > size) { \
12581304
errno = ENOBUFS; \
12591305
return NULL; \
12601306
} \
@@ -1265,9 +1311,9 @@ fru_##AREA##_area_t *find_fru_##AREA##_area(uint8_t *buffer, size_t size) {
12651311
} \
12661312
return area; \
12671313
}
1268-
AREAS
1269-
#undef X
1270-
#undef AREAS
1314+
AREA(chassis);
1315+
AREA(board);
1316+
AREA(product);
12711317

12721318
#ifdef __STANDALONE__
12731319

0 commit comments

Comments
 (0)