1069e132eSJeremy Kerr /*
2069e132eSJeremy Kerr * Copyright (c) 2015 IBM Corporation
3069e132eSJeremy Kerr * All rights reserved.
4069e132eSJeremy Kerr *
5069e132eSJeremy Kerr * Redistribution and use in source and binary forms, with or without
6069e132eSJeremy Kerr * modification, are permitted provided that the following conditions
7069e132eSJeremy Kerr * are met:
8069e132eSJeremy Kerr *
9069e132eSJeremy Kerr * 1. Redistributions of source code must retain the above copyright notice,
10069e132eSJeremy Kerr * this list of conditions and the following disclaimer.
11069e132eSJeremy Kerr *
12069e132eSJeremy Kerr * 2. Redistributions in binary form must reproduce the above copyright notice,
13069e132eSJeremy Kerr * this list of conditions and the following disclaimer in the documentation
14069e132eSJeremy Kerr * and/or other materials provided with the distribution.
15069e132eSJeremy Kerr *
16069e132eSJeremy Kerr * 3. Neither the name of the copyright holder nor the names of its
17069e132eSJeremy Kerr * contributors may be used to endorse or promote products derived from this
18069e132eSJeremy Kerr * software without specific prior written permission.
19069e132eSJeremy Kerr *
20069e132eSJeremy Kerr * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21069e132eSJeremy Kerr * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22069e132eSJeremy Kerr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23069e132eSJeremy Kerr * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24069e132eSJeremy Kerr * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25069e132eSJeremy Kerr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26069e132eSJeremy Kerr * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27069e132eSJeremy Kerr * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28069e132eSJeremy Kerr * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29069e132eSJeremy Kerr * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30069e132eSJeremy Kerr * POSSIBILITY OF SUCH DAMAGE.
31069e132eSJeremy Kerr */
32069e132eSJeremy Kerr
33069e132eSJeremy Kerr #define _BSD_SOURCE
34069e132eSJeremy Kerr
35069e132eSJeremy Kerr #include <sys/file.h>
36069e132eSJeremy Kerr #include <sys/stat.h>
37069e132eSJeremy Kerr #include <sys/types.h>
38069e132eSJeremy Kerr #include <fcntl.h>
39069e132eSJeremy Kerr #include <errno.h>
40069e132eSJeremy Kerr #include <unistd.h>
41069e132eSJeremy Kerr #include <stdbool.h>
42069e132eSJeremy Kerr
43069e132eSJeremy Kerr #include <systemd/sd-bus.h>
44069e132eSJeremy Kerr #include <systemd/sd-bus-vtable.h>
45069e132eSJeremy Kerr
46069e132eSJeremy Kerr #include <ipmitool/log.h>
47069e132eSJeremy Kerr #include <ipmitool/ipmi.h>
48069e132eSJeremy Kerr #include <ipmitool/ipmi_intf.h>
49069e132eSJeremy Kerr
50069e132eSJeremy Kerr static sd_bus *bus;
51069e132eSJeremy Kerr static uint8_t seq;
52069e132eSJeremy Kerr static struct ipmi_rs rsp;
53069e132eSJeremy Kerr static bool reply_received;
54069e132eSJeremy Kerr
55069e132eSJeremy Kerr static const char *bus_name = "org.openbmc.HostIpmi.ipmitool";
56069e132eSJeremy Kerr static const char *object_path = "/org/openbmc/HostIpmi/ipmitool";
57069e132eSJeremy Kerr static const char *interface = "org.openbmc.HostIpmi";
58069e132eSJeremy Kerr
ipmi_dbus_sendrecv(struct ipmi_intf * intf,struct ipmi_rq * req)59069e132eSJeremy Kerr static struct ipmi_rs *ipmi_dbus_sendrecv(struct ipmi_intf *intf,
60069e132eSJeremy Kerr struct ipmi_rq *req)
61069e132eSJeremy Kerr {
62069e132eSJeremy Kerr sd_bus_message *msg;
63069e132eSJeremy Kerr int rc;
64069e132eSJeremy Kerr
65069e132eSJeremy Kerr (void)intf;
66069e132eSJeremy Kerr
67069e132eSJeremy Kerr rsp.ccode = 0xff;
68069e132eSJeremy Kerr
69069e132eSJeremy Kerr rc = sd_bus_message_new_signal(bus, &msg, object_path,
70069e132eSJeremy Kerr interface, "ReceivedMessage");
71069e132eSJeremy Kerr if (rc < 0) {
72069e132eSJeremy Kerr lprintf(LOG_ERR, "%s: failed to create message: %s\n",
73069e132eSJeremy Kerr __func__, strerror(-rc));
74069e132eSJeremy Kerr goto out;
75069e132eSJeremy Kerr }
76069e132eSJeremy Kerr
779c752ddfSJeremy Kerr rc = sd_bus_message_append(msg, "yyyy",
78069e132eSJeremy Kerr ++seq,
799c752ddfSJeremy Kerr req->msg.netfn,
809c752ddfSJeremy Kerr req->msg.lun,
81069e132eSJeremy Kerr req->msg.cmd);
82069e132eSJeremy Kerr if (rc < 0) {
83069e132eSJeremy Kerr lprintf(LOG_ERR, "%s: failed to init bytes\n", __func__);
84069e132eSJeremy Kerr goto out_free;
85069e132eSJeremy Kerr }
86069e132eSJeremy Kerr
87069e132eSJeremy Kerr rc = sd_bus_message_append_array(msg, 'y', req->msg.data,
88069e132eSJeremy Kerr req->msg.data_len);
89069e132eSJeremy Kerr if (rc < 0) {
90069e132eSJeremy Kerr lprintf(LOG_ERR, "%s: failed to init body\n", __func__);
91069e132eSJeremy Kerr goto out_free;
92069e132eSJeremy Kerr }
93069e132eSJeremy Kerr
94069e132eSJeremy Kerr rc = sd_bus_send(bus, msg, NULL);
95069e132eSJeremy Kerr if (rc < 0) {
96069e132eSJeremy Kerr lprintf(LOG_ERR, "%s: failed to send dbus message\n",
97069e132eSJeremy Kerr __func__);
98069e132eSJeremy Kerr goto out_free;
99069e132eSJeremy Kerr }
100069e132eSJeremy Kerr
101069e132eSJeremy Kerr for (reply_received = false; !reply_received;) {
102069e132eSJeremy Kerr rc = sd_bus_wait(bus, -1);
103069e132eSJeremy Kerr sd_bus_process(bus, NULL);
104069e132eSJeremy Kerr }
105069e132eSJeremy Kerr
106069e132eSJeremy Kerr out_free:
107069e132eSJeremy Kerr sd_bus_message_unref(msg);
108069e132eSJeremy Kerr out:
109069e132eSJeremy Kerr return &rsp;
110069e132eSJeremy Kerr }
111069e132eSJeremy Kerr
ipmi_dbus_method_send_message(sd_bus_message * msg,void * userdata,sd_bus_error * error)112069e132eSJeremy Kerr static int ipmi_dbus_method_send_message(sd_bus_message *msg, void *userdata,
113069e132eSJeremy Kerr sd_bus_error *error)
114069e132eSJeremy Kerr {
1159c752ddfSJeremy Kerr uint8_t recv_seq, recv_netfn, recv_lun, recv_cmd, recv_cc;
116069e132eSJeremy Kerr const void *data;
117069e132eSJeremy Kerr size_t n;
118069e132eSJeremy Kerr int rc;
119069e132eSJeremy Kerr
120069e132eSJeremy Kerr (void)userdata;
121069e132eSJeremy Kerr (void)error;
122069e132eSJeremy Kerr
1239c752ddfSJeremy Kerr rc = sd_bus_message_read(msg, "yyyyy", &recv_seq, &recv_netfn,
1249c752ddfSJeremy Kerr &recv_lun, &recv_cmd, &recv_cc);
125069e132eSJeremy Kerr if (rc < 0) {
126069e132eSJeremy Kerr lprintf(LOG_ERR, "%s: failed to read reply\n", __func__);
127069e132eSJeremy Kerr goto out;
128069e132eSJeremy Kerr }
129069e132eSJeremy Kerr
130069e132eSJeremy Kerr rc = sd_bus_message_read_array(msg, 'y', &data, &n);
131069e132eSJeremy Kerr if (rc < 0) {
132069e132eSJeremy Kerr lprintf(LOG_ERR, "%s: failed to read reply data\n", __func__);
133069e132eSJeremy Kerr goto out;
134069e132eSJeremy Kerr }
135069e132eSJeremy Kerr
1369c752ddfSJeremy Kerr if (n > sizeof(rsp.data)) {
137069e132eSJeremy Kerr lprintf(LOG_ERR, "%s: data too long!\n", __func__);
138069e132eSJeremy Kerr goto out;
139069e132eSJeremy Kerr }
140069e132eSJeremy Kerr
141069e132eSJeremy Kerr if (recv_seq == seq) {
14228327660SJeremy Kerr rsp.ccode = recv_cc;
1439c752ddfSJeremy Kerr rsp.data_len = n;
1449c752ddfSJeremy Kerr memcpy(rsp.data, data, rsp.data_len);
145069e132eSJeremy Kerr reply_received = true;
146069e132eSJeremy Kerr }
147069e132eSJeremy Kerr
148069e132eSJeremy Kerr out:
149069e132eSJeremy Kerr sd_bus_reply_method_return(msg, "x", 0);
150069e132eSJeremy Kerr return 0;
151069e132eSJeremy Kerr }
152069e132eSJeremy Kerr
153069e132eSJeremy Kerr static const sd_bus_vtable dbus_vtable[] = {
154069e132eSJeremy Kerr SD_BUS_VTABLE_START(0),
1559c752ddfSJeremy Kerr SD_BUS_SIGNAL("ReceivedMessage", "yyyyay", 0),
1569c752ddfSJeremy Kerr SD_BUS_METHOD("sendMessage", "yyyyyay", "x",
157069e132eSJeremy Kerr ipmi_dbus_method_send_message,
158069e132eSJeremy Kerr SD_BUS_VTABLE_UNPRIVILEGED),
159069e132eSJeremy Kerr SD_BUS_VTABLE_END
160069e132eSJeremy Kerr };
161069e132eSJeremy Kerr
ipmi_dbus_setup(struct ipmi_intf * intf)162069e132eSJeremy Kerr static int ipmi_dbus_setup(struct ipmi_intf *intf)
163069e132eSJeremy Kerr {
164069e132eSJeremy Kerr const char *name;
165069e132eSJeremy Kerr int rc;
166069e132eSJeremy Kerr
167*e9b9c1a9SJeremy Kerr rc = sd_bus_default(&bus);
168069e132eSJeremy Kerr if (rc < 0) {
169069e132eSJeremy Kerr lprintf(LOG_ERR, "Can't connect to session bus: %s\n",
170069e132eSJeremy Kerr strerror(-rc));
171069e132eSJeremy Kerr return -1;
172069e132eSJeremy Kerr }
173069e132eSJeremy Kerr
174069e132eSJeremy Kerr sd_bus_add_object_vtable(bus, NULL, object_path, interface,
175069e132eSJeremy Kerr dbus_vtable, NULL);
176069e132eSJeremy Kerr
177069e132eSJeremy Kerr sd_bus_request_name(bus, bus_name, SD_BUS_NAME_REPLACE_EXISTING);
178069e132eSJeremy Kerr
179069e132eSJeremy Kerr sd_bus_flush(bus);
180069e132eSJeremy Kerr sd_bus_get_unique_name(bus, &name);
181069e132eSJeremy Kerr intf->opened = 1;
182069e132eSJeremy Kerr
183069e132eSJeremy Kerr return 0;
184069e132eSJeremy Kerr }
185069e132eSJeremy Kerr
ipmi_dbus_close(struct ipmi_intf * intf)186069e132eSJeremy Kerr static void ipmi_dbus_close(struct ipmi_intf *intf)
187069e132eSJeremy Kerr {
188069e132eSJeremy Kerr if (intf->opened)
189069e132eSJeremy Kerr sd_bus_close(bus);
190069e132eSJeremy Kerr intf->opened = 0;
191069e132eSJeremy Kerr }
192069e132eSJeremy Kerr
193069e132eSJeremy Kerr struct ipmi_intf ipmi_dbus_intf = {
194069e132eSJeremy Kerr .name = "dbus",
195069e132eSJeremy Kerr .desc = "OpenBMC dbus interface",
196069e132eSJeremy Kerr .setup = ipmi_dbus_setup,
197069e132eSJeremy Kerr .close = ipmi_dbus_close,
198069e132eSJeremy Kerr .sendrecv = ipmi_dbus_sendrecv,
199069e132eSJeremy Kerr };
200