int
ipmi_openipmi_ctx_set_driver_device (ipmi_openipmi_ctx_t ctx, const char *driver_device)
{
  if (!ctx || ctx->magic != IPMI_OPENIPMI_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_openipmi_ctx_errormsg (ctx), ipmi_openipmi_ctx_errnum (ctx));
      return (-1);
    }

  if (!driver_device)
    {
      OPENIPMI_SET_ERRNUM (ctx, IPMI_OPENIPMI_ERR_PARAMETERS);
      return (-1);
    }

  free (ctx->driver_device);
  ctx->driver_device = NULL;

  if (!(ctx->driver_device = strdup (driver_device)))
    {
      OPENIPMI_SET_ERRNUM (ctx, IPMI_OPENIPMI_ERR_OUT_OF_MEMORY);
      return (-1);
    }

  ctx->errnum = IPMI_OPENIPMI_ERR_SUCCESS;
  return (0);
}
int
api_openipmi_cmd_ipmb (ipmi_ctx_t ctx,
                       fiid_obj_t obj_cmd_rq,
                       fiid_obj_t obj_cmd_rs)
{
  assert (ctx
          && ctx->magic == IPMI_CTX_MAGIC
          && ctx->type == IPMI_DEVICE_OPENIPMI
          && fiid_obj_valid (obj_cmd_rq)
          && fiid_obj_packet_valid (obj_cmd_rq) == 1
          && fiid_obj_valid (obj_cmd_rs));

  if (ipmi_openipmi_cmd_ipmb (ctx->io.inband.openipmi_ctx,
                              ctx->target.channel_number,
                              ctx->target.rs_addr,
                              ctx->target.lun,
                              ctx->target.net_fn,
                              obj_cmd_rq,
                              obj_cmd_rs) < 0)
    {
      API_OPENIPMI_ERRNUM_TO_API_ERRNUM (ctx, ipmi_openipmi_ctx_errnum (ctx->io.inband.openipmi_ctx));
      return (-1);
    }

  return (0);
}
int
ipmi_openipmi_ctx_io_init (ipmi_openipmi_ctx_t ctx)
{
  unsigned int addr = IPMI_SLAVE_ADDRESS_BMC;
  char *driver_device;
  int flags;

  if (!ctx || ctx->magic != IPMI_OPENIPMI_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_openipmi_ctx_errormsg (ctx), ipmi_openipmi_ctx_errnum (ctx));
      return (-1);
    }

  if (ctx->io_init)
    goto out;

  if (ctx->driver_device)
    driver_device = ctx->driver_device;
  else
    driver_device = IPMI_OPENIPMI_DRIVER_DEVICE_DEFAULT;

  if ((ctx->device_fd = open (driver_device,
                              O_RDWR)) < 0)
    {
      OPENIPMI_ERRNO_TO_OPENIPMI_ERRNUM (ctx, errno);
      goto cleanup;
    }

  flags = fcntl(ctx->device_fd, F_GETFD);
  if (flags < 0)
    {
      OPENIPMI_ERRNO_TO_OPENIPMI_ERRNUM (ctx, errno);
      goto cleanup;
    }
  flags |= FD_CLOEXEC;
  if (fcntl(ctx->device_fd, F_SETFD, flags) < 0)
    {
      OPENIPMI_ERRNO_TO_OPENIPMI_ERRNUM (ctx, errno);
      goto cleanup;
    }

  if (ioctl (ctx->device_fd,
             IPMICTL_SET_MY_ADDRESS_CMD,
             &addr) < 0)
    {
      OPENIPMI_ERRNO_TO_OPENIPMI_ERRNUM (ctx, errno);
      goto cleanup;
    }

  ctx->io_init = 1;
 out:
  ctx->errnum = IPMI_OPENIPMI_ERR_SUCCESS;
  return (0);

 cleanup:
  /* ignore potential error, error path */
  close (ctx->device_fd);
  ctx->device_fd = -1;
  return (-1);
}
int
ipmi_openipmi_cmd_ipmb (ipmi_openipmi_ctx_t ctx,
                        uint8_t channel_number,
                        uint8_t rs_addr,
                        uint8_t lun,
                        uint8_t net_fn,
                        fiid_obj_t obj_cmd_rq,
                        fiid_obj_t obj_cmd_rs)
{
  if (!ctx || ctx->magic != IPMI_OPENIPMI_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_openipmi_ctx_errormsg (ctx), ipmi_openipmi_ctx_errnum (ctx));
      return (-1);
    }

  if (!IPMI_CHANNEL_NUMBER_VALID (channel_number)
      || !IPMI_BMC_LUN_VALID (lun)
      || !IPMI_NET_FN_RQ_VALID (net_fn)
      || !fiid_obj_valid (obj_cmd_rq)
      || !fiid_obj_valid (obj_cmd_rs)
      || fiid_obj_packet_valid (obj_cmd_rq) <= 0)
    {
      OPENIPMI_SET_ERRNUM (ctx, IPMI_OPENIPMI_ERR_PARAMETERS);
      return (-1);
    }

  if (!ctx->io_init)
    {
      OPENIPMI_SET_ERRNUM (ctx, IPMI_OPENIPMI_ERR_IO_NOT_INITIALIZED);
      return (-1);
    }

  if (_openipmi_write (ctx,
                       channel_number,
                       rs_addr,
                       lun,
                       net_fn,
                       obj_cmd_rq,
                       1) < 0)
    return (-1);

  if (_openipmi_read (ctx,
                      obj_cmd_rs) < 0)
    return (-1);

  return (0);
}
int
ipmi_openipmi_ctx_set_flags (ipmi_openipmi_ctx_t ctx, unsigned int flags)
{
  if (!ctx || ctx->magic != IPMI_OPENIPMI_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_openipmi_ctx_errormsg (ctx), ipmi_openipmi_ctx_errnum (ctx));
      return (-1);
    }

  if (flags & ~IPMI_OPENIPMI_FLAGS_MASK)
    {
      OPENIPMI_SET_ERRNUM (ctx, IPMI_OPENIPMI_ERR_PARAMETERS);
      return (-1);
    }

  ctx->flags = flags;
  ctx->errnum = IPMI_OPENIPMI_ERR_SUCCESS;
  return (0);
}
int
ipmi_openipmi_ctx_get_driver_device (ipmi_openipmi_ctx_t ctx, char **driver_device)
{
  if (!ctx || ctx->magic != IPMI_OPENIPMI_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_openipmi_ctx_errormsg (ctx), ipmi_openipmi_ctx_errnum (ctx));
      return (-1);
    }

  if (!driver_device)
    {
      OPENIPMI_SET_ERRNUM (ctx, IPMI_OPENIPMI_ERR_PARAMETERS);
      return (-1);
    }

  *driver_device = ctx->driver_device;
  ctx->errnum = IPMI_OPENIPMI_ERR_SUCCESS;
  return (0);
}
char *
ipmi_openipmi_ctx_errormsg (ipmi_openipmi_ctx_t ctx)
{
  return (ipmi_openipmi_ctx_strerror (ipmi_openipmi_ctx_errnum (ctx)));
}