Skip to content

Commit

Permalink
Apply review edits
Browse files Browse the repository at this point in the history
  • Loading branch information
Matsievskiy S.V committed Nov 29, 2022
1 parent 8a11d16 commit 8a1691d
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 137 deletions.
150 changes: 96 additions & 54 deletions fru.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,29 @@

static bool autodetect = true;

const char* enc_names[TOTAL_FIELD_TYPES] = {
[FIELD_TYPE_AUTO] = "auto",
[FIELD_TYPE_BINARY] = "binary",
[FIELD_TYPE_BCDPLUS] = "bcdplus",
[FIELD_TYPE_SIXBITASCII] = "sixbitascii",
[FIELD_TYPE_TEXT] = "text"
};

void fru_set_autodetect(bool enable)
{
autodetect = enable;
}

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

/**
* Decode a 6-bit ASCII string
* @brief Decode a 6-bit ASCII string.
*
* Return false if there were errors during decoding and true otherwise.
* @param[in] field Field to decode.
* @param[out] out Buffer to decode into.
* @param[in] out_len Length of output buffer.
* @retval true Success.
* @retval false Failure.
*/
static bool fru_decode_6bit(const fru_field_t *field,
uint8_t *out, //< [out] buffer to decode into
size_t out_len) //< [in] length of output buffer
static
bool fru_decode_6bit(const fru_field_t *field,
uint8_t *out,
size_t out_len)
{
const unsigned char *s6;
int len, len6bit;
Expand All @@ -251,7 +273,6 @@ static bool fru_decode_6bit(const fru_field_t *field,
if (out_len < (len + 1)) {
return false;
}
DEBUG("Allocated a destination buffer at %p\n", out);

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

/**
* Decode BCDPLUS string
* @brief Decode BCDPLUS string.
*
* Return false if there were errors during decoding and true otherwise.
* @param[in] field Field to decode.
* @param[out] out Buffer to decode into.
* @param[in] out_len Length of output buffer.
* @retval true Success.
* @retval false Failure.
*/
static bool fru_decode_bcdplus(const fru_field_t *field,
uint8_t *out, //< [out] buffer to decode into
size_t out_len) //< [in] length of output buffer
static
bool fru_decode_bcdplus(const fru_field_t *field,
uint8_t *out,
size_t out_len)
{
int i;
uint8_t c;
if (out_len < 2 * FRU_FIELDDATALEN(field->typelen) + 1)
return false;
/* Copy the data and pack it as BCD */
for (i = 0; i < 2 * FRU_FIELDDATALEN(field->typelen); i++) {
c = (field->data[i / 2] >> ((i % 2) ? 0 : 4)) & 0x0F;
Expand All @@ -313,12 +341,20 @@ static bool fru_decode_bcdplus(const fru_field_t *field,
case 0xC:
out[i] = '.';
break;
case 0xD:
out[i] = '?';
break;
case 0xE:
out[i] = '?';
break;
case 0xF:
out[i] = '?';
break;
default: // Digits
out[i] = c + '0';
}
}
out[2 * FRU_FIELDDATALEN(field->typelen)] = 0; // Terminate the string
out_len = 2 * FRU_FIELDDATALEN(field->typelen) + 1;
// Strip trailing spaces that may have emerged when a string of odd
// length was BCD-encoded.
cut_tail(out);
Expand All @@ -327,13 +363,18 @@ static bool fru_decode_bcdplus(const fru_field_t *field,
}

/**
* Get binary value string representation
* @brief Get a hex string representation of the supplied binary field.
*
* Return false if there were errors during decoding and true otherwise.
* @param[in] field Field to decode.
* @param[out] out Buffer to decode into.
* @param[in] out_len Length of output buffer.
* @retval true Success.
* @retval false Failure.
*/
static bool fru_decode_binary(const fru_field_t *field,
uint8_t *out, //< [out] buffer to decode into
size_t out_len) //< [in] length of output buffer
static
bool fru_decode_binary(const fru_field_t *field,
uint8_t *out,
size_t out_len)
{
int i;
uint8_t c;
Expand All @@ -343,17 +384,23 @@ static bool fru_decode_binary(const fru_field_t *field,

for (i = 0; i < FRU_FIELDDATALEN(field->typelen); i++) {
c = (field->data[i] & 0xf0) >> 4;
out[2 * i] = c > 9? c + 97 - 10: c + 48;
out[2 * i] = c > 9? c - 10 + 'A': c + '0';
c = field->data[i] & 0xf;
out[2 * i + 1] = c > 9? c + 97 - 10: c + 48;
out[2 * i + 1] = c > 9? c - 10 + 'A': c + '0';
}
out[i * 2 + 1] = '0';

return true;
}

/**
* Allocate a buffer and encode that data as per FRU specification
* @brief Allocate a buffer and encode that data as per FRU specification
*
* @param[in] len Buffer length.
* @param[in] data Binary buffer.
* @param[in] out_len Length of output buffer.
* @retval NULL Failure.
* @return Encoded field.
*/
fru_field_t * fru_encode_data(int len, const uint8_t *data)
{
Expand Down Expand Up @@ -542,7 +589,7 @@ fru_info_area_t *fru_create_info_area(fru_area_type_t atype, ///< [in] Area t
fru_time = FRU_DATE_UNSPECIFIED;
} else {
// FRU time is in minutes and we don't care about microseconds
fru_time = (tv->tv_sec - epoch_seconds_1996()) / 60;
fru_time = (tv->tv_sec - fru_datetime_base()) / 60;
}
header.mfgdate[0] = fru_time & 0xFF;
header.mfgdate[1] = (fru_time >> 8) & 0xFF;
Expand Down Expand Up @@ -715,8 +762,8 @@ fru_chassis_area_t * fru_encode_chassis_info(const fru_exploded_chassis_t *chass
}

bool fru_decode_chassis_info(
const fru_chassis_area_t *area, //< [in] encoded chassis
fru_exploded_chassis_t *chassis_out //< [out]
const fru_chassis_area_t *area,
fru_exploded_chassis_t *chassis_out
)
{
chassis_out->type = area->langtype;
Expand Down Expand Up @@ -785,28 +832,27 @@ fru_board_area_t * fru_encode_board_info(const fru_exploded_board_t *board) ///<
}

bool fru_decode_board_info(
const fru_board_area_t *area, //< [in] encoded board
fru_exploded_board_t *board_out //< [out]
const fru_board_area_t *area,
fru_exploded_board_t *board_out
)
{
fru_field_t *field;
const uint8_t *data = area->data;

board_out->lang = area->langtype;

// NOTE: host is not always small endian! //
uint32_t min_since_1996_big_endian = 0;
((uint8_t*)&min_since_1996_big_endian)[1] = area->mfgdate[2];
((uint8_t*)&min_since_1996_big_endian)[2] = area->mfgdate[1];
((uint8_t*)&min_since_1996_big_endian)[3] = area->mfgdate[0];
uint32_t min_since_1996 = be32toh(min_since_1996_big_endian);
struct tm tm_1996 = {
.tm_year = 96,
.tm_mon = 0,
.tm_mday = 1
};
// NOTE: host is not always little endian! //
union {
uint32_t val;
uint8_t arr[4];
} min_since_1996_big_endian;
min_since_1996_big_endian.val = 0;
min_since_1996_big_endian.arr[1] = area->mfgdate[2];
min_since_1996_big_endian.arr[2] = area->mfgdate[1];
min_since_1996_big_endian.arr[3] = area->mfgdate[0];
uint32_t min_since_1996 = be32toh(min_since_1996_big_endian.val);
// The argument to mktime is zoneless
board_out->tv.tv_sec = epoch_seconds_1996() + 60 * min_since_1996;
board_out->tv.tv_sec = fru_datetime_base() + 60 * min_since_1996;

field = (fru_field_t*)data;
if (!fru_decode_data(field, &board_out->mfg,
Expand Down Expand Up @@ -1073,8 +1119,8 @@ fru_mr_area_t *fru_mr_area(fru_mr_reclist_t *reclist, size_t *total)
}

bool fru_decode_product_info(
const fru_product_area_t *area, //< [in] encoded product
fru_exploded_product_t *product_out //< [out]
const fru_product_area_t *area,
fru_exploded_product_t *product_out
)
{
fru_field_t *field;
Expand Down Expand Up @@ -1234,27 +1280,23 @@ fru_t *find_fru_header(uint8_t *buffer, size_t size) {
return header;
}

#define AREAS \
X(chassis) \
X(board) \
X(product)
#define X(AREA) \
fru_##AREA##_area_t *find_fru_##AREA##_area(uint8_t *buffer, size_t size) { \
#define AREA(NAME) \
fru_##NAME##_area_t *find_fru_##NAME##_area(uint8_t *buffer, size_t size) { \
fru_t *header = find_fru_header(buffer, size); \
if ((header == NULL) || (header->AREA == 0)) { \
if ((header == NULL) || (header->NAME == 0)) { \
return NULL; \
} \
if ((header->AREA + 3) > size) { \
if ((header->NAME + 3) > size) { \
errno = ENOBUFS; \
return NULL; \
} \
fru_##AREA##_area_t *area = \
(fru_##AREA##_area_t *)(buffer + FRU_BYTES(header->AREA)); \
fru_##NAME##_area_t *area = \
(fru_##NAME##_area_t *)(buffer + FRU_BYTES(header->NAME)); \
if (area->ver != 1) { \
errno = EPROTO; \
return NULL; \
} \
if (FRU_BYTES(header->AREA) + FRU_BYTES(area->blocks) > size) { \
if (FRU_BYTES(header->NAME) + FRU_BYTES(area->blocks) > size) { \
errno = ENOBUFS; \
return NULL; \
} \
Expand All @@ -1265,9 +1307,9 @@ fru_##AREA##_area_t *find_fru_##AREA##_area(uint8_t *buffer, size_t size) {
} \
return area; \
}
AREAS
#undef X
#undef AREAS
AREA(chassis);
AREA(board);
AREA(product);

#ifdef __STANDALONE__

Expand Down
Loading

0 comments on commit 8a1691d

Please sign in to comment.