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 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 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 = rsp.ccode; 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 162 static int ipmi_dbus_setup(struct ipmi_intf *intf) 163 { 164 const char *name; 165 int rc; 166 167 rc = sd_bus_default_user(&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 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