int api_inteldcmi_cmd_raw_ipmb (ipmi_ctx_t ctx, const void *buf_rq, unsigned int buf_rq_len, void *buf_rs, unsigned int buf_rs_len) { fiid_obj_t obj_cmd_rq = NULL; fiid_obj_t obj_cmd_rs = NULL; int len, rv = -1; assert (ctx && ctx->magic == IPMI_CTX_MAGIC && ctx->type == IPMI_DEVICE_INTELDCMI && buf_rq && buf_rq_len && buf_rs && buf_rs_len); if (!(obj_cmd_rq = fiid_obj_create (tmpl_inteldcmi_raw))) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } if (!(obj_cmd_rs = fiid_obj_create (tmpl_inteldcmi_raw))) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } if (fiid_obj_set_all (obj_cmd_rq, buf_rq, buf_rq_len) < 0) { API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rq); goto cleanup; } if (api_inteldcmi_cmd_ipmb (ctx, obj_cmd_rq, obj_cmd_rs) < 0) goto cleanup; if ((len = fiid_obj_get_all (obj_cmd_rs, buf_rs, buf_rs_len)) < 0) { API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } rv = len; cleanup: fiid_obj_destroy (obj_cmd_rq); fiid_obj_destroy (obj_cmd_rs); return (rv); }
int32_t Fiid_obj_set_all(fiid_obj_t obj, uint8_t *data, uint32_t data_len) { int32_t rv; assert(fiid_obj_valid(obj) && data && data_len); if ((rv = fiid_obj_set_all(obj, data, data_len)) < 0) ierr_exit("Fiid_obj_set_all: %s", fiid_strerror(fiid_obj_errnum(obj))); return rv; }
int ipmi_sunbmc_cmd (ipmi_sunbmc_ctx_t ctx, uint8_t lun, uint8_t net_fn, fiid_obj_t obj_cmd_rq, fiid_obj_t obj_cmd_rs) { if (!ctx || ctx->magic != IPMI_SUNBMC_CTX_MAGIC) { ERR_TRACE (ipmi_sunbmc_ctx_errormsg (ctx), ipmi_sunbmc_ctx_errnum (ctx)); return (-1); } if (!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) { SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_PARAMETERS); return (-1); } if (!ctx->io_init) { SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_IO_NOT_INITIALIZED); return (-1); } if (ctx->putmsg_intf) { if (_sunbmc_write (ctx, lun, net_fn, obj_cmd_rq) < 0) return (-1); if (_sunbmc_read (ctx, obj_cmd_rs) < 0) return (-1); } else { #if defined(HAVE_SYS_STROPTS_H) struct strioctl istr; bmc_reqrsp_t reqrsp; uint8_t rq_buf_temp[IPMI_SUNBMC_BUFLEN]; uint8_t rq_buf[IPMI_SUNBMC_BUFLEN]; uint8_t rq_cmd; unsigned int rq_buf_len; uint8_t rs_buf[IPMI_SUNBMC_BUFLEN]; int len; memset (&istr, '\0', sizeof (struct strioctl)); memset (&reqrsp, '\0', sizeof (bmc_reqrsp_t)); /* Due to API differences, we need to extract the cmd out of the * request. */ memset (rq_buf_temp, '\0', IPMI_SUNBMC_BUFLEN); if ((len = fiid_obj_get_all (obj_cmd_rq, rq_buf_temp, IPMI_SUNBMC_BUFLEN)) <= 0) { SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_INTERNAL_ERROR); return (-1); } rq_cmd = rq_buf_temp[0]; if (len > 1) { /* -1 b/c of cmd */ memcpy (rq_buf, &rq_buf_temp[1], len - 1); rq_buf_len = len - 1; } else rq_buf_len = 0; reqrsp.req.fn = net_fn; reqrsp.req.lun = lun; reqrsp.req.cmd = rq_cmd; istr.ic_cmd = IOCTL_IPMI_KCS_ACTION; istr.ic_timout = 0; /* spelled 'timout', not a typo */ istr.ic_len = sizeof (struct bmc_reqrsp); istr.ic_dp = (char *)&reqrsp; if (ioctl (ctx->device_fd, I_STR, &istr) < 0) { SUNBMC_ERRNO_TO_SUNBMC_ERRNUM (ctx, errno); return (-1); } rs_buf[0] = reqrsp.rsp.cmd; rs_buf[1] = reqrsp.rsp.ccode; /* -2 b/c of cmd and ccode */ #if 0 /* achu: to remove warnings, IPMI_SUNBMC_BUFLEN > amount uint8_t can hold */ if (reqrsp.rsp.datalength >= (IPMI_SUNBMC_BUFLEN - 2)) reqrsp.rsp.datalength = IPMI_SUNBMC_BUFLEN - 2; #endif /* remove header data stuff in front we don't care about */ if (reqrsp.rsp.datalength > 3) reqrsp.rsp.datalength -= 3; else reqrsp.rsp.datalength = 0; memcpy (rs_buf + 2, reqrsp.rsp.data, reqrsp.rsp.datalength); if (fiid_obj_set_all (obj_cmd_rs, rs_buf, reqrsp.rsp.datalength + 2) < 0) { SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_INTERNAL_ERROR); return (-1); } #else /* !defined(HAVE_SYS_STROPTS_H) */ /* otherwise, device is not supported */ SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_DEVICE_NOT_SUPPORTED); return (-1); #endif /* !defined(HAVE_SYS_STROPTS_H) */ } return (0); }
static int _sunbmc_read (ipmi_sunbmc_ctx_t ctx, fiid_obj_t obj_cmd_rs) { #if defined(HAVE_SYS_STROPTS_H) struct strbuf sbuf; bmc_msg_t *msg = NULL; bmc_rsp_t *rsp = NULL; int flags = 0; uint8_t rs_buf_temp[IPMI_SUNBMC_BUFLEN]; uint8_t rs_buf[IPMI_SUNBMC_BUFLEN]; unsigned int rs_buf_len = 0; #endif /* !defined(HAVE_SYS_STROPTS_H) */ fd_set read_fds; struct timeval tv; int n; assert (ctx); assert (ctx->magic == IPMI_SUNBMC_CTX_MAGIC); assert (ctx->io_init); assert (ctx->putmsg_intf); assert (fiid_obj_valid (obj_cmd_rs)); #if defined(HAVE_SYS_STROPTS_H) memset (&sbuf, '\0', sizeof (struct strbuf)); sbuf.maxlen = IPMI_SUNBMC_BUFLEN; sbuf.buf = (char *)rs_buf_temp; #else /* !defined(HAVE_SYS_STROPTS_H) */ /* otherwise, device is not supported */ SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_DEVICE_NOT_SUPPORTED); return (-1); #endif /* !defined(HAVE_SYS_STROPTS_H) */ FD_ZERO (&read_fds); FD_SET (ctx->device_fd, &read_fds); tv.tv_sec = IPMI_SUNBMC_TIMEOUT; tv.tv_usec = 0; if ((n = select (ctx->device_fd + 1, &read_fds, NULL, NULL, &tv)) < 0) { SUNBMC_ERRNO_TO_SUNBMC_ERRNUM (ctx, errno); return (-1); } if (!n) { /* Could be due to a different error, but we assume a timeout */ SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_DRIVER_TIMEOUT); return (-1); } #if defined(HAVE_SYS_STROPTS_H) if (getmsg (ctx->device_fd, NULL, &sbuf, &flags) < 0) { SUNBMC_ERRNO_TO_SUNBMC_ERRNUM (ctx, errno); return (-1); } msg = (bmc_msg_t *)&(sbuf.buf[0]); if (msg->m_type == BMC_MSG_ERROR) { errno = msg->msg[0]; SUNBMC_ERRNO_TO_SUNBMC_ERRNUM (ctx, errno); return (-1); } if (msg->m_type != BMC_MSG_RESPONSE) { SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_SYSTEM_ERROR); return (-1); } if (msg->m_id != ctx->putmsg_intf_msg_id) { SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_SYSTEM_ERROR); return (-1); } rsp = (bmc_rsp_t *)&(msg->msg[0]); /* Due to API differences, we need to put the cmd/ccode back into * the buffer. */ rs_buf[0] = rsp->cmd; rs_buf_len++; rs_buf[1] = rsp->ccode; rs_buf_len++; memcpy (&(rs_buf[2]), rsp->data, rsp->datalength); rs_buf_len += rsp->datalength; if (fiid_obj_set_all (obj_cmd_rs, rs_buf, rs_buf_len) < 0) { SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_INTERNAL_ERROR); return (-1); } #else /* !defined(HAVE_SYS_STROPTS_H) */ /* otherwise, device is not supported */ SUNBMC_SET_ERRNUM (ctx, IPMI_SUNBMC_ERR_DEVICE_NOT_SUPPORTED); return (-1); #endif /* !defined(HAVE_SYS_STROPTS_H) */ return (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); }
int unassemble_ipmi_ipmb_msg (fiid_obj_t obj_ipmb_msg, fiid_obj_t obj_ipmb_msg_hdr, fiid_obj_t obj_cmd, fiid_obj_t obj_ipmb_msg_trlr, unsigned int flags) { uint8_t buf[IPMB_MAX_LEN+1]; int buf_len, obj_ipmb_msg_trlr_len, len; unsigned int indx = 0; unsigned int ipmb_msg_len; unsigned int flags_mask = (IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK); if (!fiid_obj_valid (obj_ipmb_msg) || !fiid_obj_valid (obj_ipmb_msg_hdr) || !fiid_obj_valid (obj_cmd) || !fiid_obj_valid (obj_ipmb_msg_trlr) || (flags & ~flags_mask)) { SET_ERRNO (EINVAL); return (-1); } if (FIID_OBJ_TEMPLATE_COMPARE (obj_ipmb_msg_hdr, tmpl_ipmb_msg_hdr_rs) < 0) { ERRNO_TRACE (errno); return (-1); } if (FIID_OBJ_TEMPLATE_COMPARE (obj_ipmb_msg_trlr, tmpl_ipmb_msg_trlr) < 0) { ERRNO_TRACE (errno); return (-1); } memset (buf, '\0', IPMB_MAX_LEN+1); if ((buf_len = fiid_obj_get_all (obj_ipmb_msg, buf, IPMB_MAX_LEN)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg); return (-1); } if (fiid_obj_clear (obj_ipmb_msg_hdr) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_hdr); return (-1); } if (fiid_obj_clear (obj_cmd) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd); return (-1); } if (fiid_obj_clear (obj_ipmb_msg_trlr) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_trlr); return (-1); } if ((len = fiid_obj_set_all (obj_ipmb_msg_hdr, buf + indx, buf_len - indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_hdr); return (-1); } indx += len; if (buf_len <= indx) { /* cannot parse packet */ ERR_TRACE ("malformed packet", EINVAL); return (0); } if ((obj_ipmb_msg_trlr_len = fiid_template_len_bytes (tmpl_ipmb_msg_trlr)) < 0) { ERRNO_TRACE (errno); return (-1); } if ((buf_len - indx) <= obj_ipmb_msg_trlr_len) { /* cannot parse packet */ ERR_TRACE ("malformed packet", EINVAL); return (0); } ipmb_msg_len = (buf_len - indx) - obj_ipmb_msg_trlr_len; if ((len = fiid_obj_set_all (obj_cmd, buf + indx, ipmb_msg_len)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd); return (-1); } indx += len; if (buf_len <= indx) { /* cannot parse packet */ ERR_TRACE ("malformed packet", EINVAL); return (0); } if ((len = fiid_obj_set_all (obj_ipmb_msg_trlr, buf + indx, buf_len - indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_trlr); return (-1); } indx += len; if (FIID_OBJ_PACKET_VALID (obj_ipmb_msg_hdr) == 1 && ((flags & IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK) || FIID_OBJ_PACKET_SUFFICIENT (obj_cmd) == 1) && FIID_OBJ_PACKET_VALID (obj_ipmb_msg_trlr) == 1) return (1); return (0); }
static int _openipmi_read (ipmi_openipmi_ctx_t ctx, fiid_obj_t obj_cmd_rs) { uint8_t rs_buf_temp[IPMI_OPENIPMI_BUFLEN]; uint8_t rs_buf[IPMI_OPENIPMI_BUFLEN]; struct ipmi_system_interface_addr rs_addr; struct ipmi_recv rs_packet; fd_set read_fds; struct timeval tv; int n; assert (ctx); assert (ctx->magic == IPMI_OPENIPMI_CTX_MAGIC); assert (fiid_obj_valid (obj_cmd_rs)); rs_packet.addr = (unsigned char *)&rs_addr; rs_packet.addr_len = sizeof (struct ipmi_system_interface_addr); rs_packet.msg.data = rs_buf_temp; rs_packet.msg.data_len = IPMI_OPENIPMI_BUFLEN; FD_ZERO (&read_fds); FD_SET (ctx->device_fd, &read_fds); tv.tv_sec = IPMI_OPENIPMI_TIMEOUT; tv.tv_usec = 0; if ((n = select (ctx->device_fd + 1, &read_fds, NULL, NULL, &tv)) < 0) { OPENIPMI_ERRNO_TO_OPENIPMI_ERRNUM (ctx, errno); return (-1); } if (!n) { /* Could be due to a different error, but we assume a timeout */ OPENIPMI_SET_ERRNUM (ctx, IPMI_OPENIPMI_ERR_DRIVER_TIMEOUT); return (-1); } if (ioctl (ctx->device_fd, IPMICTL_RECEIVE_MSG_TRUNC, &rs_packet) < 0) { OPENIPMI_ERRNO_TO_OPENIPMI_ERRNUM (ctx, errno); return (-1); } /* achu: atleast the completion code should be returned */ if (!rs_packet.msg.data_len) { OPENIPMI_SET_ERRNUM (ctx, IPMI_OPENIPMI_ERR_SYSTEM_ERROR); return (-1); } rs_buf[0] = rs_packet.msg.cmd; /* -1 b/c of cmd */ if (rs_packet.msg.data_len >= (IPMI_OPENIPMI_BUFLEN - 1)) rs_packet.msg.data_len = IPMI_OPENIPMI_BUFLEN - 1; memcpy (rs_buf + 1, rs_buf_temp, rs_packet.msg.data_len); if (fiid_obj_set_all (obj_cmd_rs, rs_buf, rs_packet.msg.data_len + 1) < 0) { OPENIPMI_SET_ERRNUM (ctx, IPMI_OPENIPMI_ERR_INTERNAL_ERROR); return (-1); } return (0); }
int ipmi_dump_rmcp_packet (int fd, const char *prefix, const char *hdr, const char *trlr, const void *pkt, unsigned int pkt_len, fiid_template_t tmpl_cmd) { unsigned int indx = 0; char prefix_buf[IPMI_DEBUG_MAX_PREFIX_LEN]; char *rmcp_hdr = "RMCP Header:\n" "------------"; char *rmcp_cmd = "RMCP Command Data:\n" "------------------"; char *unexpected_hdr = "Unexpected Data:\n" "----------------"; fiid_obj_t obj_rmcp_hdr = NULL; fiid_obj_t obj_cmd = NULL; fiid_obj_t obj_unexpected_data = NULL; int len, rv = -1; if (!pkt || !tmpl_cmd) { SET_ERRNO (EINVAL); return (-1); } if (debug_set_prefix (prefix_buf, IPMI_DEBUG_MAX_PREFIX_LEN, prefix) < 0) { ERRNO_TRACE (errno); return (-1); } if (debug_output_str (fd, prefix_buf, hdr) < 0) { ERRNO_TRACE (errno); return (-1); } /* Dump rmcp header */ if (!(obj_rmcp_hdr = fiid_obj_create (tmpl_rmcp_hdr))) { ERRNO_TRACE (errno); goto cleanup; } if ((len = fiid_obj_set_all (obj_rmcp_hdr, pkt + indx, pkt_len - indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr); goto cleanup; } indx += len; if (ipmi_obj_dump (fd, prefix, rmcp_hdr, NULL, obj_rmcp_hdr) < 0) { ERRNO_TRACE (errno); goto cleanup; } if (pkt_len <= indx) { rv = 0; goto cleanup; } /* Dump command data */ if (!(obj_cmd = fiid_obj_create (tmpl_cmd))) { ERRNO_TRACE (errno); goto cleanup; } if ((len = fiid_obj_set_all (obj_cmd, pkt + indx, pkt_len - indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd); goto cleanup; } indx += len; if (ipmi_obj_dump (fd, prefix, rmcp_cmd, NULL, obj_cmd) < 0) { ERRNO_TRACE (errno); goto cleanup; } /* Dump unexpected stuff */ if ((pkt_len - indx) > 0) { if (!(obj_unexpected_data = fiid_obj_create (tmpl_unexpected_data))) { ERRNO_TRACE (errno); goto cleanup; } if ((len = fiid_obj_set_all (obj_unexpected_data, pkt + indx, pkt_len - indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_unexpected_data); goto cleanup; } indx += len; if (ipmi_obj_dump (fd, prefix, unexpected_hdr, NULL, obj_unexpected_data) < 0) { ERRNO_TRACE (errno); goto cleanup; } } if (debug_output_str (fd, prefix_buf, trlr) < 0) { ERRNO_TRACE (errno); goto cleanup; } #if WITH_RAWDUMPS /* For those vendors that get confused when they see the nice output * and want the hex output */ if (ipmi_dump_hex (fd, prefix, hdr, trlr, pkt, pkt_len) < 0) { ERRNO_TRACE (errno); goto cleanup; } #endif rv = 0; cleanup: fiid_obj_destroy (obj_rmcp_hdr); fiid_obj_destroy (obj_cmd); fiid_obj_destroy (obj_unexpected_data); return (rv); }
/* return (1) - is oem intel node manager, fully parsed * return (0) - is not oem intel node manager * return (-1) - error */ int ipmi_sdr_oem_parse_intel_node_manager (ipmi_sdr_ctx_t ctx, const void *sdr_record, unsigned int sdr_record_len, uint8_t *nm_device_slave_address, uint8_t *sensor_owner_lun, uint8_t *channel_number, uint8_t *nm_health_event_sensor_number, uint8_t *nm_exception_event_sensor_number, uint8_t *nm_operational_capabilities_sensor_number, uint8_t *nm_alert_threshold_exceeded_sensor_number) { uint8_t sdr_record_buf[IPMI_SDR_MAX_RECORD_LENGTH]; int sdr_record_buf_len; fiid_obj_t obj_oem_record = NULL; int expected_record_len; void *sdr_record_to_use; unsigned int sdr_record_len_to_use; uint64_t val; int rv = -1; if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC) { ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx)); return (-1); } if (!sdr_record || !sdr_record_len) { if (ctx->operation == IPMI_SDR_OPERATION_READ_CACHE && !sdr_record && !sdr_record_len) { if ((sdr_record_buf_len = ipmi_sdr_cache_record_read (ctx, sdr_record_buf, IPMI_SDR_MAX_RECORD_LENGTH)) < 0) { SDR_SET_INTERNAL_ERRNUM (ctx); return (-1); } sdr_record_to_use = sdr_record_buf; sdr_record_len_to_use = sdr_record_buf_len; } else { SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS); return (-1); } } else { sdr_record_to_use = (void *)sdr_record; sdr_record_len_to_use = sdr_record_len; } if ((expected_record_len = fiid_template_len_bytes (tmpl_sdr_oem_intel_node_manager_record)) < 0) { SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno); goto cleanup; } if (sdr_record_len_to_use < expected_record_len) { rv = 0; goto cleanup; } if (!(obj_oem_record = fiid_obj_create (tmpl_sdr_oem_intel_node_manager_record))) { SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno); goto cleanup; } if (fiid_obj_set_all (obj_oem_record, sdr_record_to_use, expected_record_len) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record); goto cleanup; } /* achu: Node Manager documentation states that OEM ID in the * SDR record should be Intel's, but I've seen motherboards w/o * it, so don't bother checking. */ if (FIID_OBJ_GET (obj_oem_record, "record_subtype", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record); goto cleanup; } if (val != IPMI_SDR_OEM_INTEL_NODE_MANAGER_RECORD_SUBTYPE_NM_DISCOVERY) { rv = 0; goto cleanup; } if (FIID_OBJ_GET (obj_oem_record, "version_number", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record); goto cleanup; } if (val != IPMI_SDR_OEM_INTEL_NODE_MANAGER_DISCOVERY_VERSION) { rv = 0; goto cleanup; } if (nm_device_slave_address) { if (FIID_OBJ_GET (obj_oem_record, "nm_device_slave_address", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record); goto cleanup; } (*nm_device_slave_address) = val; } if (sensor_owner_lun) { if (FIID_OBJ_GET (obj_oem_record, "sensor_owner_lun", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record); goto cleanup; } (*sensor_owner_lun) = val; } if (channel_number) { if (FIID_OBJ_GET (obj_oem_record, "channel_number", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record); goto cleanup; } (*channel_number) = val; } if (nm_health_event_sensor_number) { if (FIID_OBJ_GET (obj_oem_record, "nm_health_event_sensor_number", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record); goto cleanup; } (*nm_health_event_sensor_number) = val; } if (nm_exception_event_sensor_number) { if (FIID_OBJ_GET (obj_oem_record, "nm_exception_event_sensor_number", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record); goto cleanup; } (*nm_exception_event_sensor_number) = val; } if (nm_operational_capabilities_sensor_number) { if (FIID_OBJ_GET (obj_oem_record, "nm_operational_capabilities_sensor_number", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record); goto cleanup; } (*nm_operational_capabilities_sensor_number) = val; } if (nm_alert_threshold_exceeded_sensor_number) { if (FIID_OBJ_GET (obj_oem_record, "nm_alert_threshold_exceeded_sensor_number", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_oem_record); goto cleanup; } (*nm_alert_threshold_exceeded_sensor_number) = val; } sdr_check_read_status (ctx); rv = 1; ctx->errnum = IPMI_SDR_ERR_SUCCESS; cleanup: fiid_obj_destroy (obj_oem_record); return (rv); }
int unassemble_rmcp_pkt (const void *pkt, unsigned int pkt_len, fiid_obj_t obj_rmcp_hdr, fiid_obj_t obj_cmd, unsigned int flags) { unsigned int indx = 0; int len; unsigned int flags_mask = (IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK); if (!pkt || !fiid_obj_valid (obj_rmcp_hdr) || !fiid_obj_valid (obj_cmd) || (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_clear (obj_rmcp_hdr) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr); return (-1); } if (fiid_obj_clear (obj_cmd) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd); return (-1); } if ((len = fiid_obj_set_all (obj_rmcp_hdr, pkt + indx, pkt_len - indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr); return (-1); } indx += len; if (pkt_len <= indx) { /* trace, but don't error out, cannot parse packet */ ERR_TRACE ("malformed packet", EINVAL); return (0); } if ((len = fiid_obj_set_all (obj_cmd, pkt + indx, pkt_len - indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd); return (-1); } indx += len; if (FIID_OBJ_PACKET_VALID (obj_rmcp_hdr) == 1 && ((flags & IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK) || FIID_OBJ_PACKET_SUFFICIENT (obj_cmd) == 1)) return (1); return (0); }
int unassemble_ipmi_lan_pkt (const void *pkt, unsigned int pkt_len, 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, fiid_obj_t obj_lan_msg_trlr, unsigned int flags) { uint8_t authentication_type; unsigned int indx = 0; unsigned int obj_cmd_len; int obj_lan_msg_trlr_len, len; uint64_t val; unsigned int flags_mask = (IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK); if (!pkt || !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) || !fiid_obj_valid (obj_lan_msg_trlr) || (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_rs) < 0) { ERRNO_TRACE (errno); return (-1); } if (FIID_OBJ_TEMPLATE_COMPARE (obj_lan_msg_trlr, tmpl_lan_msg_trlr) < 0) { ERRNO_TRACE (errno); return (-1); } indx = 0; if (fiid_obj_clear (obj_rmcp_hdr) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr); return (-1); } if (fiid_obj_clear (obj_lan_session_hdr) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr); return (-1); } if (fiid_obj_clear (obj_lan_msg_hdr) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr); return (-1); } if (fiid_obj_clear (obj_cmd) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd); return (-1); } if (fiid_obj_clear (obj_lan_msg_trlr) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr); return (-1); } if ((len = fiid_obj_set_all (obj_rmcp_hdr, pkt + indx, pkt_len - indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_rmcp_hdr); return (-1); } indx += len; if (pkt_len <= indx) { /* cannot parse packet */ ERR_TRACE ("malformed packet", EINVAL); return (0); } if ((len = fiid_obj_set_block (obj_lan_session_hdr, "authentication_type", "session_id", pkt + indx, pkt_len - indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr); return (-1); } indx += len; if (FIID_OBJ_GET (obj_lan_session_hdr, "authentication_type", &val) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr); return (-1); } authentication_type = val; if (!IPMI_1_5_AUTHENTICATION_TYPE_VALID (authentication_type)) { /* cannot parse packet */ ERR_TRACE ("malformed packet", EINVAL); return (0); } if (authentication_type != IPMI_AUTHENTICATION_TYPE_NONE) { if ((len = fiid_obj_set_data (obj_lan_session_hdr, "authentication_code", pkt + indx, pkt_len - indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr); return (-1); } indx += len; if (pkt_len <= indx) { /* cannot parse packet */ ERR_TRACE ("malformed packet", EINVAL); return (0); } } if ((len = fiid_obj_set_data (obj_lan_session_hdr, "ipmi_msg_len", pkt + indx, pkt_len - indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_session_hdr); return (-1); } indx += len; if (pkt_len <= indx) { /* cannot parse packet */ ERR_TRACE ("malformed packet", EINVAL); return (0); } if ((len = fiid_obj_set_all (obj_lan_msg_hdr, pkt + indx, pkt_len - indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_hdr); return (-1); } indx += len; if (pkt_len <= indx) { /* cannot parse packet */ ERR_TRACE ("malformed packet", EINVAL); return (0); } if ((obj_lan_msg_trlr_len = fiid_template_len_bytes (tmpl_lan_msg_trlr)) < 0) { ERRNO_TRACE (errno); return (-1); } if ((pkt_len - indx) <= obj_lan_msg_trlr_len) { /* cannot parse packet */ ERR_TRACE ("malformed packet", EINVAL); return (0); } obj_cmd_len = (pkt_len - indx) - obj_lan_msg_trlr_len; if ((len = fiid_obj_set_all (obj_cmd, pkt + indx, obj_cmd_len)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_cmd); return (-1); } indx += len; if (pkt_len <= indx) { /* cannot parse packet */ ERR_TRACE ("malformed packet", EINVAL); return (0); } if ((len = fiid_obj_set_all (obj_lan_msg_trlr, pkt + indx, pkt_len - indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_lan_msg_trlr); return (-1); } indx += len; if (FIID_OBJ_PACKET_VALID (obj_rmcp_hdr) == 1 && FIID_OBJ_PACKET_VALID (obj_lan_session_hdr) == 1 && FIID_OBJ_PACKET_VALID (obj_lan_msg_hdr) == 1 && ((flags & IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK) || FIID_OBJ_PACKET_SUFFICIENT (obj_cmd) == 1) && FIID_OBJ_PACKET_VALID (obj_lan_msg_trlr) == 1) return (1); return (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); }
static int _sdr_cache_get_record (ipmi_sdr_ctx_t ctx, ipmi_ctx_t ipmi_ctx, uint16_t record_id, void *record_buf, unsigned int record_buf_len, uint16_t *reservation_id, uint16_t *next_record_id) { fiid_obj_t obj_cmd_rs = NULL; fiid_obj_t obj_sdr_record_header = NULL; int sdr_record_header_length = 0; int sdr_record_len = 0; unsigned int record_length = 0; int rv = -1; unsigned int bytes_to_read = IPMI_SDR_CACHE_BYTES_TO_READ_START; unsigned int offset_into_record = 0; unsigned int reservation_id_retry_count = 0; uint8_t temp_record_buf[IPMI_SDR_MAX_RECORD_LENGTH]; uint64_t val; assert (ctx); assert (ctx->magic == IPMI_SDR_CTX_MAGIC); assert (ipmi_ctx); assert (record_buf); assert (record_buf_len); assert (reservation_id); assert (next_record_id); if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_sdr_rs))) { SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno); goto cleanup; } if (!(obj_sdr_record_header = fiid_obj_create (tmpl_sdr_record_header))) { SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno); goto cleanup; } if ((sdr_record_header_length = fiid_template_len_bytes (tmpl_sdr_record_header)) < 0) { SDR_ERRNO_TO_SDR_ERRNUM (ctx, errno); goto cleanup; } /* achu: * * Many motherboards now allow you to read the full SDR record, try * that first. If it fails for any reason, bail and try to read via * partial reads. */ reservation_id_retry_count = 0; while (!offset_into_record) { if (ipmi_cmd_get_sdr (ipmi_ctx, *reservation_id, record_id, 0, IPMI_SDR_READ_ENTIRE_RECORD_BYTES_TO_READ, obj_cmd_rs) < 0) { if (ipmi_ctx_errnum (ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE) { uint8_t comp_code; if (FIID_OBJ_GET (obj_cmd_rs, "comp_code", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } comp_code = val; if (comp_code == IPMI_COMP_CODE_RESERVATION_CANCELLED && (reservation_id_retry_count < IPMI_SDR_CACHE_MAX_RESERVATION_ID_RETRY)) { if (_sdr_cache_reservation_id (ctx, ipmi_ctx, reservation_id) < 0) goto cleanup; reservation_id_retry_count++; continue; } } goto partial_read; } if ((sdr_record_len = fiid_obj_get_data (obj_cmd_rs, "record_data", temp_record_buf, IPMI_SDR_MAX_RECORD_LENGTH)) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } /* Assume this is an "IPMI Error", fall through to partial reads */ if (sdr_record_len < sdr_record_header_length) goto partial_read; /* * IPMI Workaround (achu) * * Discovered on Xyratex HB-F8-SRAY * * For some reason reading the entire SDR record (with * IPMI_SDR_READ_ENTIRE_RECORD_BYTES_TO_READ) the response * returns fewer bytes than the actual length of the record. * However, when reading with partial reads things ultimately * succeed. If we notice the length is off, we fall out and do * a partial read. */ if ((((uint8_t)temp_record_buf[IPMI_SDR_RECORD_LENGTH_INDEX]) + IPMI_SDR_RECORD_HEADER_LENGTH) > sdr_record_len) goto partial_read; if (sdr_record_len > record_buf_len) { SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR); goto cleanup; } if (FIID_OBJ_GET (obj_cmd_rs, "next_record_id", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } *next_record_id = val; memcpy (record_buf, temp_record_buf, sdr_record_len); offset_into_record += sdr_record_len; goto out; } partial_read: reservation_id_retry_count = 0; while (!record_length) { uint8_t record_header_buf[IPMI_SDR_MAX_RECORD_LENGTH]; int sdr_record_header_len; if (ipmi_cmd_get_sdr (ipmi_ctx, *reservation_id, record_id, 0, sdr_record_header_length, obj_cmd_rs) < 0) { if (ipmi_ctx_errnum (ipmi_ctx) != IPMI_ERR_BAD_COMPLETION_CODE) { SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR); goto cleanup; } else { uint8_t comp_code; if (FIID_OBJ_GET (obj_cmd_rs, "comp_code", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } comp_code = val; if (comp_code == IPMI_COMP_CODE_RESERVATION_CANCELLED && (reservation_id_retry_count < IPMI_SDR_CACHE_MAX_RESERVATION_ID_RETRY)) { if (_sdr_cache_reservation_id (ctx, ipmi_ctx, reservation_id) < 0) goto cleanup; reservation_id_retry_count++; continue; } SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR); goto cleanup; } } if ((sdr_record_header_len = fiid_obj_get_data (obj_cmd_rs, "record_data", record_header_buf, IPMI_SDR_MAX_RECORD_LENGTH)) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } if (sdr_record_header_len < sdr_record_header_length) { SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR); goto cleanup; } if (fiid_obj_set_all (obj_sdr_record_header, record_header_buf, sdr_record_header_len) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_sdr_record_header); goto cleanup; } if (FIID_OBJ_GET (obj_sdr_record_header, "record_length", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_sdr_record_header); goto cleanup; } if (sdr_record_header_len > record_buf_len) { SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR); goto cleanup; } /* copy header into buf */ memcpy (record_buf, record_header_buf, sdr_record_header_len); offset_into_record += sdr_record_header_len; record_length = val + sdr_record_header_length; } if (record_length > record_buf_len) { SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_INTERNAL_ERROR); goto cleanup; } if (FIID_OBJ_GET (obj_cmd_rs, "next_record_id", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } *next_record_id = val; reservation_id_retry_count = 0; while (offset_into_record < record_length) { int record_data_len; if ((record_length - offset_into_record) < bytes_to_read) bytes_to_read = record_length - offset_into_record; if (ipmi_cmd_get_sdr (ipmi_ctx, *reservation_id, record_id, offset_into_record, bytes_to_read, obj_cmd_rs) < 0) { if (ipmi_ctx_errnum (ipmi_ctx) != IPMI_ERR_BAD_COMPLETION_CODE) { SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR); goto cleanup; } else { uint8_t comp_code; if (FIID_OBJ_GET (obj_cmd_rs, "comp_code", &val) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } comp_code = val; if (comp_code == IPMI_COMP_CODE_RESERVATION_CANCELLED && (reservation_id_retry_count < IPMI_SDR_CACHE_MAX_RESERVATION_ID_RETRY)) { if (_sdr_cache_reservation_id (ctx, ipmi_ctx, reservation_id) < 0) goto cleanup; reservation_id_retry_count++; continue; } else if ((comp_code == IPMI_COMP_CODE_CANNOT_RETURN_REQUESTED_NUMBER_OF_BYTES || comp_code == IPMI_COMP_CODE_UNSPECIFIED_ERROR) && bytes_to_read > sdr_record_header_length) { bytes_to_read -= IPMI_SDR_CACHE_BYTES_TO_READ_DECREMENT; if (bytes_to_read < sdr_record_header_length) bytes_to_read = sdr_record_header_length; continue; } SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_IPMI_ERROR); goto cleanup; } } if ((record_data_len = fiid_obj_get_data (obj_cmd_rs, "record_data", record_buf + offset_into_record, record_buf_len - offset_into_record)) < 0) { SDR_FIID_OBJECT_ERROR_TO_SDR_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } offset_into_record += record_data_len; } out: rv = offset_into_record; cleanup: fiid_obj_destroy (obj_cmd_rs); fiid_obj_destroy (obj_sdr_record_header); return (rv); }
static int _api_ssif_ipmb_recv (ipmi_ctx_t ctx, fiid_obj_t obj_ipmb_msg_hdr_rs, fiid_obj_t obj_ipmb_msg_trlr, fiid_obj_t obj_cmd_rs) { struct ipmi_ctx_target target_save; uint8_t buf[IPMI_MAX_PKT_LEN]; fiid_obj_t obj_ipmb_msg_rs = NULL; fiid_obj_t obj_get_cmd_rs = NULL; int len, ret, rv = -1; unsigned int intf_flags = IPMI_INTERFACE_FLAGS_DEFAULT; assert (ctx && ctx->magic == IPMI_CTX_MAGIC && ctx->type == IPMI_DEVICE_SSIF && fiid_obj_valid (obj_ipmb_msg_hdr_rs) && fiid_obj_valid (obj_ipmb_msg_trlr) && fiid_obj_valid (obj_cmd_rs)); if (ctx->flags & IPMI_FLAGS_NO_LEGAL_CHECK) intf_flags |= IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK; if (!(obj_ipmb_msg_rs = fiid_obj_create (tmpl_ipmb_msg))) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } if (!(obj_get_cmd_rs = fiid_obj_create (tmpl_cmd_get_message_rs))) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } /* get_message will send to the BMC, so clear out target information */ memcpy (&target_save, &ctx->target, sizeof (target_save)); ctx->target.channel_number_is_set = 0; ctx->target.rs_addr_is_set = 0; ret = ipmi_cmd_get_message (ctx, obj_get_cmd_rs); /* restore target info */ memcpy (&ctx->target, &target_save, sizeof (target_save)); if (ret < 0) { if (ipmi_check_completion_code (obj_get_cmd_rs, IPMI_COMP_CODE_GET_MESSAGE_DATA_NOT_AVAILABLE) == 1) API_SET_ERRNUM (ctx, IPMI_ERR_MESSAGE_TIMEOUT); else API_BAD_RESPONSE_TO_API_ERRNUM (ctx, obj_get_cmd_rs); goto cleanup; } if ((len = fiid_obj_get_data (obj_get_cmd_rs, "message_data", buf, IPMI_MAX_PKT_LEN)) < 0) { API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_get_cmd_rs); goto cleanup; } if (fiid_obj_set_all (obj_ipmb_msg_rs, buf, len) < 0) { API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_ipmb_msg_rs); goto cleanup; } if (unassemble_ipmi_ipmb_msg (obj_ipmb_msg_rs, obj_ipmb_msg_hdr_rs, obj_cmd_rs, obj_ipmb_msg_trlr, intf_flags) < 0) { API_ERRNO_TO_API_ERRNUM (ctx, errno); goto cleanup; } rv = 0; cleanup: fiid_obj_destroy (obj_ipmb_msg_rs); fiid_obj_destroy (obj_get_cmd_rs); return (rv); }
int debug_dump_ipmb (int fd, const char *prefix, const uint8_t *ipmb_buf, unsigned int ipmb_buf_len, fiid_template_t tmpl_ipmb_msg_hdr, fiid_template_t tmpl_ipmb_cmd) { char *ipmb_msg_hdr = "IPMB Message Header:\n" "--------------------"; char *ipmb_cmd_hdr = "IPMB Message Data:\n" "------------------"; char *ipmb_msg_trlr_hdr = "IPMB Message Trailer:\n" "---------------------"; char *ipmb_unexpected_hdr = "IPMB Unexpected Data:\n" "---------------------"; fiid_obj_t obj_ipmb_msg_hdr = NULL; fiid_obj_t obj_ipmb_cmd = NULL; fiid_obj_t obj_ipmb_msg_trlr = NULL; fiid_obj_t obj_ipmb_unexpected_data = NULL; int obj_ipmb_msg_trlr_len = 0; unsigned int obj_ipmb_cmd_len = 0; int ipmb_hdr_len = 0; int ipmb_cmd_len = 0; int ipmb_trlr_len = 0; int len; unsigned int ipmb_indx = 0; int rv = -1; assert (ipmb_buf); assert (ipmb_buf_len); assert (tmpl_ipmb_msg_hdr); assert (tmpl_ipmb_cmd); if (!(obj_ipmb_msg_hdr = fiid_obj_create (tmpl_ipmb_msg_hdr))) { ERRNO_TRACE (errno); goto cleanup; } if (!(obj_ipmb_cmd = fiid_obj_create (tmpl_ipmb_cmd))) { ERRNO_TRACE (errno); goto cleanup; } if (!(obj_ipmb_msg_trlr = fiid_obj_create (tmpl_ipmb_msg_trlr))) { ERRNO_TRACE (errno); goto cleanup; } if ((obj_ipmb_msg_trlr_len = fiid_template_len_bytes (tmpl_ipmb_msg_trlr)) < 0) { ERRNO_TRACE (errno); goto cleanup; } if ((ipmb_hdr_len = fiid_obj_set_all (obj_ipmb_msg_hdr, ipmb_buf, ipmb_buf_len)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_hdr); goto cleanup; } ipmb_indx += ipmb_hdr_len; if (ipmi_obj_dump (fd, prefix, ipmb_msg_hdr, NULL, obj_ipmb_msg_hdr) < 0) { ERRNO_TRACE (errno); goto cleanup; } if (ipmb_buf_len <= ipmb_indx) { rv = 0; goto cleanup; } if ((ipmb_buf_len - ipmb_hdr_len) <= obj_ipmb_msg_trlr_len) goto dump_ipmb_extra; obj_ipmb_cmd_len = (ipmb_buf_len - ipmb_hdr_len) - obj_ipmb_msg_trlr_len; if ((ipmb_cmd_len = fiid_obj_set_all (obj_ipmb_cmd, ipmb_buf + ipmb_hdr_len, obj_ipmb_cmd_len)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_cmd); goto cleanup; } ipmb_indx += ipmb_cmd_len; if (ipmi_obj_dump (fd, prefix, ipmb_cmd_hdr, NULL, obj_ipmb_cmd) < 0) { ERRNO_TRACE (errno); goto cleanup; } if (ipmb_buf_len <= ipmb_indx) { rv = 0; goto cleanup; } if ((ipmb_trlr_len = fiid_obj_set_all (obj_ipmb_msg_trlr, ipmb_buf + ipmb_hdr_len + ipmb_cmd_len, (ipmb_buf_len - ipmb_hdr_len - ipmb_cmd_len))) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_msg_trlr); goto cleanup; } ipmb_indx += ipmb_trlr_len; if (ipmi_obj_dump (fd, prefix, ipmb_msg_trlr_hdr, NULL, obj_ipmb_msg_trlr) < 0) { ERRNO_TRACE (errno); goto cleanup; } /* Dump IPMB unexpected stuff */ dump_ipmb_extra: if ((ipmb_buf_len - ipmb_indx) > 0) { if (!(obj_ipmb_unexpected_data = fiid_obj_create (tmpl_unexpected_data))) { ERRNO_TRACE (errno); goto cleanup; } if ((len = fiid_obj_set_all (obj_ipmb_unexpected_data, ipmb_buf + ipmb_indx, ipmb_buf_len - ipmb_indx)) < 0) { FIID_OBJECT_ERROR_TO_ERRNO (obj_ipmb_unexpected_data); goto cleanup; } ipmb_indx += len; if (ipmi_obj_dump (fd, prefix, ipmb_unexpected_hdr, NULL, obj_ipmb_unexpected_data) < 0) { ERRNO_TRACE (errno); goto cleanup; } } rv = 0; cleanup: fiid_obj_destroy (obj_ipmb_msg_hdr); fiid_obj_destroy (obj_ipmb_cmd); fiid_obj_destroy (obj_ipmb_msg_trlr); fiid_obj_destroy (obj_ipmb_unexpected_data); return (rv); }