Exemplo n.º 1
0
int
fill_ipmb_msg_hdr (uint8_t rs_addr,
                   uint8_t net_fn,
                   uint8_t rs_lun,
                   uint8_t rq_addr,
                   uint8_t rq_lun,
                   uint8_t rq_seq,
                   fiid_obj_t obj_ipmb_msg_hdr)
{
  uint8_t checksum_buf[1024];
  int checksum_len;
  uint8_t checksum;

  if (!IPMI_NET_FN_VALID (net_fn)
      || !IPMI_BMC_LUN_VALID (rs_lun)
      || !IPMI_BMC_LUN_VALID (rq_lun)
      || (rq_seq > IPMI_IPMB_REQUESTER_SEQUENCE_NUMBER_MAX)
      || !fiid_obj_valid (obj_ipmb_msg_hdr))
    {
      SET_ERRNO (EINVAL);
      return (-1);
    }

  if (FIID_OBJ_TEMPLATE_COMPARE (obj_ipmb_msg_hdr, tmpl_ipmb_msg_hdr_rq) < 0)
    {
      ERRNO_TRACE (errno);
      return (-1);
    }

  FILL_FIID_OBJ_CLEAR (obj_ipmb_msg_hdr);
  FILL_FIID_OBJ_SET (obj_ipmb_msg_hdr, "rs_addr", rs_addr);
  FILL_FIID_OBJ_SET (obj_ipmb_msg_hdr, "net_fn", net_fn);
  FILL_FIID_OBJ_SET (obj_ipmb_msg_hdr, "rs_lun", rs_lun);

  if ((checksum_len = fiid_obj_get_block (obj_ipmb_msg_hdr,
                                          "rs_addr",
                                          "net_fn",
                                          checksum_buf,
                                          1024)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_hdr);
      return (-1);
    }

  checksum = ipmi_checksum (checksum_buf, checksum_len);
  FILL_FIID_OBJ_SET (obj_ipmb_msg_hdr, "checksum1", checksum);
  FILL_FIID_OBJ_SET (obj_ipmb_msg_hdr, "rq_addr", rq_addr);
  FILL_FIID_OBJ_SET (obj_ipmb_msg_hdr, "rq_lun", rq_lun);
  FILL_FIID_OBJ_SET (obj_ipmb_msg_hdr, "rq_seq", rq_seq);

  return (0);
}
Exemplo n.º 2
0
int
assemble_ipmi_ipmb_msg (fiid_obj_t obj_ipmb_msg_hdr,
                        fiid_obj_t obj_cmd,
                        fiid_obj_t obj_ipmb_msg,
			unsigned int flags)
{
  uint8_t buf[IPMB_MAX_LEN+1];
  unsigned int indx = 0;
  uint8_t *checksum_data_ptr = NULL;
  unsigned int checksum_data_count = 0;
  unsigned int required_len = 0;
  fiid_obj_t obj_ipmb_msg_trlr = NULL;
  uint8_t checksum;
  int len, rv = -1;
  unsigned int flags_mask = 0;

  if (!fiid_obj_valid (obj_ipmb_msg_hdr)
      || !fiid_obj_valid (obj_cmd)
      || !fiid_obj_valid (obj_ipmb_msg)
      || (flags & ~flags_mask))
    {
      SET_ERRNO (EINVAL);
      return (-1);
    }

  if (FIID_OBJ_TEMPLATE_COMPARE (obj_ipmb_msg_hdr, tmpl_ipmb_msg_hdr_rq) < 0)
    {
      ERRNO_TRACE (errno);
      return (-1);
    }
  if (FIID_OBJ_TEMPLATE_COMPARE (obj_ipmb_msg, tmpl_ipmb_msg) < 0)
    {
      ERRNO_TRACE (errno);
      return (-1);
    }

  if (FIID_OBJ_PACKET_VALID (obj_ipmb_msg_hdr) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_hdr);
      return (-1);
    }
  if (FIID_OBJ_PACKET_VALID (obj_cmd) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
      return (-1);
    }

  if ((len = fiid_template_len_bytes (tmpl_ipmb_msg_hdr_rq)) < 0)
    {
      ERRNO_TRACE (errno);
      return (-1);
    }
  required_len += len;

  if ((len = fiid_obj_len_bytes (obj_cmd)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
      return (-1);
    }
  required_len += len;

  if ((len = fiid_template_len_bytes (tmpl_ipmb_msg_trlr)) < 0)
    {
      ERRNO_TRACE (errno);
      return (-1);
    }
  required_len += len;

  if (IPMB_MAX_LEN < required_len)
    {
      SET_ERRNO (EMSGSIZE);
      return (-1);
    }

  memset (buf, '\0', IPMB_MAX_LEN+1);

  if ((len = fiid_obj_get_block (obj_ipmb_msg_hdr,
                                 "rs_addr",
                                 "checksum1",
                                 buf + indx,
                                 IPMB_MAX_LEN - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_hdr);
      goto cleanup;
    }
  indx += len;

  checksum_data_ptr = (buf + indx);

  if ((len = fiid_obj_get_block (obj_ipmb_msg_hdr,
                                 "rq_addr",
                                 "rq_seq",
                                 buf + indx,
                                 IPMB_MAX_LEN - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_hdr);
      goto cleanup;
    }
  indx += len;
  checksum_data_count += len;

  if ((len = fiid_obj_get_all (obj_cmd, buf + indx, IPMB_MAX_LEN - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
      goto cleanup;
    }
  indx += len;
  checksum_data_count += len;

  if (!(obj_ipmb_msg_trlr = fiid_obj_create (tmpl_ipmb_msg_trlr)))
    {
      ERRNO_TRACE (errno);
      goto cleanup;
    }

  checksum = ipmi_checksum (checksum_data_ptr, checksum_data_count);

  if (fiid_obj_set_all (obj_ipmb_msg_trlr, &checksum, sizeof (checksum)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_trlr);
      goto cleanup;
    }

  if ((len = fiid_obj_get_all (obj_ipmb_msg_trlr, buf + indx, IPMB_MAX_LEN - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_trlr);
      goto cleanup;
    }
  indx += len;

  if ((len = fiid_obj_set_all (obj_ipmb_msg, buf, indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg);
      goto cleanup;
    }

  rv = len;
 cleanup:
  fiid_obj_destroy (obj_ipmb_msg_trlr);
  return (rv);
}
Exemplo n.º 3
0
int
assemble_ipmi_lan_pkt (fiid_obj_t obj_rmcp_hdr,
                       fiid_obj_t obj_lan_session_hdr,
                       fiid_obj_t obj_lan_msg_hdr,
                       fiid_obj_t obj_cmd,
                       const void *authentication_code_data,
                       unsigned int authentication_code_data_len,
                       void *pkt,
                       unsigned int pkt_len,
		       unsigned int flags)
{
  uint8_t authentication_type;
  uint64_t val;
  unsigned int indx = 0;
  int required_len;
  void *authentication_code_field_ptr = NULL;
  void *checksum_data_ptr = NULL;
  void *msg_data_ptr = NULL;
  void *ipmi_msg_len_ptr = NULL;
  unsigned int msg_data_count = 0;
  unsigned int checksum_data_count = 0;
  uint8_t ipmi_msg_len;
  fiid_obj_t obj_lan_msg_trlr = NULL;
  uint8_t pwbuf[IPMI_1_5_MAX_PASSWORD_LENGTH];
  uint8_t checksum;
  int len, rv = -1;
  unsigned int flags_mask = 0;

  if (!fiid_obj_valid (obj_rmcp_hdr)
      || !fiid_obj_valid (obj_lan_session_hdr)
      || !fiid_obj_valid (obj_lan_msg_hdr)
      || !fiid_obj_valid (obj_cmd)
      || (authentication_code_data && authentication_code_data_len > IPMI_1_5_MAX_PASSWORD_LENGTH)
      || !pkt
      || (flags & ~flags_mask))
    {
      SET_ERRNO (EINVAL);
      return (-1);
    }

  if (FIID_OBJ_TEMPLATE_COMPARE (obj_rmcp_hdr, tmpl_rmcp_hdr) < 0)
    {
      ERRNO_TRACE (errno);
      return (-1);
    }
  if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_session_hdr, tmpl_lan_session_hdr) < 0)
    {
      ERRNO_TRACE (errno);
      return (-1);
    }
  if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_msg_hdr, tmpl_lan_msg_hdr_rq) < 0)
    {
      ERRNO_TRACE (errno);
      return (-1);
    }

  if (FIID_OBJ_PACKET_VALID (obj_rmcp_hdr) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr);
      return (-1);
    }

  /*
   * ipmi_msg_len is calculated in this function, so we can't use
   * fiid_obj_packet_valid() on obj_lan_session_hdr b/c ipmi_msg_len
   * is probably not set yet.
   */

  if (FIID_OBJ_PACKET_VALID (obj_lan_msg_hdr) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
      return (-1);
    }
  if (FIID_OBJ_PACKET_VALID (obj_cmd) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
      return (-1);
    }

  if (FIID_OBJ_GET (obj_lan_session_hdr,
                    "authentication_type",
                    &val) < 0)
    {
      ERRNO_TRACE (errno);
      return (-1);
    }
  authentication_type = val;

  if (authentication_type != IPMI_AUTHENTICATION_TYPE_NONE
      && authentication_type != IPMI_AUTHENTICATION_TYPE_MD2
      && authentication_type != IPMI_AUTHENTICATION_TYPE_MD5
      && authentication_type != IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY)
    {
      SET_ERRNO (EINVAL);
      return (-1);
    }

  /* no need for overflow checks, handled w/ _ipmi_lan_pkt_rq_min_size check */

  required_len = _ipmi_lan_pkt_rq_min_size (authentication_type, obj_cmd);
  if (pkt_len < required_len)
    {
      SET_ERRNO (EMSGSIZE);
      return (-1);
    }

  memset (pkt, 0, pkt_len);

  if ((len = fiid_obj_get_all (obj_rmcp_hdr, pkt + indx, pkt_len - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr);
      goto cleanup;
    }
  indx += len;

  if ((len = fiid_obj_get_block (obj_lan_session_hdr,
                                 "authentication_type",
                                 "session_id",
                                 pkt + indx,
                                 pkt_len - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
      goto cleanup;
    }

  indx += len;

  /* authentication_code generated last.  Save pointers for later calculation */
  if (authentication_type != IPMI_AUTHENTICATION_TYPE_NONE)
    {
      authentication_code_field_ptr = (pkt + indx);
      indx += IPMI_1_5_MAX_PASSWORD_LENGTH;
    }

  ipmi_msg_len_ptr = (pkt + indx);
  if ((len = fiid_template_field_len_bytes (tmpl_lan_session_hdr, "ipmi_msg_len")) < 0)
    {
      ERRNO_TRACE (errno);
      goto cleanup;
    }
  if (len != 1)
    {
      SET_ERRNO (EINVAL);
      goto cleanup;
    }
  indx += len;

  msg_data_ptr = (pkt + indx);

  if ((len = fiid_obj_get_block (obj_lan_msg_hdr,
                                 "rs_addr",
                                 "checksum1",
                                 pkt + indx,
                                 pkt_len - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
      goto cleanup;
    }
  indx += len;
  msg_data_count += len;

  checksum_data_ptr = (pkt + indx);

  if ((len = fiid_obj_get_block (obj_lan_msg_hdr,
                                 "rq_addr",
                                 "rq_seq",
                                 pkt + indx,
                                 pkt_len - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr);
      goto cleanup;
    }
  indx += len;
  msg_data_count += len;
  checksum_data_count += len;

  if ((len = fiid_obj_get_all (obj_cmd, pkt + indx, pkt_len - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd);
      goto cleanup;
    }
  indx += len;
  msg_data_count += len;
  checksum_data_count += len;

  if (!(obj_lan_msg_trlr = fiid_obj_create (tmpl_lan_msg_trlr)))
    {
      ERRNO_TRACE (errno);
      goto cleanup;
    }

  checksum = ipmi_checksum (checksum_data_ptr, checksum_data_count);

  if (fiid_obj_set_all (obj_lan_msg_trlr, &checksum, sizeof (checksum)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr);
      goto cleanup;
    }

  if ((len = fiid_obj_get_all (obj_lan_msg_trlr, pkt + indx, pkt_len - indx)) < 0)
    {
      FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr);
      goto cleanup;
    }
  indx += len;
  msg_data_count += len;

  /* ipmi_msg_len done after message length is computed */
  ipmi_msg_len = msg_data_count;
  memcpy (ipmi_msg_len_ptr,
          &ipmi_msg_len,
          sizeof (ipmi_msg_len));

  /* Auth code must be done last, some authentication like md2 and md5
   * require all fields, including checksums, to be calculated
   * beforehand
   */
  if (authentication_type != IPMI_AUTHENTICATION_TYPE_NONE)
    {
      int authentication_len;

      memset (pwbuf, '\0', IPMI_1_5_MAX_PASSWORD_LENGTH);

      if ((authentication_len = fiid_obj_field_len_bytes (obj_lan_session_hdr,
                                                          "authentication_code")) < 0)
        {
          FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
          goto cleanup;
        }

      if (authentication_len)
        {
          if (fiid_obj_get_data (obj_lan_session_hdr,
                                 "authentication_code",
                                 pwbuf,
                                 IPMI_1_5_MAX_PASSWORD_LENGTH) < 0)
            {
              FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
              goto cleanup;
            }

          memcpy (authentication_code_field_ptr,
                  pwbuf,
                  IPMI_1_5_MAX_PASSWORD_LENGTH);
        }
      else
        {
          if (authentication_code_data)
            memcpy (pwbuf,
                    authentication_code_data,
                    authentication_code_data_len);

          if (authentication_type == IPMI_AUTHENTICATION_TYPE_STRAIGHT_PASSWORD_KEY)
            {
              memcpy (authentication_code_field_ptr,
                      pwbuf,
                      IPMI_1_5_MAX_PASSWORD_LENGTH);
            }
          else /* IPMI_AUTHENTICATION_TYPE_MD2 || IPMI_AUTHENTICATION_TYPE_MD5 */
            {
              uint8_t session_id_buf[1024];
              uint8_t session_sequence_number_buf[1024];
              int session_id_len, session_sequence_number_len;

              if ((session_id_len = fiid_obj_get_data (obj_lan_session_hdr,
                                                       "session_id",
                                                       session_id_buf,
                                                       1024)) < 0)
                {
                  FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
                  goto cleanup;
                }

              if ((session_sequence_number_len = fiid_obj_get_data (obj_lan_session_hdr,
                                                                    "session_sequence_number",
                                                                    session_sequence_number_buf,
                                                                    1024)) < 0)
                {
                  FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr);
                  goto cleanup;
                }

              if (authentication_type == IPMI_AUTHENTICATION_TYPE_MD2)
                {
                  md2_t ctx;
                  uint8_t digest[MD2_DIGEST_LENGTH];

                  assert (IPMI_1_5_MAX_PASSWORD_LENGTH == MD2_DIGEST_LENGTH);

                  md2_init (&ctx);
                  md2_update_data (&ctx, pwbuf, IPMI_1_5_MAX_PASSWORD_LENGTH);
                  md2_update_data (&ctx, session_id_buf, session_id_len);
                  md2_update_data (&ctx, msg_data_ptr, msg_data_count);
                  md2_update_data (&ctx, session_sequence_number_buf, session_sequence_number_len);
                  md2_update_data (&ctx, pwbuf, IPMI_1_5_MAX_PASSWORD_LENGTH);
                  md2_finish (&ctx, digest, MD2_DIGEST_LENGTH);
                  md2_init (&ctx);

                  memcpy (authentication_code_field_ptr, digest, IPMI_1_5_MAX_PASSWORD_LENGTH);
                  secure_memset (digest, '\0', MD2_DIGEST_LENGTH);
                }
              else if (authentication_type == IPMI_AUTHENTICATION_TYPE_MD5)
                {
                  md5_t ctx;
                  uint8_t digest[MD5_DIGEST_LENGTH];

                  assert (IPMI_1_5_MAX_PASSWORD_LENGTH == MD5_DIGEST_LENGTH);

                  md5_init (&ctx);
                  md5_update_data (&ctx, pwbuf, IPMI_1_5_MAX_PASSWORD_LENGTH);
                  md5_update_data (&ctx, session_id_buf, session_id_len);
                  md5_update_data (&ctx, msg_data_ptr, msg_data_count);
                  md5_update_data (&ctx, session_sequence_number_buf, session_sequence_number_len);
                  md5_update_data (&ctx, pwbuf, IPMI_1_5_MAX_PASSWORD_LENGTH);
                  md5_finish (&ctx, digest, MD5_DIGEST_LENGTH);
                  md5_init (&ctx);

                  memcpy (authentication_code_field_ptr, digest, IPMI_1_5_MAX_PASSWORD_LENGTH);
                  secure_memset (digest, '\0', MD5_DIGEST_LENGTH);
                }
            }
        }
    }

  if (indx > INT_MAX)
    {
      SET_ERRNO (EMSGSIZE);
      goto cleanup;
    }

  rv = indx;
 cleanup:
  if (rv < 0)
    secure_memset (pkt, '\0', pkt_len);
  fiid_obj_destroy (obj_lan_msg_trlr);
  secure_memset (pwbuf, '\0', IPMI_1_5_MAX_PASSWORD_LENGTH);
  return (rv);
}
Exemplo n.º 4
0
int
ipmi_sdr_cache_open (ipmi_sdr_ctx_t ctx,
                     ipmi_ctx_t ipmi_ctx,
                     const char *filename)
{
  uint8_t sdr_version;
  uint16_t record_count;
  uint32_t most_recent_addition_timestamp, most_recent_erase_timestamp;
  char sdr_version_buf;
  char sdr_cache_magic_buf[4];
  char sdr_cache_version_buf[4];
  char record_count_buf[2];
  char most_recent_addition_timestamp_buf[4];
  char most_recent_erase_timestamp_buf[4];
  struct stat stat_buf;

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (!filename)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_UNINITIALIZED)
    {
      if (ctx->operation == IPMI_SDR_OPERATION_READ_CACHE)
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_ALREADY_INITIALIZED);
      else
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR);
      return (-1);
    }

  if (stat (filename, &stat_buf) < 0)
    {
      SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
      goto cleanup;
    }

  /* File Size must be atleast magic_buf + file_version_buf +
   * sdr_version_buf + record_count_buf +
   * most_recent_addition_timestamp_buf +
   * most_recent_erase_timestamp-buf in size.
   */

  ctx->file_size = stat_buf.st_size;
  if (ctx->file_size < (4 + 4 + 1 + 2 + 4 + 4))
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
      goto cleanup;
    }

  if ((ctx->fd = open (filename, O_RDONLY)) < 0)
    {
      SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
      goto cleanup;
    }

  ctx->sdr_cache = (uint8_t *)mmap (NULL,
                                    ctx->file_size,
                                    PROT_READ,
                                    MAP_PRIVATE,
                                    ctx->fd,
                                    0);
  if (!ctx->sdr_cache || ctx->sdr_cache == ((void *) -1))
    {
      ERRNO_TRACE (errno);
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
      goto cleanup;
    }

  memcpy (sdr_cache_magic_buf, ctx->sdr_cache + ctx->records_start_offset, 4);
  ctx->records_start_offset += 4;
  memcpy (sdr_cache_version_buf, ctx->sdr_cache + ctx->records_start_offset, 4);
  ctx->records_start_offset += 4;
  memcpy (&sdr_version_buf, ctx->sdr_cache + ctx->records_start_offset, 1);
  ctx->records_start_offset += 1;
  memcpy (record_count_buf, ctx->sdr_cache + ctx->records_start_offset, 2);
  ctx->records_start_offset += 2;
  memcpy (most_recent_addition_timestamp_buf, ctx->sdr_cache + ctx->records_start_offset, 4);
  ctx->records_start_offset += 4;
  memcpy (most_recent_erase_timestamp_buf, ctx->sdr_cache + ctx->records_start_offset, 4);
  ctx->records_start_offset += 4;

  if ((uint8_t)sdr_cache_magic_buf[0] != IPMI_SDR_CACHE_FILE_MAGIC_0
      || (uint8_t)sdr_cache_magic_buf[1] != IPMI_SDR_CACHE_FILE_MAGIC_1
      || (uint8_t)sdr_cache_magic_buf[2] != IPMI_SDR_CACHE_FILE_MAGIC_2
      || (uint8_t)sdr_cache_magic_buf[3] != IPMI_SDR_CACHE_FILE_MAGIC_3)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
      goto cleanup;
    }

  if (((uint8_t)sdr_cache_version_buf[0] != IPMI_SDR_CACHE_FILE_VERSION_1_0
       || (uint8_t)sdr_cache_version_buf[1] != IPMI_SDR_CACHE_FILE_VERSION_1_1
       || (uint8_t)sdr_cache_version_buf[2] != IPMI_SDR_CACHE_FILE_VERSION_1_2
       || (uint8_t)sdr_cache_version_buf[3] != IPMI_SDR_CACHE_FILE_VERSION_1_3)
      && ((uint8_t)sdr_cache_version_buf[0] != IPMI_SDR_CACHE_FILE_VERSION_1_2_0
	  || (uint8_t)sdr_cache_version_buf[1] != IPMI_SDR_CACHE_FILE_VERSION_1_2_1
	  || (uint8_t)sdr_cache_version_buf[2] != IPMI_SDR_CACHE_FILE_VERSION_1_2_2
	  || (uint8_t)sdr_cache_version_buf[3] != IPMI_SDR_CACHE_FILE_VERSION_1_2_3))
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
      goto cleanup;
    }

  ctx->sdr_version = (uint8_t)sdr_version_buf;
  ctx->record_count = ((uint16_t)record_count_buf[0] & 0xFF);
  ctx->record_count |= ((uint16_t)record_count_buf[1] & 0xFF) << 8;
  ctx->most_recent_addition_timestamp = ((uint32_t)most_recent_addition_timestamp_buf[0] & 0xFF);
  ctx->most_recent_addition_timestamp |= ((uint32_t)most_recent_addition_timestamp_buf[1] & 0xFF) << 8;
  ctx->most_recent_addition_timestamp |= ((uint32_t)most_recent_addition_timestamp_buf[2] & 0xFF) << 16;
  ctx->most_recent_addition_timestamp |= ((uint32_t)most_recent_addition_timestamp_buf[3] & 0xFF) << 24;
  ctx->most_recent_erase_timestamp = ((uint32_t)most_recent_erase_timestamp_buf[0] & 0xFF);
  ctx->most_recent_erase_timestamp |= ((uint32_t)most_recent_erase_timestamp_buf[1] & 0xFF) << 8;
  ctx->most_recent_erase_timestamp |= ((uint32_t)most_recent_erase_timestamp_buf[2] & 0xFF) << 16;
  ctx->most_recent_erase_timestamp |= ((uint32_t)most_recent_erase_timestamp_buf[3] & 0xFF) << 24;

  if (ipmi_ctx)
    {
      if (sdr_info (ctx,
		    ipmi_ctx,
		    &sdr_version,
		    &record_count,
		    &most_recent_addition_timestamp,
		    &most_recent_erase_timestamp) < 0)
	goto cleanup;

      if (ctx->sdr_version != sdr_version
	  || ctx->most_recent_addition_timestamp != most_recent_addition_timestamp
	  || ctx->most_recent_erase_timestamp != most_recent_erase_timestamp)
	{
	  SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_OUT_OF_DATE);
	  goto cleanup;
	}
    }

  if ((uint8_t)sdr_cache_version_buf[0] == IPMI_SDR_CACHE_FILE_VERSION_1_2_0
      && (uint8_t)sdr_cache_version_buf[1] == IPMI_SDR_CACHE_FILE_VERSION_1_2_1
      && (uint8_t)sdr_cache_version_buf[2] == IPMI_SDR_CACHE_FILE_VERSION_1_2_2
      && (uint8_t)sdr_cache_version_buf[3] == IPMI_SDR_CACHE_FILE_VERSION_1_2_3)
    {
      uint8_t header_checksum_buf[512];
      unsigned int header_checksum_buf_len = 0;
      uint8_t header_checksum, header_checksum_cache;
      uint8_t trailer_checksum, trailer_checksum_cache;
      char total_bytes_written_buf[4];
      unsigned int total_bytes_written;
      unsigned int header_bytes_len;
      unsigned int trailer_bytes_len;

      /* File Size must be atleast magic_buf + file_version_buf +
       * sdr_version_buf + record_count_buf +
       * most_recent_addition_timestamp_buf +
       * most_recent_erase_timestamp-buf + header_checksum + trailer
       * bytes written + trailer records checksum.
       */
      
      header_bytes_len = 4 + 4 + 1 + 2 + 4 + 4 + 1;
      trailer_bytes_len = 4 + 1;

      if (ctx->file_size < (header_bytes_len + trailer_bytes_len))
	{
	  SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
	  goto cleanup;
	}

      memcpy (&header_checksum_cache, ctx->sdr_cache + ctx->records_start_offset, 1);
      ctx->records_start_offset += 1;

      memcpy(&header_checksum_buf[header_checksum_buf_len], sdr_cache_magic_buf, 4);
      header_checksum_buf_len += 4;
      memcpy(&header_checksum_buf[header_checksum_buf_len], sdr_cache_version_buf, 4);
      header_checksum_buf_len += 4;
      memcpy(&header_checksum_buf[header_checksum_buf_len], &sdr_version_buf, 1);
      header_checksum_buf_len += 1;
      memcpy(&header_checksum_buf[header_checksum_buf_len], record_count_buf, 2);
      header_checksum_buf_len += 2;
      memcpy(&header_checksum_buf[header_checksum_buf_len], most_recent_addition_timestamp_buf, 4);
      header_checksum_buf_len += 4;
      memcpy(&header_checksum_buf[header_checksum_buf_len], most_recent_erase_timestamp_buf, 4);
      header_checksum_buf_len += 4;
      
      header_checksum = ipmi_checksum (header_checksum_buf, header_checksum_buf_len);
      if (header_checksum != header_checksum_cache)
	{
	  SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
	  goto cleanup;
	}

      /* total_bytes_written is written before checksum */
      /* checksum of records is last byte written */
      memcpy (total_bytes_written_buf, ctx->sdr_cache + ctx->file_size - 5, 4);
      memcpy (&trailer_checksum_cache, ctx->sdr_cache + ctx->file_size - 1, 1);

      total_bytes_written = ((uint32_t)total_bytes_written_buf[0] & 0xFF);
      total_bytes_written |= ((uint32_t)total_bytes_written_buf[1] & 0xFF) << 8;
      total_bytes_written |= ((uint32_t)total_bytes_written_buf[2] & 0xFF) << 16;
      total_bytes_written |= ((uint32_t)total_bytes_written_buf[3] & 0xFF) << 24;

      if (total_bytes_written != ctx->file_size)
	{
	  SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
	  goto cleanup;
	}

      /* -1 for checksum */
      trailer_checksum = ipmi_checksum (ctx->sdr_cache + ctx->records_start_offset,
					total_bytes_written - ctx->records_start_offset - 1);

      if (trailer_checksum != trailer_checksum_cache)
	{
	  SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_INVALID);
	  goto cleanup;
	}

      ctx->records_end_offset = ctx->file_size - trailer_bytes_len;
    }
  else /* (uint8_t)sdr_cache_version_buf[0] == IPMI_SDR_CACHE_FILE_VERSION_1_0
	  && (uint8_t)sdr_cache_version_buf[1] == IPMI_SDR_CACHE_FILE_VERSION_1_1
	  && (uint8_t)sdr_cache_version_buf[2] == IPMI_SDR_CACHE_FILE_VERSION_1_2
	  && (uint8_t)sdr_cache_version_buf[3] == IPMI_SDR_CACHE_FILE_VERSION_1_3 */
    ctx->records_end_offset = ctx->file_size;

  _sdr_set_current_offset (ctx, ctx->records_start_offset);
  ctx->operation = IPMI_SDR_OPERATION_READ_CACHE;
  ctx->errnum = IPMI_SDR_ERR_SUCCESS;
  return (0);

 cleanup:
  /* ignore potential error, cleanup path */
  if (ctx->fd >= 0)
    close (ctx->fd);
  /* ignore potential error, cleanup path */
  if (ctx->sdr_cache)
    munmap ((void *)ctx->sdr_cache, ctx->file_size);
  sdr_init_ctx (ctx);
  return (-1);
}
static int
_sdr_cache_header_write (ipmi_sdr_ctx_t ctx,
                         ipmi_ctx_t ipmi_ctx,
                         int fd,
                         unsigned int *total_bytes_written,
                         uint8_t sdr_version,
                         uint16_t record_count,
                         uint32_t most_recent_addition_timestamp,
                         uint32_t most_recent_erase_timestamp)
{
    char sdr_cache_magic_buf[4];
    char sdr_cache_version_buf[4];
    char record_count_buf[2];
    char most_recent_addition_timestamp_buf[4];
    char most_recent_erase_timestamp_buf[4];
    uint8_t header_checksum_buf[512];
    unsigned int header_checksum_buf_len = 0;
    uint8_t header_checksum;
    ssize_t n;

    assert (ctx);
    assert (ctx->magic == IPMI_SDR_CTX_MAGIC);
    assert (ipmi_ctx);
    assert (fd);
    assert (total_bytes_written);

    sdr_cache_magic_buf[0] = IPMI_SDR_CACHE_FILE_MAGIC_0;
    sdr_cache_magic_buf[1] = IPMI_SDR_CACHE_FILE_MAGIC_1;
    sdr_cache_magic_buf[2] = IPMI_SDR_CACHE_FILE_MAGIC_2;
    sdr_cache_magic_buf[3] = IPMI_SDR_CACHE_FILE_MAGIC_3;

    if ((n = fd_write_n (fd, sdr_cache_magic_buf, 4)) < 0)
    {
        SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
        return (-1);
    }
    if (n != 4)
    {
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
        return (-1);
    }
    (*total_bytes_written) += 4;

    memcpy(&header_checksum_buf[header_checksum_buf_len], sdr_cache_magic_buf, 4);
    header_checksum_buf_len += 4;

    sdr_cache_version_buf[0] = IPMI_SDR_CACHE_FILE_VERSION_1_2_0;
    sdr_cache_version_buf[1] = IPMI_SDR_CACHE_FILE_VERSION_1_2_1;
    sdr_cache_version_buf[2] = IPMI_SDR_CACHE_FILE_VERSION_1_2_2;
    sdr_cache_version_buf[3] = IPMI_SDR_CACHE_FILE_VERSION_1_2_3;

    if ((n = fd_write_n (fd, sdr_cache_version_buf, 4)) < 0)
    {
        SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
        return (-1);
    }
    if (n != 4)
    {
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
        return (-1);
    }
    (*total_bytes_written) += 4;

    memcpy(&header_checksum_buf[header_checksum_buf_len], sdr_cache_version_buf, 4);
    header_checksum_buf_len += 4;

    if ((n = fd_write_n (fd, (char *)&sdr_version, 1)) < 0)
    {
        SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
        return (-1);
    }
    if (n != 1)
    {
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
        return (-1);
    }
    (*total_bytes_written) += 1;

    memcpy(&header_checksum_buf[header_checksum_buf_len], &sdr_version, 1);
    header_checksum_buf_len += 1;

    /* Store record count little-endian */
    record_count_buf[0] = (record_count & 0x00FF);
    record_count_buf[1] = (record_count & 0xFF00) >> 8;

    if ((n = fd_write_n (fd, record_count_buf, 2)) < 0)
    {
        SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
        return (-1);
    }
    if (n != 2)
    {
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
        return (-1);
    }
    (*total_bytes_written) += 2;

    memcpy(&header_checksum_buf[header_checksum_buf_len], record_count_buf, 2);
    header_checksum_buf_len += 2;

    /* Store most recent addition timestamp little-endian */
    most_recent_addition_timestamp_buf[0] = (most_recent_addition_timestamp & 0x000000FF);
    most_recent_addition_timestamp_buf[1] = (most_recent_addition_timestamp & 0x0000FF00) >> 8;
    most_recent_addition_timestamp_buf[2] = (most_recent_addition_timestamp & 0x00FF0000) >> 16;
    most_recent_addition_timestamp_buf[3] = (most_recent_addition_timestamp & 0xFF000000) >> 24;

    if ((n = fd_write_n (fd, most_recent_addition_timestamp_buf, 4)) < 0)
    {
        SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
        return (-1);
    }
    if (n != 4)
    {
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
        return (-1);
    }
    (*total_bytes_written) += 4;

    memcpy(&header_checksum_buf[header_checksum_buf_len], most_recent_addition_timestamp_buf, 4);
    header_checksum_buf_len += 4;

    /* Store most recent erase timestamp little-endian */
    most_recent_erase_timestamp_buf[0] = (most_recent_erase_timestamp & 0x000000FF);
    most_recent_erase_timestamp_buf[1] = (most_recent_erase_timestamp & 0x0000FF00) >> 8;
    most_recent_erase_timestamp_buf[2] = (most_recent_erase_timestamp & 0x00FF0000) >> 16;
    most_recent_erase_timestamp_buf[3] = (most_recent_erase_timestamp & 0xFF000000) >> 24;

    if ((n = fd_write_n (fd, most_recent_erase_timestamp_buf, 4)) < 0)
    {
        SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
        return (-1);
    }
    if (n != 4)
    {
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
        return (-1);
    }
    (*total_bytes_written) += 4;

    memcpy(&header_checksum_buf[header_checksum_buf_len], most_recent_erase_timestamp_buf, 4);
    header_checksum_buf_len += 4;

    header_checksum = ipmi_checksum (header_checksum_buf, header_checksum_buf_len);

    if ((n = fd_write_n (fd, (char *)&header_checksum, 1)) < 0)
    {
        SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno);
        return (-1);
    }
    if (n != 1)
    {
        SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_SYSTEM_ERROR);
        return (-1);
    }
    (*total_bytes_written) += 1;

    return (0);
}