blob: 305eec7132917757645be7be64b851e266a6e03b [file] [log] [blame]
Thang Q. Nguyen20c6f952020-12-09 03:28:44 +00001/*
2 * Copyright (c) 2018-2020 Ampere Computing LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * This is a daemon that forwards requests and receive responses from SSIF over
19 * the D-Bus IPMI Interface.
20 *
21 * This daemon is derived from btbridged from https://github.com/openbmc/btbridge.
22 * There is no need to queue messages for SSIF since they should not arrive out
23 * of sequence.
24 * The timer is used as we want to abort 'stuck' commands after an expiry time.
25 * Messages that are received out of order are discarded.
26 */
27
28#include <assert.h>
29#include <errno.h>
30#include <fcntl.h>
31#include <getopt.h>
32#include <limits.h>
33#include <poll.h>
34#include <stdint.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <syslog.h>
39#include <sys/mman.h>
40#include <linux/ioctl.h>
41#include <sys/ioctl.h>
42#include <sys/stat.h>
43#include <sys/timerfd.h>
44#include <time.h>
45#include <unistd.h>
46#include <systemd/sd-bus.h>
47
48static const char *ssif_bmc_device = "/dev/ipmi-ssif-host";
49
50#define PREFIX "SSIF_BRIDGED"
51
52#define SSIF_BMC_PATH ssif_bmc_device
53#define SSIF_BMC_TIMEOUT_SEC 2
54#define SSIF_MAX_REQ_LEN 254
55#define SSIF_MAX_RESP_LEN 254
56
57/* Completion code specifies a command times out */
58#define IPMI_CC_CANNOT_PROVIDE_RESP 0xce
59
60
61#define DBUS_NAME "org.openbmc.HostIpmi"
62#define OBJ_NAME "/org/openbmc/HostIpmi/1"
63
64#define SD_BUS_FD 0
65#define SSIF_FD 1
66#define TIMER_FD 2
67#define TOTAL_FDS 3
68
69#define MSG_OUT(f_, ...) do { \
70 if (verbosity != SSIF_LOG_NONE) { \
71 ssif_log(LOG_INFO, f_, ##__VA_ARGS__); \
72 } \
73} while(0)
74#define MSG_ERR(f_, ...) do { \
75 if (verbosity != SSIF_LOG_NONE) { \
76 ssif_log(LOG_ERR, f_, ##__VA_ARGS__); \
77 } \
78} while(0)
79
80struct ipmi_msg {
81 uint8_t netfn;
82 uint8_t lun;
83 uint8_t seq;
84 uint8_t cmd;
85 uint8_t cc; /* Only used on responses */
86 uint8_t *data;
87 size_t data_len;
88};
89
90struct ssifbridged_context {
91 /* The file descriptors to poll */
92 struct pollfd fds[TOTAL_FDS];
93
94 /* Pointer to sdbus */
95 struct sd_bus *bus;
96
97 /* Tracking variable for a pending message so that if it times out,
98 * we can send a response using the correct lun, netfn and command to
99 * indicate to the host that we timed out waiting for a response
100 */
101 struct ipmi_msg ssif_pending_msg;
102
103 /* Flag to indicate whether we are awaiting a response */
104 int awaiting_response;
105};
106
107static void (*ssif_vlog)(int p, const char *fmt, va_list args);
108static int running = 1;
109static enum {
110 SSIF_LOG_NONE = 0,
111 SSIF_LOG_VERBOSE,
112 SSIF_LOG_DEBUG
113} verbosity;
114
115static void ssif_log_console(int p, const char *fmt, va_list args)
116{
117 struct timespec time;
118 FILE *s = (p < LOG_WARNING) ? stdout : stderr;
119
120 clock_gettime(CLOCK_REALTIME, &time);
121
122 fprintf(s, "[%s %ld.%.9ld] ", PREFIX, time.tv_sec, time.tv_nsec);
123
124 vfprintf(s, fmt, args);
125}
126
127 __attribute__((format(printf, 2, 3)))
128static void ssif_log(int p, const char *fmt, ...)
129{
130 va_list args;
131
132 va_start(args, fmt);
133 ssif_vlog(p, fmt, args);
134 va_end(args);
135}
136
137static struct ipmi_msg *ssif_msg_create(struct ssifbridged_context *context,
138 uint8_t *ssif_data)
139{
140 int len;
141
142 assert(context && ssif_data);
143
144 /*
145 * len here is the length of the array.
146 * Helpfully SSIF doesn't count the length byte
147 */
148 len = ssif_data[0] + 1;
149
150 if (len < 3) {
151 MSG_ERR("Trying to get SSIF message with a short length (%d)\n",
152 len);
153 return NULL;
154 }
155
156 MSG_OUT("Trying to get SSIF message with len (%d)\n", len);
157
158 /* Don't count the lenfn/ln, seq and command */
159 context->ssif_pending_msg.data_len = len - 3;
160 context->ssif_pending_msg.netfn = ssif_data[1] >> 2;
161 context->ssif_pending_msg.lun = ssif_data[1] & 0x3;
162 /* Force sequence field = 0 for SSIF */
163 context->ssif_pending_msg.seq = 0;
164 context->ssif_pending_msg.cmd = ssif_data[2];
165
166 return &context->ssif_pending_msg;
167}
168
169/*
170 * Send request from the SSIF driver
171 */
172static int send_received_message_signal(struct ssifbridged_context *context,
173 struct ipmi_msg *req,
174 uint8_t *data, uint8_t data_len)
175{
176 sd_bus_message *msg = NULL;
177 int r = 0;
178
179 /* Notify sdbus for incoming message */
180 r = sd_bus_message_new_signal(context->bus,
181 &msg,
182 OBJ_NAME,
183 DBUS_NAME,
184 "ReceivedMessage");
185 if (r < 0) {
186 MSG_ERR("Failed to create signal: %s\n", strerror(-r));
187 return r;
188 }
189
190 r = sd_bus_message_append(msg, "yyyy",
191 req->seq,
192 req->netfn,
193 req->lun,
194 req->cmd);
195 if (r < 0) {
196 MSG_ERR("Couldn't append to signal: %s\n", strerror(-r));
197 return r;
198 }
199
200 r = sd_bus_message_append_array(msg, 'y', data, data_len);
201 if (r < 0) {
202 MSG_ERR("Couldn't append array to signal: %s\n", strerror(-r));
203 sd_bus_message_unref(msg);
204 return r;
205 }
206
207 MSG_OUT("Sending dbus signal with seq 0x%02x, netfn 0x%02x, "
208 "lun 0x%02x, cmd 0x%02x\n",
209 req->seq,
210 req->netfn,
211 req->lun,
212 req->cmd);
213
214 if (verbosity == SSIF_LOG_DEBUG) {
215 int i;
216 for (i = 0; i < req->data_len; i++) {
217 if (i % 8 == 0) {
218 if (i)
219 printf("\n");
220 MSG_OUT("\t");
221 }
222 printf("0x%02x ", data[i + 3]);
223 }
224 if (req->data_len)
225 printf("\n");
226 }
227
228 r = sd_bus_send(context->bus, msg, NULL);
229 if (r < 0) {
230 MSG_ERR("Couldn't emit dbus signal: %s\n", strerror(-r));
231 return r;
232 }
233
234 sd_bus_message_unref(msg);
235
236 return r;
237}
238
239/*
240 * Send a response on the SSIF driver
241 */
242static int ssif_send_response(struct ssifbridged_context *context,
243 struct ipmi_msg *ssif_resp_msg)
244{
245 uint8_t data[SSIF_MAX_RESP_LEN] = { 0 };
246 int r = 0;
247 int len = 0;
248
249 assert(context);
250
251 if (!ssif_resp_msg)
252 return -EINVAL;
253
254 /* netfn/lun + cmd + cc = 3 */
255 data[0] = ssif_resp_msg->data_len + 3;
256
257 /* Copy response message to data buffer */
258 if (ssif_resp_msg->data_len)
259 memcpy(data + 4, ssif_resp_msg->data, ssif_resp_msg->data_len);
260
261 /* Prepare Header */
262 data[1] = (ssif_resp_msg->netfn << 2) |
263 (ssif_resp_msg->lun & 0x3);
264 data[2] = ssif_resp_msg->cmd;
265 data[3] = ssif_resp_msg->cc;
266 if (ssif_resp_msg->data_len > sizeof(data) - 4) {
267 MSG_ERR("Response message size (%zu) too big, truncating\n",
268 ssif_resp_msg->data_len);
269 ssif_resp_msg->data_len = sizeof(data) - 4;
270 }
271
272 /* Write data kernel space via system calls */
273 len = write(context->fds[SSIF_FD].fd, data, data[0] + 1);
274
275 if (len < 0) {
276 MSG_ERR("Failed to write to driver (ret: %d, errno: %d)\n",
277 len,
278 errno);
279 r = -errno;
280 } else if (len != data[0] + 1) {
281 MSG_ERR("Possible short write to %s, desired len: %d, "
282 "written len: %d\n",
283 SSIF_BMC_PATH,
284 data[0] + 1,
285 len);
286 r = -EINVAL;
287 } else {
288 MSG_OUT("Successfully wrote %d of %d bytes to %s\n",
289 len,
290 data[0] + 1,
291 SSIF_BMC_PATH);
292 }
293
294 return r;
295}
296
297static int method_send_message(sd_bus_message *msg,
298 void *userdata,
299 sd_bus_error *ret_error)
300{
301 struct ssifbridged_context *context;
302 sd_bus_message* resp_msg = NULL;
303 struct ipmi_msg ssif_resp_msg;
304 int r = 1;
305
306 context = (struct ssifbridged_context *)userdata;
307 if (!context) {
308 sd_bus_error_set_const(ret_error,
309 "org.openbmc.error",
310 "Internal error");
311 return -EINVAL;
312 }
313
314 r = sd_bus_message_new_method_return(msg, &resp_msg);
315 if (r < 0) {
316 MSG_ERR("Failed to create method response (ret: %d)\n", r);
317 return r;
318 }
319
320 if (!context->awaiting_response) {
321 /* We are not expecting a response at this time */
322 MSG_ERR("Response message received when in wrong state. "
323 "Discarding\n");
324 r = -EBUSY;
325 } else {
326 uint8_t *data;
327 size_t data_sz;
328 uint8_t netfn, lun, seq, cmd, cc;
329 struct itimerspec ts;
330
331 context->awaiting_response = 0;
332
333 r = sd_bus_message_read(msg, "yyyyy",
334 &seq,
335 &netfn,
336 &lun,
337 &cmd,
338 &cc);
339 if (r < 0) {
340 MSG_ERR("Couldn't parse leading bytes of message: %s\n",
341 strerror(-r));
342 sd_bus_error_set_const(ret_error,
343 "org.openbmc.error",
344 "Bad message");
345 r = -EINVAL;
346 goto done;
347 }
348 r = sd_bus_message_read_array(msg, 'y',
349 (const void **)&data,
350 &data_sz);
351 if (r < 0) {
352 MSG_ERR("Couldn't parse data bytes of message: %s\n",
353 strerror(-r));
354 sd_bus_error_set_const(ret_error,
355 "org.openbmc.error",
356 "Bad message data");
357 r = -EINVAL;
358 goto done;
359 }
360
361 MSG_OUT("Received a dbus response for msg with seq 0x%02x\n",
362 seq);
363
364 ssif_resp_msg.netfn = netfn;
365 ssif_resp_msg.lun = lun;
366 ssif_resp_msg.seq = seq;
367 ssif_resp_msg.cmd = cmd;
368 ssif_resp_msg.cc = cc;
369 ssif_resp_msg.data_len = data_sz;
370 /* Because we've ref'ed the msg, don't need to memcpy data */
371 ssif_resp_msg.data = data;
372
373 /* Clear the timer */
374 ts.it_interval.tv_sec = 0;
375 ts.it_interval.tv_nsec = 0;
376 ts.it_value.tv_sec = 0;
377 ts.it_value.tv_nsec = 0;
378 r = timerfd_settime(context->fds[TIMER_FD].fd,
379 TFD_TIMER_ABSTIME,
380 &ts,
381 NULL);
382
383 if (r < 0) {
384 MSG_ERR("Failed to clear timer\n");
385 }
386
387 r = ssif_send_response(context, &ssif_resp_msg);
388 }
389
390done:
391 r = sd_bus_message_append(resp_msg, "x", r);
392 if (r < 0) {
393 MSG_ERR("Failed to add result to method (ret: %d)\n", r);
394 }
395
396 r = sd_bus_send(context->bus, resp_msg, NULL);
397 if (r < 0) {
398 MSG_ERR("Failed to send response (ret: %d)\n", r);
399 }
400
401 return r;
402}
403
404static int dispatch_timer(struct ssifbridged_context *context)
405{
406 int r = 0;
407
408 if (context->fds[TIMER_FD].revents & POLLIN) {
409 if(!context->awaiting_response) {
410 /* Got a timeout but not expecting a response */
411 MSG_ERR("Timeout but no pending message\n");
412 } else {
413 struct itimerspec ts;
414
415 /* Clear the timer */
416 ts.it_interval.tv_sec = 0;
417 ts.it_interval.tv_nsec = 0;
418 ts.it_value.tv_sec = 0;
419 ts.it_value.tv_nsec = 0;
420 r = timerfd_settime(context->fds[TIMER_FD].fd,
421 TFD_TIMER_ABSTIME,
422 &ts,
423 NULL);
424 if (r < 0) {
425 MSG_ERR("Failed to clear timer\n");
426 }
427
428 MSG_ERR("Timing out message\n");
429
430 /* Add one to the netfn - response netfn is always
431 * request netfn + 1
432 */
433 context->ssif_pending_msg.netfn += 1;
434 context->ssif_pending_msg.cc =
435 IPMI_CC_CANNOT_PROVIDE_RESP;
436 context->ssif_pending_msg.data = NULL;
437 context->ssif_pending_msg.data_len = 0;
438
439 r = ssif_send_response(context,
440 &context->ssif_pending_msg);
441 if (r < 0) {
442 MSG_ERR("Failed to send timeout message "
443 "(ret: %d, errno: %d)\n",
444 r,
445 errno);
446 }
447
448 context->awaiting_response = 0;
449 }
450 }
451
452 return r;
453}
454
455static int dispatch_sd_bus(struct ssifbridged_context *context)
456{
457 int r = 0;
458 if (context->fds[SD_BUS_FD].revents) {
459 r = sd_bus_process(context->bus, NULL);
460 if (r > 0)
461 MSG_OUT("Processed %d dbus events\n", r);
462 }
463
464 return r;
465}
466
467static int dispatch_ssif(struct ssifbridged_context *context)
468{
469 int r = 0;
470
471 assert(context);
472
473 if (context->fds[SSIF_FD].revents & POLLIN) {
474 /* We have received data on the driver */
475 struct itimerspec ts;
476 struct ipmi_msg *req;
477 uint8_t data[SSIF_MAX_REQ_LEN] = { 0 };
478
479 r = read(context->fds[SSIF_FD].fd, data, sizeof(data));
480 if (r < 0) {
481 MSG_ERR("Couldn't read from ssif: %s\n", strerror(-r));
482 return r;
483 }
484 if (r < data[0] + 1) {
485 MSG_ERR("Short read from ssif (%d vs %d)\n",
486 r,
487 data[1] + 2);
488 r = 0;
489 return r;
490 }
491
492 /* Check if response is still awaiting */
493 if (context->awaiting_response) {
494 MSG_ERR("Received SSIF message while awaiting response."
495 " Discarding\n");
496 } else {
497 /* Get SSIF request message that sent from
498 * kernel space
499 */
500 req = ssif_msg_create(context, data);
501 context->awaiting_response = 1;
502
503 if (!req) {
504 MSG_ERR("Can not create request\n");
505 r = -ENOMEM;
506 return r;
507 }
508
509 /* Set up the timer. We do this before sending
510 * the signal to avoid a race condition with
511 * the response
512 */
513 ts.it_interval.tv_sec = 0;
514 ts.it_interval.tv_nsec = 0;
515 ts.it_value.tv_nsec = 0;
516 ts.it_value.tv_sec = SSIF_BMC_TIMEOUT_SEC;
517 r = timerfd_settime(context->fds[TIMER_FD].fd,
518 0,
519 &ts,
520 NULL);
521 if (r < 0)
522 MSG_ERR("Failed to set timer (ret: %d, "
523 "errno: %d)\n",
524 r,
525 errno);
526
527 r = send_received_message_signal(context,
528 req,
529 data + 3,
530 req->data_len);
531 if (r < 0) {
532 MSG_ERR("Failed to send Received Message "
533 "signal (ret: %d)\n",
534 r);
535 }
536 }
537 }
538
539 return r;
540}
541
542static void usage(const char *name)
543{
544 fprintf(stderr, "\
545 Usage %s [--v[v] | --syslog] [-d <DEVICE>]\n\
546 --v Be verbose\n\
547 --vv Be verbose and dump entire messages\n\
548 -s, --syslog Log output to syslog (pointless without --verbose)\n\
549 -d, --device <DEVICE> use <DEVICE> file. Default is '%s'\n\n",
550 name, ssif_bmc_device);
551}
552
553static const sd_bus_vtable ipmid_vtable[] = {
554 SD_BUS_VTABLE_START(0),
555 SD_BUS_METHOD("sendMessage",
556 "yyyyyay",
557 "x",
558 &method_send_message,
559 SD_BUS_VTABLE_UNPRIVILEGED),
560 SD_BUS_SIGNAL("ReceivedMessage",
561 "yyyyay",
562 0),
563 SD_BUS_VTABLE_END
564};
565
566int main(int argc, char *argv[]) {
567 struct ssifbridged_context *context;
568 const char *name = argv[0];
569 int opt, polled, r;
570
571 static const struct option long_options[] = {
572 { "device", required_argument, NULL, 'd' },
573 { "v", no_argument, (int *)&verbosity, SSIF_LOG_VERBOSE },
574 { "vv", no_argument, (int *)&verbosity, SSIF_LOG_DEBUG },
575 { "syslog", no_argument, 0, 's' },
576 { 0, 0, 0, 0 }
577 };
578
579 context = calloc(1, sizeof(*context));
580 if (context == NULL) {
581 MSG_ERR("Failed to allocate memory\n");
582 exit(EXIT_FAILURE);
583 }
584
585 ssif_vlog = &ssif_log_console;
586 while ((opt = getopt_long(argc, argv, "", long_options, NULL)) != -1) {
587 switch (opt) {
588 case 0:
589 break;
590 case 'd':
591 ssif_bmc_device = optarg;
592 break;
593 case 's':
594 /* Avoid a double openlog() */
595 if (ssif_vlog != &vsyslog) {
596 openlog(PREFIX, LOG_ODELAY, LOG_DAEMON);
597 ssif_vlog = &vsyslog;
598 }
599 break;
600 default:
601 usage(name);
602 exit(EXIT_FAILURE);
603 }
604 }
605
606 if (verbosity == SSIF_LOG_VERBOSE)
607 MSG_OUT("Verbose logging\n");
608
609 if (verbosity == SSIF_LOG_DEBUG)
610 MSG_OUT("Debug logging\n");
611
612 MSG_OUT("Starting\n");
613 r = sd_bus_default_system(&context->bus);
614 if (r < 0) {
615 MSG_ERR("Failed to connect to system bus: %s\n", strerror(-r));
616 goto error;
617 }
618
619 MSG_OUT("Registering dbus methods/signals\n");
620 r = sd_bus_add_object_vtable(context->bus,
621 NULL,
622 OBJ_NAME,
623 DBUS_NAME,
624 ipmid_vtable,
625 context);
626 if (r < 0) {
627 MSG_ERR("Failed to issue method call: %s\n", strerror(-r));
628 goto deregister_sdbus;
629 }
630
631 MSG_OUT("Requesting dbus name: %s\n", DBUS_NAME);
632 r = sd_bus_request_name(context->bus, DBUS_NAME,
633 SD_BUS_NAME_ALLOW_REPLACEMENT | SD_BUS_NAME_REPLACE_EXISTING);
634 if (r < 0) {
635 MSG_ERR("Failed to acquire service name: %s\n", strerror(-r));
636 goto deregister_sdbus;
637 }
638
639 MSG_OUT("Getting dbus file descriptors\n");
640 context->fds[SD_BUS_FD].fd = sd_bus_get_fd(context->bus);
641 if (context->fds[SD_BUS_FD].fd < 0) {
642 r = -errno;
643 MSG_OUT("Couldn't get the bus file descriptor: %s\n",
644 strerror(errno));
645 goto deregister_sdbus;
646 }
647
648 MSG_OUT("Opening %s\n", SSIF_BMC_PATH);
649 context->fds[SSIF_FD].fd = open(SSIF_BMC_PATH, O_RDWR | O_NONBLOCK);
650 if (context->fds[SSIF_FD].fd < 0) {
651 r = -errno;
652 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
653 SSIF_BMC_PATH,
654 strerror(errno));
655 goto free_sdbus_fd;
656 }
657
658 MSG_OUT("Creating timer fd\n");
659 context->fds[TIMER_FD].fd = timerfd_create(CLOCK_MONOTONIC, 0);
660 if (context->fds[TIMER_FD].fd < 0) {
661 r = -errno;
662 MSG_ERR("Couldn't create timer fd: %s\n", strerror(errno));
663 goto free_ssif_fd;
664 }
665 context->fds[SD_BUS_FD].events = POLLIN;
666 context->fds[SSIF_FD].events = POLLIN;
667 context->fds[TIMER_FD].events = POLLIN;
668
669 MSG_OUT("Entering polling loop\n");
670
671 while (running) {
672 polled = poll(context->fds, TOTAL_FDS, -1);
673 if (polled == 0)
674 continue;
675 if (polled < 0) {
676 r = -errno;
677 MSG_ERR("Error from poll(): %s\n",
678 strerror(errno));
679 goto finish;
680 }
681 r = dispatch_sd_bus(context);
682 if (r < 0) {
683 MSG_ERR("Error handling dbus event: %s\n",
684 strerror(-r));
685 goto finish;
686 }
687 r = dispatch_ssif(context);
688 if (r < 0) {
689 MSG_ERR("Error handling SSIF event: %s\n",
690 strerror(-r));
691 goto finish;
692 }
693 r = dispatch_timer(context);
694 if (r < 0) {
695 MSG_ERR("Error handling timer event: %s\n",
696 strerror(-r));
697 goto finish;
698 }
699 }
700
701finish:
702 close(context->fds[TIMER_FD].fd);
703free_ssif_fd:
704 close(context->fds[SSIF_FD].fd);
705free_sdbus_fd:
706 close(context->fds[SD_BUS_FD].fd);
707deregister_sdbus:
708 sd_bus_unref(context->bus);
709error:
710 free(context);
711
712 return r;
713}