int hservice_ipmi_msg(uint8_t netfn, uint8_t cmd, void *tx_buf, size_t tx_size, void *rx_buf, size_t *rx_size) { struct timeval start, now, delta; struct pollfd pollfds[1]; static long seq; size_t size; int rc, fd; size = be64toh(*rx_size); fd = open(ipmi_devnode, O_RDWR); if (fd < 0) { pr_log(LOG_WARNING, "IPMI: Failed to open IPMI device %s: %m", ipmi_devnode); return -1; } seq++; pr_debug("IPMI: sending %zd bytes (netfn 0x%02x, cmd 0x%02x)", tx_size, netfn, cmd); rc = ipmi_send(fd, netfn, cmd, seq, tx_buf, tx_size); if (rc) { pr_log(LOG_WARNING, "IPMI: send failed"); goto out; } gettimeofday(&start, NULL); pollfds[0].fd = fd; pollfds[0].events = POLLIN; for (;;) { long rx_seq; int timeout; gettimeofday(&now, NULL); timersub(&now, &start, &delta); timeout = ipmi_timeout_ms - ((delta.tv_sec * 1000) + (delta.tv_usec / 1000)); if (timeout < 0) timeout = 0; rc = poll(pollfds, 1, timeout); if (rc < 0) { pr_log(LOG_ERR, "IPMI: poll(%s) failed: %m", ipmi_devnode); break; } if (rc == 0) { pr_log(LOG_WARNING, "IPMI: response timeout (>%dms)", ipmi_timeout_ms); rc = -1; break; } rc = ipmi_recv(fd, &netfn, &cmd, &rx_seq, rx_buf, &size); if (rc) break; if (seq != rx_seq) { pr_log(LOG_NOTICE, "IPMI: out-of-sequence reply: %ld, " "expected %ld. Dropping message.", rx_seq, seq); continue; } pr_debug("IPMI: received %zd bytes", tx_size); *rx_size = be64toh(size); rc = 0; break; } out: close(fd); return rc; }
int ipmi_transaction(struct ipmi *ipmi, uint8_t netfn, uint8_t cmd, uint8_t *req_buf, uint16_t req_len, uint8_t *resp_buf, uint16_t *resp_len, int timeout_ms) { struct timeval start, now, delta; struct pollfd pollfds[1]; struct flock lock; int expired_ms, rc; memset(&lock, 0, sizeof(lock)); lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; rc = fcntl(ipmi->fd, F_SETLKW, &lock); if (rc == -1) { pb_log("IPMI: error locking IPMI device: %m\n"); return rc; } rc = ipmi_send(ipmi, netfn, cmd, req_buf, req_len); if (rc) goto out; pollfds[0].fd = ipmi->fd; pollfds[0].events = POLLIN; gettimeofday(&start, NULL); expired_ms = 0; for (;;) { uint8_t resp_netfn, resp_cmd; long seq; rc = poll(pollfds, 1, timeout_ms - expired_ms); if (rc < 0) { pb_log("IPMI: poll() error %m"); break; } if (rc == 0) { pb_log("IPMI: timeout waiting for response " "(netfn %d, cmd %d)\n", netfn, cmd); rc = -1; break; } if (!(pollfds[0].revents & POLLIN)) { pb_log("IPMI: unexpected fd status from poll?\n"); rc = -1; break; } rc = ipmi_recv(ipmi, &resp_netfn, &resp_cmd, &seq, resp_buf, resp_len); if (rc) break; if (seq != ipmi->seq - 1) { pb_log("IPMI: out-of-sequence reply: " "exp %ld, got %ld\n", ipmi->seq, seq); if (timeout_ms) { gettimeofday(&now, NULL); timersub(&now, &start, &delta); expired_ms = (delta.tv_sec * 1000) + (delta.tv_usec / 1000); if (expired_ms >= timeout_ms) { rc = -1; break; } } } else { pb_debug("IPMI: netfn(%x->%x), cmd(%x->%x)\n", netfn, resp_netfn, cmd, resp_cmd); rc = 0; goto out; } } out: lock.l_type = F_UNLCK; if (fcntl(ipmi->fd, F_SETLKW, &lock) == -1) pb_log("IPMI: error unlocking IPMI device: %m\n"); return rc ? -1 : 0; }