10 #include <sys/types.h>
12 #include <linux/ipmi.h>
15 #include <talloc/talloc.h>
24 static const char *ipmi_devnode = "/dev/ipmi0";
26 bool ipmi_bootdev_is_valid(int x)
29 case IPMI_BOOTDEV_NONE:
30 case IPMI_BOOTDEV_NETWORK:
31 case IPMI_BOOTDEV_DISK:
32 case IPMI_BOOTDEV_SAFE:
33 case IPMI_BOOTDEV_CDROM:
34 case IPMI_BOOTDEV_SETUP:
41 static int ipmi_send(struct ipmi *ipmi, uint8_t netfn, uint8_t cmd,
42 uint8_t *buf, uint16_t len)
44 struct ipmi_system_interface_addr addr;
48 memset(&addr, 0, sizeof(addr));
49 addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
50 addr.channel = IPMI_BMC_CHANNEL;
52 memset(&req, 0, sizeof(req));
53 req.addr = (unsigned char *)&addr;
54 req.addr_len = sizeof(addr);
56 req.msgid = ipmi->seq++;
59 req.msg.data_len = len;
60 req.msg.netfn = netfn;
63 rc = ioctl(ipmi->fd, IPMICTL_SEND_COMMAND, &req);
65 pb_log("IPMI: send (netfn %d, cmd %d, %d bytes) failed: %m\n",
73 static int ipmi_recv(struct ipmi *ipmi, uint8_t *netfn, uint8_t *cmd,
74 long *seq, uint8_t *buf, uint16_t *len)
76 struct ipmi_recv recv;
77 struct ipmi_addr addr;
80 recv.addr = (unsigned char *)&addr;
81 recv.addr_len = sizeof(addr);
83 recv.msg.data_len = *len;
85 rc = ioctl(ipmi->fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv);
86 if (rc < 0 && errno != EMSGSIZE) {
87 pb_log("IPMI: recv (%d bytes) failed: %m\n", *len);
89 } else if (rc < 0 && errno == EMSGSIZE) {
90 pb_debug("IPMI: truncated message (netfn %d, cmd %d, "
91 "size %d), continuing anyway\n",
92 recv.msg.netfn, recv.msg.cmd, *len);
95 *netfn = recv.msg.netfn;
98 *len = recv.msg.data_len;
103 int ipmi_transaction(struct ipmi *ipmi, uint8_t netfn, uint8_t cmd,
104 uint8_t *req_buf, uint16_t req_len,
105 uint8_t *resp_buf, uint16_t *resp_len,
108 struct timeval start, now, delta;
109 struct pollfd pollfds[1];
113 memset(&lock, 0, sizeof(lock));
114 lock.l_type = F_WRLCK;
115 lock.l_whence = SEEK_SET;
116 rc = fcntl(ipmi->fd, F_SETLKW, &lock);
118 pb_log("IPMI: error locking IPMI device: %m\n");
122 rc = ipmi_send(ipmi, netfn, cmd, req_buf, req_len);
126 pollfds[0].fd = ipmi->fd;
127 pollfds[0].events = POLLIN;
129 gettimeofday(&start, NULL);
133 uint8_t resp_netfn, resp_cmd;
136 rc = poll(pollfds, 1, timeout_ms - expired_ms);
139 pb_log("IPMI: poll() error %m");
143 pb_log("IPMI: timeout waiting for response "
144 "(netfn %d, cmd %d)\n", netfn, cmd);
149 if (!(pollfds[0].revents & POLLIN)) {
150 pb_log("IPMI: unexpected fd status from poll?\n");
155 rc = ipmi_recv(ipmi, &resp_netfn, &resp_cmd, &seq,
160 if (seq != ipmi->seq - 1) {
161 pb_log("IPMI: out-of-sequence reply: "
162 "exp %ld, got %ld\n",
166 gettimeofday(&now, NULL);
167 timersub(&now, &start, &delta);
168 expired_ms = (delta.tv_sec * 1000) +
169 (delta.tv_usec / 1000);
171 if (expired_ms >= timeout_ms) {
177 pb_debug("IPMI: netfn(%x->%x), cmd(%x->%x)\n",
178 netfn, resp_netfn, cmd, resp_cmd);
185 lock.l_type = F_UNLCK;
186 if (fcntl(ipmi->fd, F_SETLKW, &lock) == -1)
187 pb_log("IPMI: error unlocking IPMI device: %m\n");
191 static int ipmi_destroy(void *p)
193 struct ipmi *ipmi = p;
198 struct ipmi *ipmi_open(void *ctx)
203 fd = open(ipmi_devnode, O_RDWR);
205 pb_log("IPMI: can't open IPMI device %s: %m\n", ipmi_devnode);
209 ipmi = talloc(ctx, struct ipmi);
213 talloc_set_destructor(ipmi, ipmi_destroy);
218 bool ipmi_present(void)
220 return !access(ipmi_devnode, R_OK | W_OK);