3939
4040static 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+
4250void 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 */
358405fru_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
717768bool 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
787838bool 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
10751125bool 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