All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH ipmi-fru-parser 00/11] Checking in the basic IPMI FRU Parser Library.
@ 2015-11-08  3:58 OpenBMC Patches
  2015-11-08  3:58 ` [PATCH ipmi-fru-parser 01/11] Checking in the basic IPMI FRU Parser Library. Parser has just enough intelligence to parse Chassis, Board & Product info areas. No support for multi-record in this version. This parser is a stripped down version of the parser in the FreeIPMI distribution OpenBMC Patches
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: OpenBMC Patches @ 2015-11-08  3:58 UTC (permalink / raw)
  To: openbmc

Parser has just enough intelligence to parse Chassis, Board & Product info areas. No support for multi-record in this version.
This parser is a stripped down version of the parser in the FreeIPMI distribution.

https://github.com/openbmc/ipmi-fru-parser/pull/2

Hariharasubramanian R (11):
  Checking in the basic IPMI FRU Parser Library.     Parser has just
    enough intelligence to parse Chassis, Board & Product info areas. No
    support for multi-record in this version.     This parser is a
    stripped down version of the parser in the FreeIPMI distribution.
  IPMI FRU Parser Interface.
  Added interface function to parse wirte fru data message into a
    dictionary.
  Format string change in sd_bus_message_append.
  Added interface parse_fru_area to parse a specific area and populate a
    name/value dictionary.
  Removing depency in Makefile on the systemd library.
  Internal parser functions expect the area buffer to point to location
    where     language code. Hence advance 2 bytes on the areabuf(to go
    past the fmt/version     and len fields) and pass it to the area
    specific parser routines.     Also fix bugs on offset/len
    calcuation.
  Fix format string in sd_bus_message_append to add as dictionary.    
    Store manufacturing time in ISO8601 format.
  Construct format string for sd_bus_message_append based on field type
    encoding.
  Merging IPMI FRU writer and parser.
  Include sdbus header in frup.c

 Makefile       |   30 ++
 frup.c         | 1093 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 frup.h         |   20 ++
 writefrudata.C |  564 +++++++++++++++++++++++++++++
 writefrudata.H |   53 +++
 5 files changed, 1760 insertions(+)
 create mode 100644 Makefile
 create mode 100644 frup.c
 create mode 100644 frup.h
 create mode 100644 writefrudata.C
 create mode 100644 writefrudata.H

-- 
2.6.3

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH ipmi-fru-parser 01/11] Checking in the basic IPMI FRU Parser Library. Parser has just enough intelligence to parse Chassis, Board & Product info areas. No support for multi-record in this version. This parser is a stripped down version of the parser in the FreeIPMI distribution.
  2015-11-08  3:58 [PATCH ipmi-fru-parser 00/11] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
@ 2015-11-08  3:58 ` OpenBMC Patches
  2015-11-08  3:58 ` [PATCH ipmi-fru-parser 02/11] IPMI FRU Parser Interface OpenBMC Patches
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: OpenBMC Patches @ 2015-11-08  3:58 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 Makefile |  19 ++
 frup.c   | 599 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 618 insertions(+)
 create mode 100644 Makefile
 create mode 100644 frup.c

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..cf75af3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+CXX ?= $(CROSS_COMPILE)g++
+
+IPMI_FRU_PARSER_LIB = libifp.so
+IPMI_FRU_PARSER_OBJS = frup.o
+
+INC_FLAGS += $(shell pkg-config --cflags --libs libsystemd) -I. -O2 --std=gnu++11
+LIB_FLAGS += $(shell pkg-config  --libs libsystemd) -rdynamic
+#IPMID_PATH ?= -DHOST_IPMI_LIB_PATH=\"/usr/lib/host-ipmid/\" 
+
+all: $(IPMI_FRU_PARSER_LIB)
+
+%.o: %.c
+	$(CXX) -fpic -c $< $(CXXFLAGS) $(INC_FLAG) $(IPMID_PATH) -o $@
+
+$(IPMI_FRU_PARSER_LIB): $(IPMI_FRU_PARSER_OBJS)
+	$(CXX) $^ -shared $(LDFLAGS) $(LIB_FLAGS) -o $@
+
+clean:
+	rm -f $(IPMI_FRU_PARSER_OBJS) $(IPMI_FRU_PARSER_LIB)
diff --git a/frup.c b/frup.c
new file mode 100644
index 0000000..d3471ff
--- /dev/null
+++ b/frup.c
@@ -0,0 +1,599 @@
+/*
+ * Copyright (C) 2003-2014 FreeIPMI Core Team
+ * 
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+/*****************************************************************************\
+ *  Copyright (C) 2007-2014 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Albert Chu <chu11@llnl.gov>
+ *  UCRL-CODE-232183
+ *
+ *  This file is part of Ipmi-fru, a tool used for retrieving
+ *  motherboard field replaceable unit (FRU) information. For details,
+ *  see http://www.llnl.gov/linux/.
+ *
+ *  Ipmi-fru 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 3 of the License, or (at your
+ *  option) any later version.
+ *
+ *  Ipmi-fru 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 Ipmi-fru.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+
+#define uint8_t unsigned char
+#define uint32_t unsigned int
+
+#define ASSERT(x) if(!(x)) return -1;
+
+
+#define IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX            512
+#define IPMI_FRU_SENTINEL_VALUE                        0xC1
+#define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK            0xC0
+#define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT           0x06
+#define IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK 0x3F
+#define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE   0x03
+
+
+struct ipmi_fru_field
+{
+  uint8_t type_length_field[IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX];
+  /* store length of data stored in buffer */
+  unsigned int type_length_field_length;
+};
+
+typedef struct ipmi_fru_field ipmi_fru_field_t;
+
+static int
+_parse_type_length (const void *areabuf,
+                    unsigned int areabuflen,
+                    unsigned int current_area_offset,
+                    uint8_t *number_of_data_bytes,
+                    ipmi_fru_field_t *field)
+{
+  const uint8_t *areabufptr = (const uint8_t*) areabuf;
+  uint8_t type_length;
+  uint8_t type_code;
+
+  ASSERT (areabuf);
+  ASSERT (areabuflen);
+  ASSERT (number_of_data_bytes);
+  
+  type_length = areabufptr[current_area_offset];
+
+  /* IPMI Workaround 
+   *
+   * Dell P weredge R610
+   *
+   * My reading of the FRU Spec is that all non-custom fields are
+   * required to be listed by the vendor.  However, on this
+   * motherboard, some areas list this, indicating that there is
+   * no more data to be parsed.  So now, for "required" fields, I
+   * check to see if the type-length field is a sentinel before
+   * calling this function.
+   */
+
+  ASSERT (type_length != IPMI_FRU_SENTINEL_VALUE);
+
+  type_code = (type_length & IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK) >> IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT;
+  (*number_of_data_bytes) = type_length & IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK;
+
+  /* Special Case: This shouldn't be a length of 0x01 (see type/length
+   * byte format in FRU Information Storage Definition).
+   */
+  if (type_code == IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE
+      && (*number_of_data_bytes) == 0x01)
+    {
+      return (-1);
+    }
+
+  if ((current_area_offset + 1 + (*number_of_data_bytes)) > areabuflen)
+    {
+      return (-1);
+    }
+
+  if (field)
+    {
+      memset (field->type_length_field,
+              '\0',
+              IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
+      memcpy (field->type_length_field,
+              &areabufptr[current_area_offset],
+              1 + (*number_of_data_bytes));
+      field->type_length_field_length = 1 + (*number_of_data_bytes);
+    }
+      
+  return (0);
+}
+                    
+int
+ipmi_fru_chassis_info_area (const void *areabuf,
+			    unsigned int areabuflen,
+			    uint8_t *chassis_type,
+			    ipmi_fru_field_t *chassis_part_number,
+			    ipmi_fru_field_t *chassis_serial_number,
+			    ipmi_fru_field_t *chassis_custom_fields,
+			    unsigned int chassis_custom_fields_len)
+{
+  const uint8_t *areabufptr = (const uint8_t*) areabuf;
+  unsigned int area_offset = 0;
+  unsigned int custom_fields_index = 0;
+  uint8_t number_of_data_bytes;
+  int rv = -1;
+
+  if (!areabuf || !areabuflen)
+    {
+      return (-1);
+    }
+
+  if (chassis_part_number)
+    memset (chassis_part_number,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (chassis_serial_number)
+    memset (chassis_serial_number,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (chassis_custom_fields && chassis_custom_fields_len)
+    memset (chassis_custom_fields,
+            '\0',
+            sizeof (ipmi_fru_field_t) * chassis_custom_fields_len);
+
+  if (chassis_type)
+    (*chassis_type) = areabufptr[area_offset];
+  area_offset++;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          chassis_part_number) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          chassis_serial_number) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  while (area_offset < areabuflen
+         && areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
+    {
+      ipmi_fru_field_t *field_ptr = NULL;
+
+      if (chassis_custom_fields && chassis_custom_fields_len)
+        {
+          if (custom_fields_index < chassis_custom_fields_len)
+            field_ptr = &chassis_custom_fields[custom_fields_index];
+          else
+            {
+              goto cleanup;
+            }
+        }
+
+      if (_parse_type_length (areabufptr,
+                              areabuflen,
+                              area_offset,
+                              &number_of_data_bytes,
+                              field_ptr) < 0)
+        goto cleanup;
+
+      area_offset += 1;          /* type/length byte */
+      area_offset += number_of_data_bytes;
+      custom_fields_index++;
+    }
+
+
+ out:
+  rv = 0;
+ cleanup:
+  return (rv);
+}
+
+int
+ipmi_fru_board_info_area (const void *areabuf,
+			  unsigned int areabuflen,
+			  uint8_t *language_code,
+			  uint32_t *mfg_date_time,
+			  ipmi_fru_field_t *board_manufacturer,
+			  ipmi_fru_field_t *board_product_name,
+			  ipmi_fru_field_t *board_serial_number,
+			  ipmi_fru_field_t *board_part_number,
+			  ipmi_fru_field_t *board_fru_file_id,
+			  ipmi_fru_field_t *board_custom_fields,
+			  unsigned int board_custom_fields_len)
+{
+  const uint8_t *areabufptr = (const uint8_t*) areabuf;
+  uint32_t mfg_date_time_tmp = 0;
+  unsigned int area_offset = 0;
+  unsigned int custom_fields_index = 0;
+  uint8_t number_of_data_bytes;
+  int rv = -1;
+
+  if (!areabuf || !areabuflen)
+    {
+      return (-1);
+    }
+
+  if (board_manufacturer)
+    memset (board_manufacturer,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (board_product_name)
+    memset (board_product_name,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (board_serial_number)
+    memset (board_serial_number,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (board_part_number)
+    memset (board_part_number,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (board_fru_file_id)
+    memset (board_fru_file_id,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (board_custom_fields && board_custom_fields_len)
+    memset (board_custom_fields,
+            '\0',
+            sizeof (ipmi_fru_field_t) * board_custom_fields_len);
+
+  if (language_code)
+    (*language_code) = areabufptr[area_offset];
+  area_offset++;
+
+  if (mfg_date_time)
+    {
+      struct tm tm;
+      time_t t;
+
+      /* mfg_date_time is little endian - see spec */
+      mfg_date_time_tmp |= areabufptr[area_offset];
+      area_offset++;
+      mfg_date_time_tmp |= (areabufptr[area_offset] << 8);
+      area_offset++;
+      mfg_date_time_tmp |= (areabufptr[area_offset] << 16);
+      area_offset++;
+      
+      /* mfg_date_time is in minutes, so multiple by 60 to get seconds */
+      mfg_date_time_tmp *= 60;
+
+      /* Posix says individual calls need not clear/set all portions of
+       * 'struct tm', thus passing 'struct tm' between functions could
+       * have issues.  So we need to memset.
+       */
+      memset (&tm, '\0', sizeof(struct tm));
+
+      /* In FRU, epoch is 0:00 hrs 1/1/96
+       *
+       * So convert into ansi epoch
+       */
+
+      tm.tm_year = 96;          /* years since 1900 */
+      tm.tm_mon = 0;            /* months since January */
+      tm.tm_mday = 1;           /* 1-31 */
+      tm.tm_hour = 0;
+      tm.tm_min = 0;
+      tm.tm_sec = 0;
+      tm.tm_isdst = -1;
+
+      if ((t = mktime (&tm)) == (time_t)-1)
+        {
+          goto cleanup;
+        }
+
+      mfg_date_time_tmp += (uint32_t)t;
+      (*mfg_date_time) = mfg_date_time_tmp;
+    }
+  else
+    area_offset += 3;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          board_manufacturer) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          board_product_name) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          board_serial_number) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (
+                          areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          board_part_number) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          board_fru_file_id) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  while (area_offset < areabuflen
+         && areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
+    {
+      ipmi_fru_field_t *field_ptr = NULL;
+
+      if (board_custom_fields && board_custom_fields_len)
+        {
+          if (custom_fields_index < board_custom_fields_len)
+            field_ptr = &board_custom_fields[custom_fields_index];
+          else
+            {
+              goto cleanup;
+            }
+        }
+
+      if (_parse_type_length (areabufptr,
+                              areabuflen,
+                              area_offset,
+                              &number_of_data_bytes,
+                              field_ptr) < 0)
+        goto cleanup;
+
+      area_offset += 1;          /* type/length byte */
+      area_offset += number_of_data_bytes;
+      custom_fields_index++;
+    }
+
+ out:
+  rv = 0;
+ cleanup:
+  return (rv);
+}
+
+int
+ipmi_fru_product_info_area (const void *areabuf,
+			    unsigned int areabuflen,
+			    uint8_t *language_code,
+			    ipmi_fru_field_t *product_manufacturer_name,
+			    ipmi_fru_field_t *product_name,
+			    ipmi_fru_field_t *product_part_model_number,
+			    ipmi_fru_field_t *product_version,
+			    ipmi_fru_field_t *product_serial_number,
+			    ipmi_fru_field_t *product_asset_tag,
+			    ipmi_fru_field_t *product_fru_file_id,
+			    ipmi_fru_field_t *product_custom_fields,
+			    unsigned int product_custom_fields_len)
+{
+  const uint8_t *areabufptr = (const uint8_t*) areabuf;
+  unsigned int area_offset = 0;
+  unsigned int custom_fields_index = 0;
+  uint8_t number_of_data_bytes;
+  int rv = -1;
+
+  if (!areabuf || !areabuflen)
+    {
+      return (-1);
+    }
+
+  if (product_manufacturer_name)
+    memset (product_manufacturer_name,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_name)
+    memset (product_name,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_part_model_number)
+    memset (product_part_model_number,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_version)
+    memset (product_version,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_serial_number)
+    memset (product_serial_number,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_asset_tag)
+    memset (product_asset_tag,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_fru_file_id)
+    memset (product_fru_file_id,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_custom_fields && product_custom_fields_len)
+    memset (product_custom_fields,
+            '\0',
+            sizeof (ipmi_fru_field_t) * product_custom_fields_len);
+
+  if (language_code)
+    (*language_code) = areabufptr[area_offset];
+  area_offset++;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_manufacturer_name) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_name) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_part_model_number) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_version) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_serial_number) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_asset_tag) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_fru_file_id) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  while (area_offset < areabuflen
+         && areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
+    {
+      ipmi_fru_field_t *field_ptr = NULL;
+
+      if (product_custom_fields && product_custom_fields_len)
+        {
+          if (custom_fields_index < product_custom_fields_len)
+            field_ptr = &product_custom_fields[custom_fields_index];
+          else
+            {
+              goto cleanup;
+            }
+        }
+
+      if (_parse_type_length (areabufptr,
+                              areabuflen,
+                              area_offset,
+                              &number_of_data_bytes,
+                              field_ptr) < 0)
+        goto cleanup;
+
+      area_offset += 1;          /* type/length byte */
+      area_offset += number_of_data_bytes;
+      custom_fields_index++;
+    }
+
+
+ out:
+  rv = 0;
+ cleanup:
+  return (rv);
+}
-- 
2.6.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH ipmi-fru-parser 02/11] IPMI FRU Parser Interface.
  2015-11-08  3:58 [PATCH ipmi-fru-parser 00/11] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
  2015-11-08  3:58 ` [PATCH ipmi-fru-parser 01/11] Checking in the basic IPMI FRU Parser Library. Parser has just enough intelligence to parse Chassis, Board & Product info areas. No support for multi-record in this version. This parser is a stripped down version of the parser in the FreeIPMI distribution OpenBMC Patches
@ 2015-11-08  3:58 ` OpenBMC Patches
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 03/11] Added interface function to parse wirte fru data message into a dictionary OpenBMC Patches
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: OpenBMC Patches @ 2015-11-08  3:58 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 frup.h | 7 +++++++
 1 file changed, 7 insertions(+)
 create mode 100644 frup.h

diff --git a/frup.h b/frup.h
new file mode 100644
index 0000000..2270470
--- /dev/null
+++ b/frup.h
@@ -0,0 +1,7 @@
+#ifndef OPENBMC_IPMI_FRU_PARSER_H
+#define OPENBMC_IPMI_FRU_PARSER_H
+
+/* Parse an IPMI write fru data message into a dictionary containing name value pair of VPD entries.*/
+int parse_fru (const void* msgbuf, sd_bus_message* vpdtbl);
+
+#endif
-- 
2.6.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH ipmi-fru-parser 03/11] Added interface function to parse wirte fru data message into a dictionary.
  2015-11-08  3:58 [PATCH ipmi-fru-parser 00/11] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
  2015-11-08  3:58 ` [PATCH ipmi-fru-parser 01/11] Checking in the basic IPMI FRU Parser Library. Parser has just enough intelligence to parse Chassis, Board & Product info areas. No support for multi-record in this version. This parser is a stripped down version of the parser in the FreeIPMI distribution OpenBMC Patches
  2015-11-08  3:58 ` [PATCH ipmi-fru-parser 02/11] IPMI FRU Parser Interface OpenBMC Patches
@ 2015-11-08  3:59 ` OpenBMC Patches
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 04/11] Format string change in sd_bus_message_append OpenBMC Patches
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: OpenBMC Patches @ 2015-11-08  3:59 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 frup.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 237 insertions(+), 13 deletions(-)

diff --git a/frup.c b/frup.c
index d3471ff..9711645 100644
--- a/frup.c
+++ b/frup.c
@@ -47,7 +47,19 @@
 #define uint8_t unsigned char
 #define uint32_t unsigned int
 
-#define ASSERT(x) if(!(x)) return -1;
+#define TEXTSTR(a) #a
+# define ASSERT(x) \
+do { \
+if (0 == (x)) { \
+fprintf(stderr, \
+"Assertion failed: %s, " \
+"%d at \'%s\'\n", \
+__FILE__, \
+__LINE__, \
+TEXTSTR(a)); \
+return -1; \
+} \
+} while (0)
 
 
 #define IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX            512
@@ -57,6 +69,20 @@
 #define IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK 0x3F
 #define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE   0x03
 
+/* OpenBMC defines for Parser */
+#define IPMI_FRU_AREA_TYPE_MAX                         0x05
+#define IPMI_FRU_AREA_INTERNAL_USE                     0x00
+#define IPMI_FRU_AREA_CHASSIS_INFO                     0x01
+#define IPMI_FRU_AREA_BOARD_INFO                       0x02
+#define IPMI_FRU_AREA_PRODUCT_INFO                     0x03
+#define IPMI_FRU_AREA_MULTI_RECORD                     0x04
+
+#define OPENBMC_VPD_KEY_LEN                            64
+#define OPENBMC_VPD_VAL_LEN                            512
+
+
+int sd_bus_message_append (void*, const char*, ...);
+typedef struct sd_bus_message sd_bus_message;
 
 struct ipmi_fru_field
 {
@@ -66,7 +92,91 @@ struct ipmi_fru_field
 };
 
 typedef struct ipmi_fru_field ipmi_fru_field_t;
+/* 
+ * FRU Parser 
+ */
+
+typedef struct ipmi_fru_area_info
+{
+    uint8_t off;
+    uint8_t len;
+} ipmi_fru_area_info_t;
+
+typedef struct ipmi_fru_common_hdr
+{
+    uint8_t fmtver;
+    uint8_t internal;
+    uint8_t chassis;
+    uint8_t board;
+    uint8_t product;
+    uint8_t multirec;
+} ipmi_fru_common_hdr_t;
+
+enum openbmc_vpd_key_id
+{
+  OPENBMC_VPD_KEY_CHASSIS_TYPE = 1, /* not a type/len */
+  OPENBMC_VPD_KEY_CHASSIS_PART_NUM,
+  OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,
+  /* TODO: chassis_custom_fields */
+
+  OPENBMC_VPD_KEY_BOARD_MFG_DATE, /* not a type/len */
+  OPENBMC_VPD_KEY_BOARD_MFR,
+  OPENBMC_VPD_KEY_BOARD_NAME,
+  OPENBMC_VPD_KEY_BOARD_SERIAL_NUM,
+  OPENBMC_VPD_KEY_BOARD_PART_NUM,
+  OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID,
+  /* TODO: board_custom_fields */
+
+  OPENBMC_VPD_KEY_PRODUCT_MFR,
+  OPENBMC_VPD_KEY_PRODUCT_NAME,
+  OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM,
+  OPENBMC_VPD_KEY_PRODUCT_VER,
+  OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM,
+  OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG,
+  OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID,
+  /* TODO: product_custom_fields */
+
+  OPENBMC_VPD_KEY_MAX,
+  
+};
+
+const char* vpd_key_names [] = 
+{
+  "Key Names Table Start", 
+  "Chassis Type", /*OPENBMC_VPD_KEY_CHASSIS_TYPE*/
+  "Chassis Part Number", /*OPENBMC_VPD_KEY_CHASSIS_PART_NUM,*/
+  "Chassis Serial Number", /*OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,*/
+
+  /* TODO: chassis_custom_fields */
+
+  "Board Mfg Date", /* OPENBMC_VPD_KEY_BOARD_MFG_DATE, */ /* not a type/len */
+  "Board Manufacturer", /* OPENBMC_VPD_KEY_BOARD_MFR, */
+  "Board Name", /* OPENBMC_VPD_KEY_BOARD_NAME, */
+  "Board Serial Number", /* OPENBMC_VPD_KEY_BOARD_SERIAL_NUM, */
+  "Board Part Number", /* OPENBMC_VPD_KEY_BOARD_PART_NUM, */
+  "Board FRU File ID", /* OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID, */
+  /* TODO: board_custom_fields */
+
+  "Product Manufacturer", /* OPENBMC_VPD_KEY_PRODUCT_MFR, */
+  "Product Name", /* OPENBMC_VPD_KEY_PRODUCT_NAME, */
+  "Product Model Number", /* OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM, */
+  "Product Version", /* OPENBMC_VPD_KEY_PRODUCT_VER, */
+  "Product Serial Number", /* OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM, */
+  "Product Asset Tag", /* OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG, */
+  "Product FRU File ID", /* OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID, */
+  /* TODO: product_custom_fields */
+
+  "Key Names Table End" /*OPENBMC_VPD_KEY_MAX,*/
+};
 
+
+/*
+ * --------------------------------------------------------------------
+ *
+ * --------------------------------------------------------------------
+ */
+
+/* private method to parse type/length */
 static int
 _parse_type_length (const void *areabuf,
                     unsigned int areabuflen,
@@ -84,14 +194,14 @@ _parse_type_length (const void *areabuf,
   
   type_length = areabufptr[current_area_offset];
 
-  /* IPMI Workaround 
+  /* ipmi workaround 
    *
-   * Dell P weredge R610
+   * dell p weredge r610
    *
-   * My reading of the FRU Spec is that all non-custom fields are
-   * required to be listed by the vendor.  However, on this
+   * my reading of the fru spec is that all non-custom fields are
+   * required to be listed by the vendor.  however, on this
    * motherboard, some areas list this, indicating that there is
-   * no more data to be parsed.  So now, for "required" fields, I
+   * no more data to be parsed.  so now, for "required" fields, i
    * check to see if the type-length field is a sentinel before
    * calling this function.
    */
@@ -101,8 +211,8 @@ _parse_type_length (const void *areabuf,
   type_code = (type_length & IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK) >> IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT;
   (*number_of_data_bytes) = type_length & IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK;
 
-  /* Special Case: This shouldn't be a length of 0x01 (see type/length
-   * byte format in FRU Information Storage Definition).
+  /* special case: this shouldn't be a length of 0x01 (see type/length
+   * byte format in fru information storage definition).
    */
   if (type_code == IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE
       && (*number_of_data_bytes) == 0x01)
@@ -294,19 +404,19 @@ ipmi_fru_board_info_area (const void *areabuf,
       /* mfg_date_time is in minutes, so multiple by 60 to get seconds */
       mfg_date_time_tmp *= 60;
 
-      /* Posix says individual calls need not clear/set all portions of
+      /* posix says individual calls need not clear/set all portions of
        * 'struct tm', thus passing 'struct tm' between functions could
-       * have issues.  So we need to memset.
+       * have issues.  so we need to memset.
        */
       memset (&tm, '\0', sizeof(struct tm));
 
-      /* In FRU, epoch is 0:00 hrs 1/1/96
+      /* in fru, epoch is 0:00 hrs 1/1/96
        *
-       * So convert into ansi epoch
+       * so convert into ansi epoch
        */
 
       tm.tm_year = 96;          /* years since 1900 */
-      tm.tm_mon = 0;            /* months since January */
+      tm.tm_mon = 0;            /* months since january */
       tm.tm_mday = 1;           /* 1-31 */
       tm.tm_hour = 0;
       tm.tm_min = 0;
@@ -597,3 +707,117 @@ ipmi_fru_product_info_area (const void *areabuf,
  cleanup:
   return (rv);
 }
+
+
+int
+parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
+{
+  int ret = 0;
+  int rv = -1;
+  int i = 0;
+  ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ];
+  ipmi_fru_common_hdr_t* chdr = NULL;
+  uint8_t* hdr = NULL;
+
+
+  ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
+
+  /* Chassis */
+  uint8_t chassis_type;
+
+  /* Board */
+  uint32_t mfg_date_time;
+
+  /* Product */
+  unsigned int product_custom_fields_len;
+
+  ASSERT (msgbuf);
+  ASSERT (vpdtbl);
+
+  chdr = (ipmi_fru_common_hdr_t*) msgbuf;
+  hdr  = (uint8_t*) msgbuf;
+
+  fru_area_info [ IPMI_FRU_AREA_INTERNAL_USE ].off = chdr->internal;
+  fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].off = chdr->chassis;
+  fru_area_info [ IPMI_FRU_AREA_BOARD_INFO   ].off = chdr->board;
+  fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].off = chdr->product;
+  fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].off = chdr->multirec;
+
+  if (chdr->internal)
+  {
+    fru_area_info [ IPMI_FRU_AREA_INTERNAL_USE ].len = 8*(*(hdr+chdr->internal+1));
+    
+    /* TODO: Parse internal use area */
+  }
+
+  if (chdr->chassis)
+  {
+    fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].len = 8*(*(hdr+chdr->chassis+1));
+    ipmi_fru_chassis_info_area (hdr+chdr->chassis,
+        fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].len,
+        &chassis_type,
+        &vpd_info [OPENBMC_VPD_KEY_CHASSIS_PART_NUM],
+        &vpd_info [OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM],
+        NULL, 0);
+  }
+    
+  if (chdr->board)
+  {
+    fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].len = 8*(*(hdr+chdr->board+1));
+    ipmi_fru_board_info_area (hdr+chdr->board, 
+        fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].len,
+        NULL,
+        &mfg_date_time,
+        &vpd_info [OPENBMC_VPD_KEY_BOARD_MFR],
+        &vpd_info [OPENBMC_VPD_KEY_BOARD_NAME],
+        &vpd_info [OPENBMC_VPD_KEY_BOARD_SERIAL_NUM],
+        &vpd_info [OPENBMC_VPD_KEY_BOARD_PART_NUM],
+        &vpd_info [OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID],
+        NULL, 0);
+  }
+
+  if (chdr->product)
+  {
+    fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].len = 8*(*(hdr+chdr->product+1));
+    ipmi_fru_product_info_area (hdr+chdr->product, 
+        fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].len,
+        NULL,
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_MFR],
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_NAME],
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM],
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_VER],
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM],
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG],
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID],
+        NULL, 0);
+  }
+
+  if (chdr->multirec)
+  {
+    fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].len = 8*(*(hdr+chdr->multirec+1));
+    /* TODO: Parse multi record area */
+  }
+
+  /* Populate VPD Table */
+  for (i=1; i<OPENBMC_VPD_KEY_MAX; i++)
+  {
+    if (i==OPENBMC_VPD_KEY_CHASSIS_TYPE)
+    {
+        sd_bus_message_append (vpdtbl, "sd", vpd_key_names[i], chassis_type);
+        continue;
+    }
+
+    if (i==OPENBMC_VPD_KEY_BOARD_MFG_DATE)
+    {
+        sd_bus_message_append (vpdtbl, "sd", vpd_key_names[i], mfg_date_time);
+        continue;
+    }
+    
+    sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], vpd_info [i].type_length_field); 
+  }
+
+ out:
+  rv = 0;
+ cleanup:
+  return (rv);
+}
-- 
2.6.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH ipmi-fru-parser 04/11] Format string change in sd_bus_message_append.
  2015-11-08  3:58 [PATCH ipmi-fru-parser 00/11] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
                   ` (2 preceding siblings ...)
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 03/11] Added interface function to parse wirte fru data message into a dictionary OpenBMC Patches
@ 2015-11-08  3:59 ` OpenBMC Patches
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 05/11] Added interface parse_fru_area to parse a specific area and populate a name/value dictionary OpenBMC Patches
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: OpenBMC Patches @ 2015-11-08  3:59 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 frup.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/frup.c b/frup.c
index 9711645..ab58426 100644
--- a/frup.c
+++ b/frup.c
@@ -803,13 +803,13 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
   {
     if (i==OPENBMC_VPD_KEY_CHASSIS_TYPE)
     {
-        sd_bus_message_append (vpdtbl, "sd", vpd_key_names[i], chassis_type);
+        sd_bus_message_append (vpdtbl, "sy", vpd_key_names[i], chassis_type);
         continue;
     }
 
     if (i==OPENBMC_VPD_KEY_BOARD_MFG_DATE)
     {
-        sd_bus_message_append (vpdtbl, "sd", vpd_key_names[i], mfg_date_time);
+        sd_bus_message_append (vpdtbl, "sa{y}", vpd_key_names[i], mfg_date_time);
         continue;
     }
     
-- 
2.6.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH ipmi-fru-parser 05/11] Added interface parse_fru_area to parse a specific area and populate a name/value dictionary.
  2015-11-08  3:58 [PATCH ipmi-fru-parser 00/11] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
                   ` (3 preceding siblings ...)
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 04/11] Format string change in sd_bus_message_append OpenBMC Patches
@ 2015-11-08  3:59 ` OpenBMC Patches
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 06/11] Removing depency in Makefile on the systemd library OpenBMC Patches
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: OpenBMC Patches @ 2015-11-08  3:59 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 frup.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 frup.h |  11 +++++++
 2 files changed, 119 insertions(+)

diff --git a/frup.c b/frup.c
index ab58426..d279666 100644
--- a/frup.c
+++ b/frup.c
@@ -117,6 +117,7 @@ enum openbmc_vpd_key_id
   OPENBMC_VPD_KEY_CHASSIS_TYPE = 1, /* not a type/len */
   OPENBMC_VPD_KEY_CHASSIS_PART_NUM,
   OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,
+  OPENBMC_VPD_KEY_CHASSIS_MAX = OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,
   /* TODO: chassis_custom_fields */
 
   OPENBMC_VPD_KEY_BOARD_MFG_DATE, /* not a type/len */
@@ -125,6 +126,7 @@ enum openbmc_vpd_key_id
   OPENBMC_VPD_KEY_BOARD_SERIAL_NUM,
   OPENBMC_VPD_KEY_BOARD_PART_NUM,
   OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID,
+  OPENBMC_VPD_KEY_BOARD_MAX = OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID,
   /* TODO: board_custom_fields */
 
   OPENBMC_VPD_KEY_PRODUCT_MFR,
@@ -134,6 +136,7 @@ enum openbmc_vpd_key_id
   OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM,
   OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG,
   OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID,
+  OPENBMC_VPD_KEY_PRODUCT_MAX = OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID,
   /* TODO: product_custom_fields */
 
   OPENBMC_VPD_KEY_MAX,
@@ -821,3 +824,108 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
  cleanup:
   return (rv);
 }
+
+int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, sd_bus_message* vpdtbl)
+{
+  int ret = 0;
+  int rv = -1;
+  int i = 0;
+  ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ];
+  ipmi_fru_common_hdr_t* chdr = NULL;
+  uint8_t* hdr = NULL;
+
+
+  ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
+
+  /* Chassis */
+  uint8_t chassis_type;
+
+  /* Board */
+  uint32_t mfg_date_time;
+
+  /* Product */
+  unsigned int product_custom_fields_len;
+
+  ASSERT (msgbuf);
+  ASSERT (vpdtbl);
+
+  chdr = (ipmi_fru_common_hdr_t*) msgbuf;
+  hdr  = (uint8_t*) msgbuf;
+
+  fru_area_info [ IPMI_FRU_AREA_INTERNAL_USE ].off = chdr->internal;
+  fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].off = chdr->chassis;
+  fru_area_info [ IPMI_FRU_AREA_BOARD_INFO   ].off = chdr->board;
+  fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].off = chdr->product;
+  fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].off = chdr->multirec;
+
+  switch (area)
+  {
+    case IPMI_FRU_AREA_CHASSIS_INFO:
+        ipmi_fru_chassis_info_area (msgbuf,
+            len,
+            &chassis_type,
+            &vpd_info [OPENBMC_VPD_KEY_CHASSIS_PART_NUM],
+            &vpd_info [OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM],
+            NULL, 0);
+
+          /* Populate VPD Table */
+          for (i=1; i<=OPENBMC_VPD_KEY_CHASSIS_MAX; i++)
+          {
+            if (i==OPENBMC_VPD_KEY_CHASSIS_TYPE)
+            {
+                sd_bus_message_append (vpdtbl, "sy", vpd_key_names[i], chassis_type);
+                continue;
+            }
+            sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], vpd_info [i].type_length_field); 
+          }
+        break;
+    case IPMI_FRU_AREA_BOARD_INFO:
+            ipmi_fru_board_info_area (msgbuf, 
+                len,
+                NULL,
+                &mfg_date_time,
+                &vpd_info [OPENBMC_VPD_KEY_BOARD_MFR],
+                &vpd_info [OPENBMC_VPD_KEY_BOARD_NAME],
+                &vpd_info [OPENBMC_VPD_KEY_BOARD_SERIAL_NUM],
+                &vpd_info [OPENBMC_VPD_KEY_BOARD_PART_NUM],
+                &vpd_info [OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID],
+                NULL, 0);
+
+          /* Populate VPD Table */
+            for (i=OPENBMC_VPD_KEY_BOARD_MFR; i<=OPENBMC_VPD_KEY_BOARD_MAX; i++)
+            {
+                if (i==OPENBMC_VPD_KEY_BOARD_MFG_DATE)
+                {
+                    sd_bus_message_append (vpdtbl, "sa{y}", vpd_key_names[i], mfg_date_time);
+                    continue;
+                }
+                sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], vpd_info [i].type_length_field); 
+            }
+            break;
+    case IPMI_FRU_AREA_PRODUCT_INFO:
+            ipmi_fru_product_info_area (msgbuf,
+                len,
+                NULL,
+                &vpd_info [OPENBMC_VPD_KEY_PRODUCT_MFR],
+                &vpd_info [OPENBMC_VPD_KEY_PRODUCT_NAME],
+                &vpd_info [OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM],
+                &vpd_info [OPENBMC_VPD_KEY_PRODUCT_VER],
+                &vpd_info [OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM],
+                &vpd_info [OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG],
+                &vpd_info [OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID],
+                NULL, 0);
+            for (i=OPENBMC_VPD_KEY_PRODUCT_MFR; i<=OPENBMC_VPD_KEY_PRODUCT_MAX; i++)
+            {
+                sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], vpd_info [i].type_length_field); 
+            }
+            break;
+    defualt:
+    /* TODO: Parse Multi Rec / Internal use area */
+    break;
+  }
+
+ out:
+  rv = 0;
+ cleanup:
+  return (rv);
+}
diff --git a/frup.h b/frup.h
index 2270470..b6b9476 100644
--- a/frup.h
+++ b/frup.h
@@ -3,5 +3,16 @@
 
 /* Parse an IPMI write fru data message into a dictionary containing name value pair of VPD entries.*/
 int parse_fru (const void* msgbuf, sd_bus_message* vpdtbl);
+int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, sd_bus_message* vpdtbl);
+
+enum openbmc_ipmi_fru_area_type
+{
+    IPMI_FRU_AREA_INTERNAL_USE = 0x00,
+    IPMI_FRU_AREA_CHASSIS_INFO,
+    IPMI_FRU_AREA_BOARD_INFO,
+    IPMI_FRU_AREA_PRODUCT_INFO,
+    IPMI_FRU_AREA_MULTI_RECORD,
+    IPMI_FRU_AREA_TYPE_MAX
+}
 
 #endif
-- 
2.6.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH ipmi-fru-parser 06/11] Removing depency in Makefile on the systemd library.
  2015-11-08  3:58 [PATCH ipmi-fru-parser 00/11] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
                   ` (4 preceding siblings ...)
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 05/11] Added interface parse_fru_area to parse a specific area and populate a name/value dictionary OpenBMC Patches
@ 2015-11-08  3:59 ` OpenBMC Patches
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 07/11] Internal parser functions expect the area buffer to point to location where language code. Hence advance 2 bytes on the areabuf(to go past the fmt/version and len fields) and pass it to the area specific parser routines. Also fix bugs on offset/len calcuation OpenBMC Patches
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: OpenBMC Patches @ 2015-11-08  3:59 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 Makefile | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index cf75af3..bcb3648 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,8 @@ IPMI_FRU_PARSER_LIB = libifp.so
 IPMI_FRU_PARSER_OBJS = frup.o
 
 INC_FLAGS += $(shell pkg-config --cflags --libs libsystemd) -I. -O2 --std=gnu++11
-LIB_FLAGS += $(shell pkg-config  --libs libsystemd) -rdynamic
+#LIB_FLAGS += $(shell pkg-config  --libs libsystemd) -rdynamic
+LIB_FLAGS += -rdynamic
 #IPMID_PATH ?= -DHOST_IPMI_LIB_PATH=\"/usr/lib/host-ipmid/\" 
 
 all: $(IPMI_FRU_PARSER_LIB)
-- 
2.6.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH ipmi-fru-parser 07/11] Internal parser functions expect the area buffer to point to location where language code. Hence advance 2 bytes on the areabuf(to go past the fmt/version and len fields) and pass it to the area specific parser routines. Also fix bugs on offset/len calcuation.
  2015-11-08  3:58 [PATCH ipmi-fru-parser 00/11] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
                   ` (5 preceding siblings ...)
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 06/11] Removing depency in Makefile on the systemd library OpenBMC Patches
@ 2015-11-08  3:59 ` OpenBMC Patches
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 08/11] Fix format string in sd_bus_message_append to add as dictionary. Store manufacturing time in ISO8601 format OpenBMC Patches
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: OpenBMC Patches @ 2015-11-08  3:59 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 frup.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 94 insertions(+), 27 deletions(-)

diff --git a/frup.c b/frup.c
index d279666..87669f8 100644
--- a/frup.c
+++ b/frup.c
@@ -44,6 +44,7 @@
 #include <string.h>
 #include <time.h>
 
+#define IPMI_FRU_PARSER_DEBUG 1
 #define uint8_t unsigned char
 #define uint32_t unsigned int
 
@@ -61,7 +62,6 @@ return -1; \
 } \
 } while (0)
 
-
 #define IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX            512
 #define IPMI_FRU_SENTINEL_VALUE                        0xC1
 #define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK            0xC0
@@ -70,12 +70,12 @@ return -1; \
 #define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE   0x03
 
 /* OpenBMC defines for Parser */
-#define IPMI_FRU_AREA_TYPE_MAX                         0x05
 #define IPMI_FRU_AREA_INTERNAL_USE                     0x00
 #define IPMI_FRU_AREA_CHASSIS_INFO                     0x01
 #define IPMI_FRU_AREA_BOARD_INFO                       0x02
 #define IPMI_FRU_AREA_PRODUCT_INFO                     0x03
 #define IPMI_FRU_AREA_MULTI_RECORD                     0x04
+#define IPMI_FRU_AREA_TYPE_MAX                         0x05
 
 #define OPENBMC_VPD_KEY_LEN                            64
 #define OPENBMC_VPD_VAL_LEN                            512
@@ -110,7 +110,7 @@ typedef struct ipmi_fru_common_hdr
     uint8_t board;
     uint8_t product;
     uint8_t multirec;
-} ipmi_fru_common_hdr_t;
+} __attribute__((packed)) ipmi_fru_common_hdr_t;
 
 enum openbmc_vpd_key_id
 {
@@ -178,7 +178,6 @@ const char* vpd_key_names [] =
  *
  * --------------------------------------------------------------------
  */
-
 /* private method to parse type/length */
 static int
 _parse_type_length (const void *areabuf,
@@ -476,8 +475,7 @@ ipmi_fru_board_info_area (const void *areabuf,
   if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
     goto out;
 
-  if (_parse_type_length (
-                          areabufptr,
+  if (_parse_type_length (areabufptr,
                           areabuflen,
                           area_offset,
                           &number_of_data_bytes,
@@ -724,6 +722,9 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
 
 
   ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
+  /*char ipmi_fru_field_str [ IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX ];
+  uint32_t len=0;*/
+  const uint8_t* ipmi_fru_field_str;
 
   /* Chassis */
   uint8_t chassis_type;
@@ -737,6 +738,18 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
   ASSERT (msgbuf);
   ASSERT (vpdtbl);
 
+  for (i=0; i<OPENBMC_VPD_KEY_MAX; i++)
+  {
+    memset (vpd_info[i].type_length_field, '\0', IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
+    vpd_info[i].type_length_field_length = 0;
+  }
+
+  for (i=0; i<IPMI_FRU_AREA_TYPE_MAX; i++)
+  {
+    fru_area_info [ i ].off = 0;
+    fru_area_info [ i ].len = 0;
+  }
+
   chdr = (ipmi_fru_common_hdr_t*) msgbuf;
   hdr  = (uint8_t*) msgbuf;
 
@@ -748,15 +761,15 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
 
   if (chdr->internal)
   {
-    fru_area_info [ IPMI_FRU_AREA_INTERNAL_USE ].len = 8*(*(hdr+chdr->internal+1));
+    fru_area_info [ IPMI_FRU_AREA_INTERNAL_USE ].len =  8*(*(hdr+8*chdr->internal+1));
     
     /* TODO: Parse internal use area */
   }
 
   if (chdr->chassis)
   {
-    fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].len = 8*(*(hdr+chdr->chassis+1));
-    ipmi_fru_chassis_info_area (hdr+chdr->chassis,
+    fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].len = 8*(*(hdr+8*chdr->chassis+1));
+    ipmi_fru_chassis_info_area (hdr+8*chdr->chassis+2,
         fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].len,
         &chassis_type,
         &vpd_info [OPENBMC_VPD_KEY_CHASSIS_PART_NUM],
@@ -766,8 +779,8 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
     
   if (chdr->board)
   {
-    fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].len = 8*(*(hdr+chdr->board+1));
-    ipmi_fru_board_info_area (hdr+chdr->board, 
+    fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].len = 8*(*(hdr+8*chdr->board+1));
+    ipmi_fru_board_info_area (hdr+8*chdr->board+2,
         fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].len,
         NULL,
         &mfg_date_time,
@@ -781,8 +794,8 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
 
   if (chdr->product)
   {
-    fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].len = 8*(*(hdr+chdr->product+1));
-    ipmi_fru_product_info_area (hdr+chdr->product, 
+    fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].len = 8*(*(hdr+8*chdr->product+1));
+    ipmi_fru_product_info_area (hdr+8*chdr->product+2,
         fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].len,
         NULL,
         &vpd_info [OPENBMC_VPD_KEY_PRODUCT_MFR],
@@ -797,26 +810,55 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
 
   if (chdr->multirec)
   {
-    fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].len = 8*(*(hdr+chdr->multirec+1));
+    fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].len = 8*(*(hdr+8*chdr->multirec+1));
     /* TODO: Parse multi record area */
   }
 
+  for (i=0; i<IPMI_FRU_AREA_TYPE_MAX; i++)
+  {
+#if IPMI_FRU_PARSER_DEBUG
+    printf ("IPMI_FRU_AREA_TYPE=[%d] : Offset=[%d] : Len=[%d]\n", i, fru_area_info [i].off, fru_area_info[i].len);
+#else
+;
+#endif
+  }
+
   /* Populate VPD Table */
   for (i=1; i<OPENBMC_VPD_KEY_MAX; i++)
   {
     if (i==OPENBMC_VPD_KEY_CHASSIS_TYPE)
     {
         sd_bus_message_append (vpdtbl, "sy", vpd_key_names[i], chassis_type);
+#if IPMI_FRU_PARSER_DEBUG
+        printf ("[%s] = [%d]\n", vpd_key_names[i], chassis_type);
+#else
+;
+#endif
         continue;
     }
 
     if (i==OPENBMC_VPD_KEY_BOARD_MFG_DATE)
     {
         sd_bus_message_append (vpdtbl, "sa{y}", vpd_key_names[i], mfg_date_time);
+#if IPMI_FRU_PARSER_DEBUG
+        printf ("[%s] = [%d]\n", vpd_key_names[i], mfg_date_time);
+#else
+;
+#endif
         continue;
     }
     
-    sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], vpd_info [i].type_length_field); 
+    /* FIXME: Field type encoding *ASSUMED* to be *BINARY* */
+    ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
+    sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], ipmi_fru_field_str); 
+    if (vpd_info[i].type_length_field_length)
+    {
+#if IPMI_FRU_PARSER_DEBUG
+        printf ("[%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
+#else
+;
+#endif
+    }
   }
 
  out:
@@ -833,9 +875,15 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
   ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ];
   ipmi_fru_common_hdr_t* chdr = NULL;
   uint8_t* hdr = NULL;
+  const uint8_t* ipmi_fru_field_str=NULL;
 
 
   ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
+  for (i=0; i<OPENBMC_VPD_KEY_MAX; i++)
+  {
+    memset (vpd_info[i].type_length_field, '\0', IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
+    vpd_info[i].type_length_field_length = 0;
+  }
 
   /* Chassis */
   uint8_t chassis_type;
@@ -849,15 +897,6 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
   ASSERT (msgbuf);
   ASSERT (vpdtbl);
 
-  chdr = (ipmi_fru_common_hdr_t*) msgbuf;
-  hdr  = (uint8_t*) msgbuf;
-
-  fru_area_info [ IPMI_FRU_AREA_INTERNAL_USE ].off = chdr->internal;
-  fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].off = chdr->chassis;
-  fru_area_info [ IPMI_FRU_AREA_BOARD_INFO   ].off = chdr->board;
-  fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].off = chdr->product;
-  fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].off = chdr->multirec;
-
   switch (area)
   {
     case IPMI_FRU_AREA_CHASSIS_INFO:
@@ -874,9 +913,20 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
             if (i==OPENBMC_VPD_KEY_CHASSIS_TYPE)
             {
                 sd_bus_message_append (vpdtbl, "sy", vpd_key_names[i], chassis_type);
+#if IPMI_FRU_PARSER_DEBUG
+                printf ("Chassis : [%s] = [%d]\n", vpd_key_names[i], chassis_type);
+#else
+;
+#endif
                 continue;
             }
-            sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], vpd_info [i].type_length_field); 
+            ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
+            sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], ipmi_fru_field_str);
+#if IPMI_FRU_PARSER_DEBUG
+            printf ("Chassis : [%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
+#else
+;
+#endif
           }
         break;
     case IPMI_FRU_AREA_BOARD_INFO:
@@ -897,9 +947,20 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
                 if (i==OPENBMC_VPD_KEY_BOARD_MFG_DATE)
                 {
                     sd_bus_message_append (vpdtbl, "sa{y}", vpd_key_names[i], mfg_date_time);
+#if IPMI_FRU_PARSER_DEBUG
+                    printf ("Board : [%s] = [%d]\n", vpd_key_names[i], mfg_date_time);
+#else
+;
+#endif
                     continue;
                 }
-                sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], vpd_info [i].type_length_field); 
+                ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
+                sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], ipmi_fru_field_str);
+#if IPMI_FRU_PARSER_DEBUG
+                printf ("Board : [%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
+#else
+;
+#endif
             }
             break;
     case IPMI_FRU_AREA_PRODUCT_INFO:
@@ -916,7 +977,13 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
                 NULL, 0);
             for (i=OPENBMC_VPD_KEY_PRODUCT_MFR; i<=OPENBMC_VPD_KEY_PRODUCT_MAX; i++)
             {
-                sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], vpd_info [i].type_length_field); 
+                ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
+                sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], ipmi_fru_field_str);
+#if IPMI_FRU_PARSER_DEBUG
+                printf ("Product : [%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
+#else
+;
+#endif
             }
             break;
     defualt:
-- 
2.6.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH ipmi-fru-parser 08/11] Fix format string in sd_bus_message_append to add as dictionary. Store manufacturing time in ISO8601 format.
  2015-11-08  3:58 [PATCH ipmi-fru-parser 00/11] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
                   ` (6 preceding siblings ...)
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 07/11] Internal parser functions expect the area buffer to point to location where language code. Hence advance 2 bytes on the areabuf(to go past the fmt/version and len fields) and pass it to the area specific parser routines. Also fix bugs on offset/len calcuation OpenBMC Patches
@ 2015-11-08  3:59 ` OpenBMC Patches
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 09/11] Construct format string for sd_bus_message_append based on field type encoding OpenBMC Patches
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: OpenBMC Patches @ 2015-11-08  3:59 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 frup.c | 39 +++++++++++++++++++++++++++++++--------
 1 file changed, 31 insertions(+), 8 deletions(-)

diff --git a/frup.c b/frup.c
index 87669f8..7e39ad1 100644
--- a/frup.c
+++ b/frup.c
@@ -178,6 +178,25 @@ const char* vpd_key_names [] =
  *
  * --------------------------------------------------------------------
  */
+
+static size_t _to_time_str (uint32_t mfg_date_time, char* timestr, uint32_t len)
+{
+    struct tm tm;
+    time_t t;
+    size_t s;
+
+    ASSERT (timestr);
+    ASSERT (len);
+
+    memset (&tm, '\0', sizeof (struct tm));
+
+    t = mfg_date_time;
+    gmtime_r (&t, &tm);
+    s = strftime (timestr, len, "%F - %H:%M:%S", &tm);
+
+    return s;
+}
+
 /* private method to parse type/length */
 static int
 _parse_type_length (const void *areabuf,
@@ -719,6 +738,7 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
   ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ];
   ipmi_fru_common_hdr_t* chdr = NULL;
   uint8_t* hdr = NULL;
+  char timestr [ OPENBMC_VPD_VAL_LEN ];
 
 
   ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
@@ -828,7 +848,7 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
   {
     if (i==OPENBMC_VPD_KEY_CHASSIS_TYPE)
     {
-        sd_bus_message_append (vpdtbl, "sy", vpd_key_names[i], chassis_type);
+        sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "y", chassis_type);
 #if IPMI_FRU_PARSER_DEBUG
         printf ("[%s] = [%d]\n", vpd_key_names[i], chassis_type);
 #else
@@ -839,7 +859,8 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
 
     if (i==OPENBMC_VPD_KEY_BOARD_MFG_DATE)
     {
-        sd_bus_message_append (vpdtbl, "sa{y}", vpd_key_names[i], mfg_date_time);
+        _to_time_str (mfg_date_time, timestr, OPENBMC_VPD_VAL_LEN);
+        sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", timestr);
 #if IPMI_FRU_PARSER_DEBUG
         printf ("[%s] = [%d]\n", vpd_key_names[i], mfg_date_time);
 #else
@@ -850,7 +871,7 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
     
     /* FIXME: Field type encoding *ASSUMED* to be *BINARY* */
     ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
-    sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], ipmi_fru_field_str); 
+    sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str); 
     if (vpd_info[i].type_length_field_length)
     {
 #if IPMI_FRU_PARSER_DEBUG
@@ -876,6 +897,7 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
   ipmi_fru_common_hdr_t* chdr = NULL;
   uint8_t* hdr = NULL;
   const uint8_t* ipmi_fru_field_str=NULL;
+  char timestr [ OPENBMC_VPD_VAL_LEN ];
 
 
   ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
@@ -912,7 +934,7 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
           {
             if (i==OPENBMC_VPD_KEY_CHASSIS_TYPE)
             {
-                sd_bus_message_append (vpdtbl, "sy", vpd_key_names[i], chassis_type);
+                sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "y", chassis_type);
 #if IPMI_FRU_PARSER_DEBUG
                 printf ("Chassis : [%s] = [%d]\n", vpd_key_names[i], chassis_type);
 #else
@@ -921,7 +943,7 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
                 continue;
             }
             ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
-            sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], ipmi_fru_field_str);
+            sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
 #if IPMI_FRU_PARSER_DEBUG
             printf ("Chassis : [%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
 #else
@@ -946,7 +968,8 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
             {
                 if (i==OPENBMC_VPD_KEY_BOARD_MFG_DATE)
                 {
-                    sd_bus_message_append (vpdtbl, "sa{y}", vpd_key_names[i], mfg_date_time);
+                    _to_time_str (mfg_date_time, timestr, OPENBMC_VPD_VAL_LEN);
+                    sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", timestr);
 #if IPMI_FRU_PARSER_DEBUG
                     printf ("Board : [%s] = [%d]\n", vpd_key_names[i], mfg_date_time);
 #else
@@ -955,7 +978,7 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
                     continue;
                 }
                 ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
-                sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], ipmi_fru_field_str);
+                sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
 #if IPMI_FRU_PARSER_DEBUG
                 printf ("Board : [%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
 #else
@@ -978,7 +1001,7 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
             for (i=OPENBMC_VPD_KEY_PRODUCT_MFR; i<=OPENBMC_VPD_KEY_PRODUCT_MAX; i++)
             {
                 ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
-                sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], ipmi_fru_field_str);
+                sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
 #if IPMI_FRU_PARSER_DEBUG
                 printf ("Product : [%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
 #else
-- 
2.6.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH ipmi-fru-parser 09/11] Construct format string for sd_bus_message_append based on field type encoding.
  2015-11-08  3:58 [PATCH ipmi-fru-parser 00/11] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
                   ` (7 preceding siblings ...)
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 08/11] Fix format string in sd_bus_message_append to add as dictionary. Store manufacturing time in ISO8601 format OpenBMC Patches
@ 2015-11-08  3:59 ` OpenBMC Patches
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 10/11] Merging IPMI FRU writer and parser OpenBMC Patches
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 11/11] Include sdbus header in frup.c OpenBMC Patches
  10 siblings, 0 replies; 12+ messages in thread
From: OpenBMC Patches @ 2015-11-08  3:59 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 Makefile |  10 +--
 frup.c   | 278 ++++++++++++++++++++++++++++++++++++++++-----------------------
 frup.h   |   4 +-
 3 files changed, 185 insertions(+), 107 deletions(-)

diff --git a/Makefile b/Makefile
index bcb3648..8e74dd8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,17 +1,17 @@
-CXX ?= $(CROSS_COMPILE)g++
+CXX ?= $(CROSS_COMPILE)gcc
 
 IPMI_FRU_PARSER_LIB = libifp.so
 IPMI_FRU_PARSER_OBJS = frup.o
 
-INC_FLAGS += $(shell pkg-config --cflags --libs libsystemd) -I. -O2 --std=gnu++11
-#LIB_FLAGS += $(shell pkg-config  --libs libsystemd) -rdynamic
+
+INC_FLAGS += -I. -O2 --std=gnu++11 -DIPMI_FRU_PARSER_DEBUG
+#INC_FLAGS += -I. -O2 --std=gnu++11
 LIB_FLAGS += -rdynamic
-#IPMID_PATH ?= -DHOST_IPMI_LIB_PATH=\"/usr/lib/host-ipmid/\" 
 
 all: $(IPMI_FRU_PARSER_LIB)
 
 %.o: %.c
-	$(CXX) -fpic -c $< $(CXXFLAGS) $(INC_FLAG) $(IPMID_PATH) -o $@
+	$(CXX) -fpic -c $< $(CXXFLAGS) $(INC_FLAGS) $(IPMID_PATH) -o $@
 
 $(IPMI_FRU_PARSER_LIB): $(IPMI_FRU_PARSER_OBJS)
 	$(CXX) $^ -shared $(LDFLAGS) $(LIB_FLAGS) -o $@
diff --git a/frup.c b/frup.c
index 7e39ad1..2d8cc3b 100644
--- a/frup.c
+++ b/frup.c
@@ -43,8 +43,8 @@
 #include <unistd.h>
 #include <string.h>
 #include <time.h>
+#include <ctype.h>
 
-#define IPMI_FRU_PARSER_DEBUG 1
 #define uint8_t unsigned char
 #define uint32_t unsigned int
 
@@ -81,8 +81,11 @@ return -1; \
 #define OPENBMC_VPD_VAL_LEN                            512
 
 
+extern "C"
+{
 int sd_bus_message_append (void*, const char*, ...);
 typedef struct sd_bus_message sd_bus_message;
+};
 
 struct ipmi_fru_field
 {
@@ -117,7 +120,15 @@ enum openbmc_vpd_key_id
   OPENBMC_VPD_KEY_CHASSIS_TYPE = 1, /* not a type/len */
   OPENBMC_VPD_KEY_CHASSIS_PART_NUM,
   OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,
-  OPENBMC_VPD_KEY_CHASSIS_MAX = OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM1,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM2,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM3,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM4,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM5,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM6,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM7,
+  OPENBMC_VPD_KEY_CHASSIS_CUSTOM8,
+  OPENBMC_VPD_KEY_CHASSIS_MAX = OPENBMC_VPD_KEY_CHASSIS_CUSTOM8,
   /* TODO: chassis_custom_fields */
 
   OPENBMC_VPD_KEY_BOARD_MFG_DATE, /* not a type/len */
@@ -126,7 +137,15 @@ enum openbmc_vpd_key_id
   OPENBMC_VPD_KEY_BOARD_SERIAL_NUM,
   OPENBMC_VPD_KEY_BOARD_PART_NUM,
   OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID,
-  OPENBMC_VPD_KEY_BOARD_MAX = OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM1,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM2,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM3,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM4,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM5,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM6,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM7,
+  OPENBMC_VPD_KEY_BOARD_CUSTOM8,
+  OPENBMC_VPD_KEY_BOARD_MAX = OPENBMC_VPD_KEY_BOARD_CUSTOM8,
   /* TODO: board_custom_fields */
 
   OPENBMC_VPD_KEY_PRODUCT_MFR,
@@ -136,38 +155,66 @@ enum openbmc_vpd_key_id
   OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM,
   OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG,
   OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID,
-  OPENBMC_VPD_KEY_PRODUCT_MAX = OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID,
-  /* TODO: product_custom_fields */
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM1,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM2,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM3,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM4,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM5,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM6,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM7,
+  OPENBMC_VPD_KEY_PRODUCT_CUSTOM8,
+  OPENBMC_VPD_KEY_PRODUCT_MAX = OPENBMC_VPD_KEY_PRODUCT_CUSTOM8,
 
   OPENBMC_VPD_KEY_MAX,
+  OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX=8,
   
 };
 
 const char* vpd_key_names [] = 
 {
   "Key Names Table Start", 
-  "Chassis Type", /*OPENBMC_VPD_KEY_CHASSIS_TYPE*/
-  "Chassis Part Number", /*OPENBMC_VPD_KEY_CHASSIS_PART_NUM,*/
-  "Chassis Serial Number", /*OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,*/
-
-  /* TODO: chassis_custom_fields */
-
-  "Board Mfg Date", /* OPENBMC_VPD_KEY_BOARD_MFG_DATE, */ /* not a type/len */
-  "Board Manufacturer", /* OPENBMC_VPD_KEY_BOARD_MFR, */
-  "Board Name", /* OPENBMC_VPD_KEY_BOARD_NAME, */
-  "Board Serial Number", /* OPENBMC_VPD_KEY_BOARD_SERIAL_NUM, */
-  "Board Part Number", /* OPENBMC_VPD_KEY_BOARD_PART_NUM, */
-  "Board FRU File ID", /* OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID, */
-  /* TODO: board_custom_fields */
-
-  "Product Manufacturer", /* OPENBMC_VPD_KEY_PRODUCT_MFR, */
-  "Product Name", /* OPENBMC_VPD_KEY_PRODUCT_NAME, */
-  "Product Model Number", /* OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM, */
-  "Product Version", /* OPENBMC_VPD_KEY_PRODUCT_VER, */
-  "Product Serial Number", /* OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM, */
-  "Product Asset Tag", /* OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG, */
-  "Product FRU File ID", /* OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID, */
-  /* TODO: product_custom_fields */
+  "Type", /*OPENBMC_VPD_KEY_CHASSIS_TYPE*/
+  "Part Number", /*OPENBMC_VPD_KEY_CHASSIS_PART_NUM,*/
+  "Serial Number", /*OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,*/
+  "Custom Field 1", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM1,*/
+  "Custom Field 2", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM2,*/
+  "Custom Field 3", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM3,*/
+  "Custom Field 4", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM4,*/
+  "Custom Field 5", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM5,*/
+  "Custom Field 6", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM6,*/
+  "Custom Field 7", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM7,*/
+  "Custom Field 8", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM8,*/
+
+  "Mfg Date", /* OPENBMC_VPD_KEY_BOARD_MFG_DATE, */ /* not a type/len */
+  "Manufacturer", /* OPENBMC_VPD_KEY_BOARD_MFR, */
+  "Name", /* OPENBMC_VPD_KEY_BOARD_NAME, */
+  "Serial Number", /* OPENBMC_VPD_KEY_BOARD_SERIAL_NUM, */
+  "Part Number", /* OPENBMC_VPD_KEY_BOARD_PART_NUM, */
+  "FRU File ID", /* OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID, */
+  "Custom Field 1", /*OPENBMC_VPD_KEY_BOARD_CUSTOM1,*/
+  "Custom Field 2", /*OPENBMC_VPD_KEY_BOARD_CUSTOM2,*/
+  "Custom Field 3", /*OPENBMC_VPD_KEY_BOARD_CUSTOM3,*/
+  "Custom Field 4", /*OPENBMC_VPD_KEY_BOARD_CUSTOM4,*/
+  "Custom Field 5", /*OPENBMC_VPD_KEY_BOARD_CUSTOM5,*/
+  "Custom Field 6", /*OPENBMC_VPD_KEY_BOARD_CUSTOM6,*/
+  "Custom Field 7", /*OPENBMC_VPD_KEY_BOARD_CUSTOM7,*/
+  "Custom Field 8", /*OPENBMC_VPD_KEY_BOARD_CUSTOM8,*/
+
+  "Manufacturer", /* OPENBMC_VPD_KEY_PRODUCT_MFR, */
+  "Name", /* OPENBMC_VPD_KEY_PRODUCT_NAME, */
+  "Model Number", /* OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM, */
+  "Version", /* OPENBMC_VPD_KEY_PRODUCT_VER, */
+  "Serial Number", /* OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM, */
+  "Asset Tag", /* OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG, */
+  "FRU File ID", /* OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID, */
+  "Custom Field 1", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM1,*/
+  "Custom Field 2", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM2,*/
+  "Custom Field 3", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM3,*/
+  "Custom Field 4", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM4,*/
+  "Custom Field 5", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM5,*/
+  "Custom Field 6", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM6,*/
+  "Custom Field 7", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM7,*/
+  "Custom Field 8", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM8,*/
 
   "Key Names Table End" /*OPENBMC_VPD_KEY_MAX,*/
 };
@@ -691,6 +738,7 @@ ipmi_fru_product_info_area (const void *areabuf,
                           &number_of_data_bytes,
                           product_fru_file_id) < 0)
     goto cleanup;
+
   area_offset += 1;          /* type/length byte */
   area_offset += number_of_data_bytes;
 
@@ -729,12 +777,42 @@ ipmi_fru_product_info_area (const void *areabuf,
 }
 
 
+int _append_to_dict (uint8_t vpd_key_id, uint8_t* vpd_key_val, sd_bus_message* vpdtbl) 
+{
+    int type_length = vpd_key_val[0];
+    int type_code = (type_length & IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK) >> IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT;
+    int vpd_val_len = type_length & IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK;
+    int sdr=0;
+
+    switch (type_code)
+    {
+        case 0:
+            printf ("_append_to_dict: VPD Key = [%s] : Type Code = [BINARY] : Len = [%d] : Val = [%s]\n", vpd_key_names [vpd_key_id], vpd_val_len, &vpd_key_val[1]);
+            sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[vpd_key_id], "ay", vpd_val_len, &vpd_key_val[1]);
+            /*sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[vpd_key_id], "s", &vpd_key_val[1]);*/
+            break;
+        case 3:
+            printf ("_append_to_dict: VPD Key = [%s] : Type Code = [ASCII+Latin] : Len = [%d] : Val = [%s]\n", vpd_key_names [vpd_key_id], vpd_val_len, &vpd_key_val[1]);
+            sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[vpd_key_id], "s", &vpd_key_val[1]);
+            break;
+    }
+
+    if (sdr < 0)
+    {
+#if IPMI_FRU_PARSER_DEBUG
+        printf ("_append_to_dict : sd_bus_message_append Failed [ %d ] for [%s]\n", sdr, vpd_key_names[vpd_key_id]);
+#endif
+    }
+}
+
 int
 parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
 {
   int ret = 0;
   int rv = -1;
   int i = 0;
+  int j = 0;
+  int isprintable = 0;
   ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ];
   ipmi_fru_common_hdr_t* chdr = NULL;
   uint8_t* hdr = NULL;
@@ -742,9 +820,7 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
 
 
   ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
-  /*char ipmi_fru_field_str [ IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX ];
-  uint32_t len=0;*/
-  const uint8_t* ipmi_fru_field_str;
+  uint8_t* ipmi_fru_field_str;
 
   /* Chassis */
   uint8_t chassis_type;
@@ -794,7 +870,8 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
         &chassis_type,
         &vpd_info [OPENBMC_VPD_KEY_CHASSIS_PART_NUM],
         &vpd_info [OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM],
-        NULL, 0);
+        &vpd_info [OPENBMC_VPD_KEY_CHASSIS_CUSTOM1], 
+        OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
   }
     
   if (chdr->board)
@@ -809,7 +886,8 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
         &vpd_info [OPENBMC_VPD_KEY_BOARD_SERIAL_NUM],
         &vpd_info [OPENBMC_VPD_KEY_BOARD_PART_NUM],
         &vpd_info [OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID],
-        NULL, 0);
+        &vpd_info [OPENBMC_VPD_KEY_BOARD_CUSTOM1], 
+        OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
   }
 
   if (chdr->product)
@@ -825,7 +903,8 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
         &vpd_info [OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM],
         &vpd_info [OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG],
         &vpd_info [OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID],
-        NULL, 0);
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_CUSTOM1], 
+        OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
   }
 
   if (chdr->multirec)
@@ -838,8 +917,6 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
   {
 #if IPMI_FRU_PARSER_DEBUG
     printf ("IPMI_FRU_AREA_TYPE=[%d] : Offset=[%d] : Len=[%d]\n", i, fru_area_info [i].off, fru_area_info[i].len);
-#else
-;
 #endif
   }
 
@@ -851,8 +928,6 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
         sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "y", chassis_type);
 #if IPMI_FRU_PARSER_DEBUG
         printf ("[%s] = [%d]\n", vpd_key_names[i], chassis_type);
-#else
-;
 #endif
         continue;
     }
@@ -863,25 +938,16 @@ parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
         sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", timestr);
 #if IPMI_FRU_PARSER_DEBUG
         printf ("[%s] = [%d]\n", vpd_key_names[i], mfg_date_time);
-#else
-;
 #endif
         continue;
     }
-    
-    /* FIXME: Field type encoding *ASSUMED* to be *BINARY* */
-    ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
-    sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str); 
-    if (vpd_info[i].type_length_field_length)
-    {
-#if IPMI_FRU_PARSER_DEBUG
-        printf ("[%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
-#else
-;
-#endif
-    }
-  }
 
+    /* Append TypeLen Field to Dictionary */
+    _append_to_dict (i, vpd_info[i].type_length_field, vpdtbl);
+
+    /*ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;*/
+    /*sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str); */
+  }
  out:
   rv = 0;
  cleanup:
@@ -893,66 +959,72 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
   int ret = 0;
   int rv = -1;
   int i = 0;
-  ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ];
-  ipmi_fru_common_hdr_t* chdr = NULL;
-  uint8_t* hdr = NULL;
-  const uint8_t* ipmi_fru_field_str=NULL;
-  char timestr [ OPENBMC_VPD_VAL_LEN ];
-
-
-  ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
-  for (i=0; i<OPENBMC_VPD_KEY_MAX; i++)
-  {
-    memset (vpd_info[i].type_length_field, '\0', IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
-    vpd_info[i].type_length_field_length = 0;
-  }
+  int j = 0;
+  int sdr = 0;
+  int isprintable = 0;
 
   /* Chassis */
   uint8_t chassis_type;
-
   /* Board */
   uint32_t mfg_date_time;
-
   /* Product */
   unsigned int product_custom_fields_len;
 
+  ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ];
+  ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
+  char timestr [ OPENBMC_VPD_VAL_LEN ];
+
+  uint8_t* ipmi_fru_field_str=NULL;
+  ipmi_fru_common_hdr_t* chdr = NULL;
+  uint8_t* hdr = NULL;
+
   ASSERT (msgbuf);
   ASSERT (vpdtbl);
 
+  for (i=0; i<OPENBMC_VPD_KEY_MAX; i++)
+  {
+    memset (vpd_info[i].type_length_field, '\0', IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
+    vpd_info[i].type_length_field_length = 0;
+  }
+
   switch (area)
   {
     case IPMI_FRU_AREA_CHASSIS_INFO:
-        ipmi_fru_chassis_info_area (msgbuf,
+#if IPMI_FRU_PARSER_DEBUG
+          printf ("Chassis : Buf len = [%d]\n", len);
+#endif
+        ipmi_fru_chassis_info_area ((uint8_t*)msgbuf+2,
             len,
             &chassis_type,
             &vpd_info [OPENBMC_VPD_KEY_CHASSIS_PART_NUM],
             &vpd_info [OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM],
-            NULL, 0);
+            &vpd_info [OPENBMC_VPD_KEY_CHASSIS_CUSTOM1],
+            OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
 
           /* Populate VPD Table */
           for (i=1; i<=OPENBMC_VPD_KEY_CHASSIS_MAX; i++)
           {
             if (i==OPENBMC_VPD_KEY_CHASSIS_TYPE)
             {
-                sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "y", chassis_type);
 #if IPMI_FRU_PARSER_DEBUG
-                printf ("Chassis : [%s] = [%d]\n", vpd_key_names[i], chassis_type);
-#else
-;
+                printf ("Chassis : Appending [%s] = [%d]\n", vpd_key_names[i], chassis_type);
 #endif
+                sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "y", chassis_type);
                 continue;
             }
+
+            _append_to_dict (i, vpd_info[i].type_length_field, vpdtbl);
+/*
             ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
-            sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
-#if IPMI_FRU_PARSER_DEBUG
-            printf ("Chassis : [%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
-#else
-;
-#endif
+            sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
+*/
           }
         break;
     case IPMI_FRU_AREA_BOARD_INFO:
-            ipmi_fru_board_info_area (msgbuf, 
+#if IPMI_FRU_PARSER_DEBUG
+            printf ("Board : Buf len = [%d]\n", len);
+#endif
+            ipmi_fru_board_info_area ((uint8_t*)msgbuf+2,
                 len,
                 NULL,
                 &mfg_date_time,
@@ -961,7 +1033,8 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
                 &vpd_info [OPENBMC_VPD_KEY_BOARD_SERIAL_NUM],
                 &vpd_info [OPENBMC_VPD_KEY_BOARD_PART_NUM],
                 &vpd_info [OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID],
-                NULL, 0);
+                &vpd_info [OPENBMC_VPD_KEY_BOARD_CUSTOM1],
+                OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
 
           /* Populate VPD Table */
             for (i=OPENBMC_VPD_KEY_BOARD_MFR; i<=OPENBMC_VPD_KEY_BOARD_MAX; i++)
@@ -969,25 +1042,31 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
                 if (i==OPENBMC_VPD_KEY_BOARD_MFG_DATE)
                 {
                     _to_time_str (mfg_date_time, timestr, OPENBMC_VPD_VAL_LEN);
-                    sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", timestr);
 #if IPMI_FRU_PARSER_DEBUG
-                    printf ("Board : [%s] = [%d]\n", vpd_key_names[i], mfg_date_time);
-#else
-;
+                    printf ("Board : Appending [%s] = [%d]\n", vpd_key_names[i], timestr);
+#endif
+                    sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", timestr);
+                    if (sdr < 0)
+                    {
+#if IPMI_FRU_PARSER_DEBUG
+                        printf ("ipmi_fru_board_info_area : sd_bus_message_append Failed [ %d ] for [%s]\n", sdr, vpd_key_names[i]);
 #endif
+                    }
                     continue;
                 }
+
+                _append_to_dict (i, vpd_info[i].type_length_field, vpdtbl);
+/*
                 ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
-                sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
-#if IPMI_FRU_PARSER_DEBUG
-                printf ("Board : [%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
-#else
-;
-#endif
+                sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
+*/
             }
             break;
     case IPMI_FRU_AREA_PRODUCT_INFO:
-            ipmi_fru_product_info_area (msgbuf,
+#if IPMI_FRU_PARSER_DEBUG
+            printf ("Product : Buf len = [%d]\n", len);
+#endif
+            ipmi_fru_product_info_area ((uint8_t*)msgbuf+2,
                 len,
                 NULL,
                 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_MFR],
@@ -997,16 +1076,12 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
                 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM],
                 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG],
                 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID],
-                NULL, 0);
+                &vpd_info [OPENBMC_VPD_KEY_PRODUCT_CUSTOM1],
+                OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
+
             for (i=OPENBMC_VPD_KEY_PRODUCT_MFR; i<=OPENBMC_VPD_KEY_PRODUCT_MAX; i++)
             {
-                ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
-                sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
-#if IPMI_FRU_PARSER_DEBUG
-                printf ("Product : [%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
-#else
-;
-#endif
+                _append_to_dict (i, vpd_info[i].type_length_field, vpdtbl);
             }
             break;
     defualt:
@@ -1014,6 +1089,9 @@ int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, s
     break;
   }
 
+#if IPMI_FRU_PARSER_DEBUG
+    printf ("parse_fru_area : Dictionary Packing Complete\n");
+#endif
  out:
   rv = 0;
  cleanup:
diff --git a/frup.h b/frup.h
index b6b9476..0269bf8 100644
--- a/frup.h
+++ b/frup.h
@@ -5,7 +5,7 @@
 int parse_fru (const void* msgbuf, sd_bus_message* vpdtbl);
 int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, sd_bus_message* vpdtbl);
 
-enum openbmc_ipmi_fru_area_type
+enum ipmi_fru_area_type
 {
     IPMI_FRU_AREA_INTERNAL_USE = 0x00,
     IPMI_FRU_AREA_CHASSIS_INFO,
@@ -13,6 +13,6 @@ enum openbmc_ipmi_fru_area_type
     IPMI_FRU_AREA_PRODUCT_INFO,
     IPMI_FRU_AREA_MULTI_RECORD,
     IPMI_FRU_AREA_TYPE_MAX
-}
+};
 
 #endif
-- 
2.6.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH ipmi-fru-parser 10/11] Merging IPMI FRU writer and parser.
  2015-11-08  3:58 [PATCH ipmi-fru-parser 00/11] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
                   ` (8 preceding siblings ...)
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 09/11] Construct format string for sd_bus_message_append based on field type encoding OpenBMC Patches
@ 2015-11-08  3:59 ` OpenBMC Patches
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 11/11] Include sdbus header in frup.c OpenBMC Patches
  10 siblings, 0 replies; 12+ messages in thread
From: OpenBMC Patches @ 2015-11-08  3:59 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 Makefile       |  26 ++-
 frup.h         |   2 +
 writefrudata.C | 564 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 writefrudata.H |  53 ++++++
 4 files changed, 637 insertions(+), 8 deletions(-)
 create mode 100644 writefrudata.C
 create mode 100644 writefrudata.H

diff --git a/Makefile b/Makefile
index 8e74dd8..076aa76 100644
--- a/Makefile
+++ b/Makefile
@@ -1,20 +1,30 @@
 CXX ?= $(CROSS_COMPILE)gcc
 
-IPMI_FRU_PARSER_LIB = libifp.so
-IPMI_FRU_PARSER_OBJS = frup.o
+FRU_WRITE_AND_PARSER_LIB = libwritefrudata.so
+FRU_WRITE_AND_PARSER_OBJS = frup.o writefrudata.o
 
+INC_FLAGS += $(shell pkg-config --cflags --libs libsystemd) -I. -O2 --std=gnu++14
+LIB_FLAGS += $(shell pkg-config  --libs libsystemd) -rdynamic
 
-INC_FLAGS += -I. -O2 --std=gnu++11 -DIPMI_FRU_PARSER_DEBUG
-#INC_FLAGS += -I. -O2 --std=gnu++11
-LIB_FLAGS += -rdynamic
+DESTDIR ?= /
+SBINDIR ?= /usr/sbin
+INCLUDEDIR ?= /usr/include
+LIBDIR ?= /usr/lib
 
-all: $(IPMI_FRU_PARSER_LIB)
+all: $(FRU_WRITE_AND_PARSER_LIB)
 
 %.o: %.c
 	$(CXX) -fpic -c $< $(CXXFLAGS) $(INC_FLAGS) $(IPMID_PATH) -o $@
 
-$(IPMI_FRU_PARSER_LIB): $(IPMI_FRU_PARSER_OBJS)
+%.o: %.C
+	$(CXX) -fpic -c $< $(CXXFLAGS) $(INC_FLAGS) $(IPMID_PATH) -o $@
+
+$(FRU_WRITE_AND_PARSER_LIB): $(FRU_WRITE_AND_PARSER_OBJS)
 	$(CXX) $^ -shared $(LDFLAGS) $(LIB_FLAGS) -o $@
 
 clean:
-	rm -f $(IPMI_FRU_PARSER_OBJS) $(IPMI_FRU_PARSER_LIB)
+	rm -f $(FRU_WRITE_AND_PARSER_OBJS) $(FRU_WRITE_AND_PARSER_LIB)
+
+install:
+		install -m 0755 -d $(DESTDIR)$(LIBDIR)/host-ipmid
+		install -m 0755 $(FRU_WRITE_AND_PARSER_LIB) $(DESTDIR)$(LIBDIR)/host-ipmid
diff --git a/frup.h b/frup.h
index 0269bf8..3286260 100644
--- a/frup.h
+++ b/frup.h
@@ -1,6 +1,8 @@
 #ifndef OPENBMC_IPMI_FRU_PARSER_H
 #define OPENBMC_IPMI_FRU_PARSER_H
 
+#include <systemd/sd-bus.h>
+
 /* Parse an IPMI write fru data message into a dictionary containing name value pair of VPD entries.*/
 int parse_fru (const void* msgbuf, sd_bus_message* vpdtbl);
 int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, sd_bus_message* vpdtbl);
diff --git a/writefrudata.C b/writefrudata.C
new file mode 100644
index 0000000..30ba39a
--- /dev/null
+++ b/writefrudata.C
@@ -0,0 +1,564 @@
+#include <ipmid-api.h>
+#include <vector>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdio.h>
+#include "frup.h"
+#include "writefrudata.H"
+#include <systemd/sd-bus.h>
+
+void register_netfn_storage_write_fru() __attribute__((constructor));
+
+// Needed to be passed into fru parser alorithm
+typedef std::vector<fru_area_t> fru_area_vec_t;
+
+// OpenBMC System Manager dbus framework
+const char  *bus_name      =  "org.openbmc.managers.System";
+const char  *object_name   =  "/org/openbmc/managers/System";
+const char  *intf_name     =  "org.openbmc.managers.System";
+
+//------------------------------------------------
+// Takes the pointer to stream of bytes and length 
+// returns the 8 bit checksum per IPMI spec.
+//-------------------------------------------------
+unsigned char calculate_crc(unsigned char *data, int len)
+{
+    char crc = 0;
+    int byte = 0;
+
+    for(byte = 0; byte < len; byte++)
+    {
+        crc += *data++;
+    }
+    
+    return(-crc);
+}
+
+//---------------------------------------------------------------------
+// Accepts a fru area offset in commom hdr and tells which area it is.
+//---------------------------------------------------------------------
+uint8_t get_fru_area_type(uint8_t area_offset)
+{
+    ipmi_fru_area_type type = IPMI_FRU_AREA_TYPE_MAX;
+
+    switch(area_offset)
+    {
+        case IPMI_FRU_INTERNAL_OFFSET:
+            type = IPMI_FRU_AREA_INTERNAL_USE;
+            break;
+
+        case IPMI_FRU_CHASSIS_OFFSET:
+            type = IPMI_FRU_AREA_CHASSIS_INFO;
+            break;
+
+        case IPMI_FRU_BOARD_OFFSET:
+            type = IPMI_FRU_AREA_BOARD_INFO;
+            break;
+
+        case IPMI_FRU_PRODUCT_OFFSET:
+            type = IPMI_FRU_AREA_PRODUCT_INFO;
+            break;
+
+        case IPMI_FRU_MULTI_OFFSET:
+            type = IPMI_FRU_AREA_MULTI_RECORD;
+            break;
+
+        default:
+            type = IPMI_FRU_AREA_TYPE_MAX;
+    }
+
+    return type;
+}
+
+//------------------------------------------------------------------------
+// Takes FRU data, invokes Parser for each fru record area and updates
+// Inventory
+//------------------------------------------------------------------------
+int ipmi_update_inventory(const uint8_t fruid, const uint8_t *fru_data, 
+                          fru_area_vec_t & area_vec)
+{
+    // Now, use this fru dictionary object and connect with FRU Inventory Dbus
+    // and update the data for this FRU ID.
+    int rc = 0;
+    
+    // Dictionary object to hold Name:Value pair
+    sd_bus_message *fru_dict = NULL;
+
+    // SD Bus error report mechanism.
+    sd_bus_error bus_error = SD_BUS_ERROR_NULL;
+
+    // Gets a hook onto either a SYSTEM or SESSION bus
+    sd_bus *bus_type = NULL;
+
+    // Req message contains the specifics about which method etc that we want to
+    // access on which bus, object
+    sd_bus_message *response = NULL;
+
+    rc = sd_bus_open_system(&bus_type);
+    if(rc < 0)
+    {
+        fprintf(stderr,"ERROR: Getting a SYSTEM bus hook\n");
+        return -1;
+    }
+
+    // For each FRU area, extract the needed data , get it parsed and update
+    // the Inventory.
+    for(auto& iter : area_vec)
+    {
+        uint8_t area_type = (iter).type;
+
+        uint8_t area_data[(iter).len];
+        memset(area_data, 0x0, sizeof(area_data));
+
+        // Grab area specific data
+        memmove(area_data, (iter).offset, (iter).len);
+
+        // Need this to get respective DBUS objects
+        const char *area_name  = NULL;
+
+        if(area_type == IPMI_FRU_AREA_CHASSIS_INFO)
+        {
+            area_name = "CHASSIS_";
+        }
+        else if(area_type == IPMI_FRU_AREA_BOARD_INFO)
+        {
+            area_name = "BOARD_";
+        }
+        else if(area_type == IPMI_FRU_AREA_PRODUCT_INFO)
+        {
+            area_name = "PRODUCT_";
+        }
+        else
+        {
+            fprintf(stderr, "ERROR: Invalid Area type :[%d]",area_type);
+            break;
+        }
+ 
+        // What we need is BOARD_1, PRODUCT_1, CHASSIS_1 etc..
+        char fru_area_name[16] = {0};
+        sprintf(fru_area_name,"%s%d",area_name, fruid);
+
+#ifdef __IPMI_DEBUG__
+        printf("Updating Inventory with :[%s]\n",fru_area_name);
+#endif
+        // Each area needs a clean set.       
+        sd_bus_error_free(&bus_error);
+        sd_bus_message_unref(response);
+        sd_bus_message_unref(fru_dict);
+    
+        // We want to call a method "getObjectFromId" on System Bus that is
+        // made available over  OpenBmc system services.
+        rc = sd_bus_call_method(bus_type,                   // On the System Bus
+                                bus_name,                   // Service to contact
+                                object_name,                // Object path 
+                                intf_name,                  // Interface name
+                                "getObjectFromId",          // Method to be called
+                                &bus_error,                 // object to return error
+                                &response,                  // Response message on success
+                                "ss",                       // input message (string,byte)
+                                "FRU_STR",                  // First argument to getObjectFromId
+                                fru_area_name);             // Second Argument
+
+        if(rc < 0)
+        {
+            fprintf(stderr, "Failed to issue method call: %s\n", bus_error.message);
+            break;
+        }
+
+        // Method getObjectFromId returns 3 parameters and all are strings, namely
+        // bus_name , object_path and interface name for accessing that particular 
+        // FRU over Inventory SDBUS manager. 'sss' here mentions that format.
+        char *inv_bus_name, *inv_obj_path, *inv_intf_name;
+        rc = sd_bus_message_read(response, "(sss)", &inv_bus_name, &inv_obj_path, &inv_intf_name);
+        if(rc < 0)
+        {
+            fprintf(stderr, "Failed to parse response message:[%s]\n", strerror(-rc));
+            break;
+        }
+
+#ifdef __IPMI_DEBUG__
+        printf("fru_area=[%s], inv_bus_name=[%s], inv_obj_path=[%s],inv_intf_name=[%s]\n",
+                fru_area_name, inv_bus_name, inv_obj_path, inv_intf_name);
+#endif
+
+        // Constructor to allow further initializations and customization.
+        rc = sd_bus_message_new_method_call(bus_type,
+                                            &fru_dict,
+                                            inv_bus_name,
+                                            inv_obj_path,
+                                            inv_intf_name,
+                                            "update");
+        if(rc < 0)
+        {
+            fprintf(stderr,"ERROR: creating a update method call\n");
+            break;
+        }
+
+        // A Dictionary ({}) having (string, variant)
+        rc = sd_bus_message_open_container(fru_dict, 'a', "{sv}");
+        if(rc < 0)
+        {
+            fprintf(stderr,"ERROR:[%d] creating a dict container:\n",errno);
+            break;
+        }
+
+        // Fill the container with information
+        rc = parse_fru_area((iter).type, (void *)area_data, (iter).len, fru_dict);
+        if(rc < 0)
+        {
+            fprintf(stderr,"ERROR parsing FRU records\n");
+            break;
+        }
+
+        sd_bus_message_close_container(fru_dict);
+
+        // Now, Make the actual call to update the FRU inventory database with the
+        // dictionary given by FRU Parser. There is no response message expected for
+        // this.
+        rc = sd_bus_call(bus_type,            // On the System Bus
+                         fru_dict,            // With the Name:value dictionary array
+                         0,                   // 
+                         &bus_error,          // Object to return error.
+                         &response);          // Response message if any.
+
+        if(rc < 0)
+        {
+            fprintf(stderr, "ERROR:[%s] updating FRU inventory for ID:[0x%X]\n",
+                    bus_error.message, fruid);
+        }
+        else
+        {
+            printf("SUCCESS: Updated:[%s] successfully\n",fru_area_name);
+        }
+    } // END walking the vector of areas and updating
+
+    sd_bus_error_free(&bus_error);
+    sd_bus_message_unref(response);
+    sd_bus_message_unref(fru_dict);
+    sd_bus_unref(bus_type);
+
+    return rc;
+}
+
+//-------------------------------------------------------------------------
+// Validates the CRC and if found good, calls fru areas parser and calls
+// Inventory Dbus with the dictionary of Name:Value for updating. 
+//-------------------------------------------------------------------------
+int ipmi_validate_and_update_inventory(const uint8_t fruid, const uint8_t *fru_data)
+{
+    // Used for generic checksum calculation
+    uint8_t checksum = 0;
+
+    // This can point to any FRU entry.
+    uint8_t fru_entry;
+
+    // A generic offset locator for any FRU record.
+    uint8_t area_offset = 0;
+
+    // First 2 bytes in the record.
+    uint8_t fru_area_hdr[2] = {0};
+
+    // To hold info about individual FRU record areas.
+    fru_area_t fru_area;
+
+    // For parsing and updating Inventory.
+    fru_area_vec_t fru_area_vec;
+
+    int rc = 0;
+
+    uint8_t common_hdr[sizeof(struct common_header)] = {0};
+    memset(common_hdr, 0x0, sizeof(common_hdr));
+
+    // Copy first 8 bytes to verify common header
+    memcpy(common_hdr, fru_data, sizeof(common_hdr));
+
+    // Validate for first byte to always have a value of [1]
+    if(common_hdr[0] != IPMI_FRU_HDR_BYTE_ZERO)
+    {
+        fprintf(stderr, "ERROR: Common Header entry_1:[0x%X] Invalid.\n",common_hdr[0]);
+        return -1;
+    }
+    else
+    {
+        printf("SUCCESS: Validated [0x%X] in common header\n",common_hdr[0]);
+    }
+
+    // Validate the header checskum that is at last byte ( Offset: 7 )
+    checksum = calculate_crc(common_hdr, sizeof(common_hdr)-1);
+    if(checksum != common_hdr[IPMI_FRU_HDR_CRC_OFFSET])
+    {
+#ifdef __IPMI__DEBUG__
+        fprintf(stderr, "ERROR: Common Header checksum mismatch."
+                " Calculated:[0x%X], Embedded:[0x%X]\n", 
+                checksum, common_hdr[IPMI_FRU_HDR_CRC_OFFSET]);
+#endif    
+        return -1;
+    }
+    else
+    {
+        printf("SUCCESS: Common Header checksum MATCH:[0x%X]\n",checksum);
+    }
+
+    //-------------------------------------------
+    // TODO:  Add support for Multi Record later
+    //-------------------------------------------
+
+    //  Now start walking the common_hdr array that has offsets into other FRU
+    //  record areas and validate those. Starting with second entry since the
+    //  first one is always a [0x01]
+    for(fru_entry = IPMI_FRU_INTERNAL_OFFSET; fru_entry < (sizeof(struct common_header) -2); fru_entry++)
+    {
+        // Offset is 'value given in' internal_offset * 8 from the START of
+        // common header. So an an example, 01 00 00 00 01 00 00 fe has
+        // product area set at the offset 01 * 8 --> 8 bytes from the START of
+        // common header. That means, soon after the header checksum.
+        area_offset = common_hdr[fru_entry] * IPMI_EIGHT_BYTES;
+        
+        if(area_offset)
+        {
+            memset((void *)&fru_area, 0x0, sizeof(fru_area_t));
+
+            // Enumerated FRU area.
+            fru_area.type = get_fru_area_type(fru_entry);
+
+            // From start of fru header + record offset, copy 2 bytes.
+            fru_area.offset = &((uint8_t *)fru_data)[area_offset];
+            memcpy(fru_area_hdr, fru_area.offset, sizeof(fru_area_hdr));
+
+            // A NON zero value means that the vpd packet has the data for that
+            // area. err if first element in the record header is _not_ a [0x01].
+            if(fru_area_hdr[0] != IPMI_FRU_HDR_BYTE_ZERO)
+            {
+                fprintf(stderr, "ERROR: Unexpected :[0x%X] found at Record header\n",
+                        fru_area_hdr[0]);
+
+                // This vector by now may have had some entries. Since this is a
+                // failure now, clear the state data.
+                fru_area_vec.clear();
+                return -1;
+            }
+            else
+            {
+                printf("SUCCESS: Validated [0x%X] in fru record:[%d] header\n",
+                        fru_area_hdr[0],fru_entry);
+            }
+
+            // Read Length bytes ( makes a complete record read now )
+            fru_area.len = fru_area_hdr[1] * IPMI_EIGHT_BYTES;
+#ifdef __IPMI_DEBUG__
+            printf("AREA NO[%d], SIZE = [%d]\n",fru_entry, fru_area.len);
+#endif
+            uint8_t fru_area_data[fru_area.len];
+            memset(fru_area_data, 0x0, sizeof(fru_area_data));
+
+            memmove(fru_area_data, fru_area.offset, sizeof(fru_area_data));
+
+            // Calculate checksum (from offset -> (Length-1)).
+            // All the bytes except the last byte( which is CRC :) ) will
+            // participate in calculating the checksum.
+            checksum = calculate_crc(fru_area_data, sizeof(fru_area_data)-1);
+
+            // Verify the embedded checksum in last byte with calculated checksum
+            // record_len -1 since length is some N but numbering is 0..N-1
+            if(checksum != fru_area_data[fru_area.len-1])
+            {
+#ifdef __IPMI_DEBUG__
+                fprintf(stderr, "ERROR: FRU Header checksum mismatch. "
+                        " Calculated:[0x%X], Embedded:[0x%X]\n", 
+                        checksum, fru_area_data[fru_area.len - 1]);
+#endif
+                // This vector by now may have had some entries. Since this is a
+                // failure now, clear the state data.
+                fru_area_vec.clear();
+                return -1;
+            }
+            else
+            {
+                printf("SUCCESS: FRU Header checksum MATCH:[0x%X]\n",checksum);
+            }
+
+            // Everything is rihgt about this particular FRU record,
+            fru_area_vec.push_back(fru_area);
+
+            // Update the internal structure with info about this entry that is
+            // needed while handling each areas.
+        } // If the packet has data for a particular data record.
+    } // End walking all the fru records.
+        
+    // If we reach here, then we have validated the crc for all the records and
+    // time to call FRU area parser to get a Name:Value pair dictionary.
+    // This will start iterating all over again on the buffer -BUT- now with the
+    // job of taking each areas, getting it parsed and then updating the
+    // DBUS.
+        
+    if(!(fru_area_vec.empty()))
+    {
+        rc =  ipmi_update_inventory(fruid, fru_data, fru_area_vec);
+    }
+ 
+    // We are done with this FRU write packet. 
+    fru_area_vec.clear();
+
+    return rc;
+}
+
+///-----------------------------------------------------
+// Accepts the filename and validates per IPMI FRU spec
+//----------------------------------------------------
+int ipmi_validate_fru_area(const uint8_t fruid, const char *fru_file_name)
+{
+    int file_size = 0;
+    uint8_t *fru_data = NULL;
+    int bytes_read = 0;
+    int rc = 0;
+
+    FILE *fru_file = fopen(fru_file_name,"rb");
+    if(fru_file == NULL)
+    {
+        fprintf(stderr, "ERROR: opening:[%s]\n",fru_file_name);
+        perror("Error:");
+        return -1;
+    }
+
+    // Get the size of the file to allocate buffer to hold the entire contents.
+    if(fseek(fru_file, 0, SEEK_END))
+    {
+        perror("Error:");
+        fclose(fru_file);
+        return -1;
+    }
+
+    file_size = ftell(fru_file);
+    fru_data = (uint8_t *)malloc(file_size);
+
+    // Read entire file contents to the internal buffer
+    if(fseek(fru_file, 0, SEEK_SET))
+    {
+        perror("Error:");
+        fclose(fru_file);
+        return -1;
+    }
+
+    bytes_read = fread(fru_data, file_size, 1, fru_file);
+    if(bytes_read != 1)
+    {
+        fprintf(stderr, "ERROR reading common header. Bytes read=:[%d]\n",bytes_read);
+        perror("Error:");
+        fclose(fru_file);
+        return -1;
+    }
+    fclose(fru_file);
+
+    rc = ipmi_validate_and_update_inventory(fruid, fru_data);
+    if(rc == -1)
+    {
+        printf("ERROR: Validation failed for:[%d]\n",fruid);
+    }
+    else
+    {
+        printf("SUCCESS: Validated:[%s]\n",fru_file_name);
+    }
+
+    if(fru_data)
+    {
+        free(fru_data);
+        fru_data = NULL;
+    }
+
+    return rc;
+}
+
+///-------------------------------------------------------
+// Called by IPMI netfn router for write fru data command
+//--------------------------------------------------------
+ipmi_ret_t ipmi_storage_write_fru_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 
+                              ipmi_request_t request, ipmi_response_t response, 
+                              ipmi_data_len_t data_len, ipmi_context_t context)
+{
+    FILE *fp = NULL;
+    char fru_file_name[16] = {0};
+    uint8_t offset = 0;
+    uint16_t len = 0;
+    ipmi_ret_t rc = IPMI_CC_INVALID;
+    int validate_rc = 0;
+    const char *mode = NULL;
+
+    // From the payload, extract the header that has fruid and the offsets
+    write_fru_data_t *reqptr = (write_fru_data_t*)request;
+
+    // There is no response data for this command.
+    *data_len = 0;
+
+    // Maintaining a temporary file to pump the data
+    sprintf(fru_file_name, "%s%02x", "/tmp/ipmifru", reqptr->frunum);
+
+    offset = ((uint16_t)reqptr->offsetms) << 8 | reqptr->offsetls;
+
+    // Length is the number of request bytes minus the header itself.
+    // The header contains an extra byte to indicate the start of
+    // the data (so didn't need to worry about word/byte boundaries)
+    // hence the -1...
+    len = ((uint16_t)*data_len) - (sizeof(write_fru_data_t)-1);
+    
+#ifdef __IPMI__DEBUG__
+    printf("IPMI WRITE-FRU-DATA for [%s]  Offset = [%d] Length = [%d]\n",
+            fru_file_name, offset, len);
+#endif
+
+    // offset would be zero if the cmd payload is targeting a new fru
+    if (offset == 0)
+    {
+        mode = "wb";
+    } 
+    else 
+    {
+        // offset would be non-zero if the cmd payload is continued for prev
+        // fru
+        mode = "rb+";
+    }
+
+    if ((fp = fopen(fru_file_name, mode)) != NULL) 
+    {
+        if(fseek(fp, offset, SEEK_SET))
+        {
+            perror("Error:");
+            fclose(fp);
+            return rc;
+        }
+    
+        if(fwrite(&reqptr->data, len, 1, fp) != 1)
+        {
+            perror("Error:");
+            fclose(fp);
+            return rc;
+        }
+    
+        fclose(fp);
+    } 
+    else 
+    {
+        fprintf(stderr, "Error trying to write to fru file %s\n",fru_file_name);
+        return rc;
+    }
+    
+    // We received some bytes. It may be full or partial. Run a validator.
+    validate_rc = ipmi_validate_fru_area(reqptr->frunum, fru_file_name);
+    if(validate_rc != -1)
+    {
+        // Success validating _and_ updating the Inventory. We no longer need
+        // this file.
+        remove(fru_file_name);
+    }
+
+    // convert the rc per ipmi spec   
+    rc = (validate_rc != -1) ? IPMI_CC_OK : IPMI_CC_INVALID;
+
+    return rc;
+}
+
+void register_netfn_storage_write_fru()
+{
+    printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_WRITE_FRU_DATA);
+    ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WRITE_FRU_DATA, NULL, ipmi_storage_write_fru_data);
+}
diff --git a/writefrudata.H b/writefrudata.H
new file mode 100644
index 0000000..42924a3
--- /dev/null
+++ b/writefrudata.H
@@ -0,0 +1,53 @@
+#ifndef __IPMI_WRITE_FRU_DATA_H__
+#define __IPMI_WRITE_FRU_DATA_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+// IPMI commands for Storage net functions.
+enum ipmi_netfn_storage_cmds
+{
+    IPMI_CMD_WRITE_FRU_DATA = 0x12
+};
+
+// Format of write fru data command
+struct write_fru_data_t 
+{
+    uint8_t  frunum;
+    uint8_t  offsetls;
+    uint8_t  offsetms;
+    uint8_t  data;
+}__attribute__ ((packed));
+
+// Per IPMI v2.0 FRU specification
+struct common_header
+{
+    uint8_t fixed;
+    uint8_t internal_offset;
+    uint8_t chassis_offset;
+    uint8_t board_offset;
+    uint8_t product_offset;
+    uint8_t multi_offset;
+    uint8_t pad;
+    uint8_t crc;
+}__attribute__((packed));
+
+// Contains key info about a particular area.
+typedef struct
+{
+    uint8_t type;
+    uint8_t *offset;
+    size_t  len;
+}__attribute__((packed)) fru_area_t;
+
+// first byte in header is 1h per IPMI V2 spec.
+#define IPMI_FRU_HDR_BYTE_ZERO   1
+#define IPMI_FRU_INTERNAL_OFFSET offsetof(struct common_header, internal_offset)
+#define IPMI_FRU_CHASSIS_OFFSET  offsetof(struct common_header, chassis_offset)
+#define IPMI_FRU_BOARD_OFFSET    offsetof(struct common_header, board_offset)
+#define IPMI_FRU_PRODUCT_OFFSET  offsetof(struct common_header, product_offset)
+#define IPMI_FRU_MULTI_OFFSET    offsetof(struct common_header, multi_offset)
+#define IPMI_FRU_HDR_CRC_OFFSET  offsetof(struct common_header, crc)
+#define IPMI_EIGHT_BYTES         8
+
+#endif
-- 
2.6.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH ipmi-fru-parser 11/11] Include sdbus header in frup.c
  2015-11-08  3:58 [PATCH ipmi-fru-parser 00/11] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
                   ` (9 preceding siblings ...)
  2015-11-08  3:59 ` [PATCH ipmi-fru-parser 10/11] Merging IPMI FRU writer and parser OpenBMC Patches
@ 2015-11-08  3:59 ` OpenBMC Patches
  10 siblings, 0 replies; 12+ messages in thread
From: OpenBMC Patches @ 2015-11-08  3:59 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 frup.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/frup.c b/frup.c
index 2d8cc3b..96fd2ae 100644
--- a/frup.c
+++ b/frup.c
@@ -44,6 +44,7 @@
 #include <string.h>
 #include <time.h>
 #include <ctype.h>
+#include <systemd/sd-bus.h>
 
 #define uint8_t unsigned char
 #define uint32_t unsigned int
@@ -80,13 +81,6 @@ return -1; \
 #define OPENBMC_VPD_KEY_LEN                            64
 #define OPENBMC_VPD_VAL_LEN                            512
 
-
-extern "C"
-{
-int sd_bus_message_append (void*, const char*, ...);
-typedef struct sd_bus_message sd_bus_message;
-};
-
 struct ipmi_fru_field
 {
   uint8_t type_length_field[IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX];
-- 
2.6.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2015-11-08  3:59 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-08  3:58 [PATCH ipmi-fru-parser 00/11] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
2015-11-08  3:58 ` [PATCH ipmi-fru-parser 01/11] Checking in the basic IPMI FRU Parser Library. Parser has just enough intelligence to parse Chassis, Board & Product info areas. No support for multi-record in this version. This parser is a stripped down version of the parser in the FreeIPMI distribution OpenBMC Patches
2015-11-08  3:58 ` [PATCH ipmi-fru-parser 02/11] IPMI FRU Parser Interface OpenBMC Patches
2015-11-08  3:59 ` [PATCH ipmi-fru-parser 03/11] Added interface function to parse wirte fru data message into a dictionary OpenBMC Patches
2015-11-08  3:59 ` [PATCH ipmi-fru-parser 04/11] Format string change in sd_bus_message_append OpenBMC Patches
2015-11-08  3:59 ` [PATCH ipmi-fru-parser 05/11] Added interface parse_fru_area to parse a specific area and populate a name/value dictionary OpenBMC Patches
2015-11-08  3:59 ` [PATCH ipmi-fru-parser 06/11] Removing depency in Makefile on the systemd library OpenBMC Patches
2015-11-08  3:59 ` [PATCH ipmi-fru-parser 07/11] Internal parser functions expect the area buffer to point to location where language code. Hence advance 2 bytes on the areabuf(to go past the fmt/version and len fields) and pass it to the area specific parser routines. Also fix bugs on offset/len calcuation OpenBMC Patches
2015-11-08  3:59 ` [PATCH ipmi-fru-parser 08/11] Fix format string in sd_bus_message_append to add as dictionary. Store manufacturing time in ISO8601 format OpenBMC Patches
2015-11-08  3:59 ` [PATCH ipmi-fru-parser 09/11] Construct format string for sd_bus_message_append based on field type encoding OpenBMC Patches
2015-11-08  3:59 ` [PATCH ipmi-fru-parser 10/11] Merging IPMI FRU writer and parser OpenBMC Patches
2015-11-08  3:59 ` [PATCH ipmi-fru-parser 11/11] Include sdbus header in frup.c OpenBMC Patches

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.