1 /*
2 * Copyright (c) 2015 IBM Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * 3. Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from this
18 * software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #define _BSD_SOURCE
34
35 #include <sys/file.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <fcntl.h>
39 #include <errno.h>
40 #include <unistd.h>
41 #include <stdbool.h>
42
43 #include <systemd/sd-bus.h>
44 #include <systemd/sd-bus-vtable.h>
45
46 #include <ipmitool/log.h>
47 #include <ipmitool/ipmi.h>
48 #include <ipmitool/ipmi_intf.h>
49
50 static sd_bus *bus;
51 static uint8_t seq;
52 static struct ipmi_rs rsp;
53 static bool reply_received;
54
55 static const char *bus_name = "org.openbmc.HostIpmi.ipmitool";
56 static const char *object_path = "/org/openbmc/HostIpmi/ipmitool";
57 static const char *interface = "org.openbmc.HostIpmi";
58
ipmi_dbus_sendrecv(struct ipmi_intf * intf,struct ipmi_rq * req)59 static struct ipmi_rs *ipmi_dbus_sendrecv(struct ipmi_intf *intf,
60 struct ipmi_rq *req)
61 {
62 sd_bus_message *msg;
63 int rc;
64
65 (void)intf;
66
67 rsp.ccode = 0xff;
68
69 rc = sd_bus_message_new_signal(bus, &msg, object_path,
70 interface, "ReceivedMessage");
71 if (rc < 0) {
72 lprintf(LOG_ERR, "%s: failed to create message: %s\n",
73 __func__, strerror(-rc));
74 goto out;
75 }
76
77 rc = sd_bus_message_append(msg, "yyyy",
78 ++seq,
79 req->msg.netfn,
80 req->msg.lun,
81 req->msg.cmd);
82 if (rc < 0) {
83 lprintf(LOG_ERR, "%s: failed to init bytes\n", __func__);
84 goto out_free;
85 }
86
87 rc = sd_bus_message_append_array(msg, 'y', req->msg.data,
88 req->msg.data_len);
89 if (rc < 0) {
90 lprintf(LOG_ERR, "%s: failed to init body\n", __func__);
91 goto out_free;
92 }
93
94 rc = sd_bus_send(bus, msg, NULL);
95 if (rc < 0) {
96 lprintf(LOG_ERR, "%s: failed to send dbus message\n",
97 __func__);
98 goto out_free;
99 }
100
101 for (reply_received = false; !reply_received;) {
102 rc = sd_bus_wait(bus, -1);
103 sd_bus_process(bus, NULL);
104 }
105
106 out_free:
107 sd_bus_message_unref(msg);
108 out:
109 return &rsp;
110 }
111
ipmi_dbus_method_send_message(sd_bus_message * msg,void * userdata,sd_bus_error * error)112 static int ipmi_dbus_method_send_message(sd_bus_message *msg, void *userdata,
113 sd_bus_error *error)
114 {
115 uint8_t recv_seq, recv_netfn, recv_lun, recv_cmd, recv_cc;
116 const void *data;
117 size_t n;
118 int rc;
119
120 (void)userdata;
121 (void)error;
122
123 rc = sd_bus_message_read(msg, "yyyyy", &recv_seq, &recv_netfn,
124 &recv_lun, &recv_cmd, &recv_cc);
125 if (rc < 0) {
126 lprintf(LOG_ERR, "%s: failed to read reply\n", __func__);
127 goto out;
128 }
129
130 rc = sd_bus_message_read_array(msg, 'y', &data, &n);
131 if (rc < 0) {
132 lprintf(LOG_ERR, "%s: failed to read reply data\n", __func__);
133 goto out;
134 }
135
136 if (n > sizeof(rsp.data)) {
137 lprintf(LOG_ERR, "%s: data too long!\n", __func__);
138 goto out;
139 }
140
141 if (recv_seq == seq) {
142 rsp.ccode = recv_cc;
143 rsp.data_len = n;
144 memcpy(rsp.data, data, rsp.data_len);
145 reply_received = true;
146 }
147
148 out:
149 sd_bus_reply_method_return(msg, "x", 0);
150 return 0;
151 }
152
153 static const sd_bus_vtable dbus_vtable[] = {
154 SD_BUS_VTABLE_START(0),
155 SD_BUS_SIGNAL("ReceivedMessage", "yyyyay", 0),
156 SD_BUS_METHOD("sendMessage", "yyyyyay", "x",
157 ipmi_dbus_method_send_message,
158 SD_BUS_VTABLE_UNPRIVILEGED),
159 SD_BUS_VTABLE_END
160 };
161
ipmi_dbus_setup(struct ipmi_intf * intf)162 static int ipmi_dbus_setup(struct ipmi_intf *intf)
163 {
164 const char *name;
165 int rc;
166
167 rc = sd_bus_default(&bus);
168 if (rc < 0) {
169 lprintf(LOG_ERR, "Can't connect to session bus: %s\n",
170 strerror(-rc));
171 return -1;
172 }
173
174 sd_bus_add_object_vtable(bus, NULL, object_path, interface,
175 dbus_vtable, NULL);
176
177 sd_bus_request_name(bus, bus_name, SD_BUS_NAME_REPLACE_EXISTING);
178
179 sd_bus_flush(bus);
180 sd_bus_get_unique_name(bus, &name);
181 intf->opened = 1;
182
183 return 0;
184 }
185
ipmi_dbus_close(struct ipmi_intf * intf)186 static void ipmi_dbus_close(struct ipmi_intf *intf)
187 {
188 if (intf->opened)
189 sd_bus_close(bus);
190 intf->opened = 0;
191 }
192
193 struct ipmi_intf ipmi_dbus_intf = {
194 .name = "dbus",
195 .desc = "OpenBMC dbus interface",
196 .setup = ipmi_dbus_setup,
197 .close = ipmi_dbus_close,
198 .sendrecv = ipmi_dbus_sendrecv,
199 };
200