xref: /openbmc/ipmitool/src/plugins/dbus/dbus.c (revision e9b9c1a9)
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