blob: bc6c522b21bc4e042da67514b6427616a1949ade [file] [log] [blame]
Patrick Venture0b02be92018-08-31 11:55:55 -07001#include "ipmid.hpp"
2
Patrick Venture46470a32018-09-07 19:26:25 -07003#include "host-cmd-manager.hpp"
4#include "ipmiwhitelist.hpp"
5#include "sensorhandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07006#include "settings.hpp"
Patrick Venture46470a32018-09-07 19:26:25 -07007#include "timer.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07008
vishwabmcba0bd5f2015-09-30 16:50:23 +05309#include <assert.h>
10#include <dirent.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070011#include <dlfcn.h>
12#include <errno.h>
13#include <mapper.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070014#include <sys/time.h>
15#include <systemd/sd-bus.h>
16#include <unistd.h>
17
18#include <algorithm>
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070019#include <cstring>
Patrick Venture0b02be92018-08-31 11:55:55 -070020#include <host-ipmid/ipmid-host-cmd.hpp>
Patrick Venture46470a32018-09-07 19:26:25 -070021#include <host-ipmid/oemrouter.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070022#include <iostream>
Patrick Venture0b02be92018-08-31 11:55:55 -070023#include <iterator>
vishwabmcba0bd5f2015-09-30 16:50:23 +053024#include <map>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050025#include <memory>
Andrew Geissler93c679b2017-04-02 10:06:43 -050026#include <phosphor-logging/log.hpp>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050027#include <sdbusplus/bus.hpp>
28#include <sdbusplus/bus/match.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070029#include <vector>
30#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
31
Andrew Geissler93c679b2017-04-02 10:06:43 -050032using namespace phosphor::logging;
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050033namespace sdbusRule = sdbusplus::bus::match::rules;
Andrew Geissler93c679b2017-04-02 10:06:43 -050034
Patrick Venture0b02be92018-08-31 11:55:55 -070035sd_bus* bus = NULL;
36sd_bus_slot* ipmid_slot = NULL;
37sd_event* events = nullptr;
Chris Austen30195fa2015-11-13 14:39:19 -060038
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053039// Need this to use new sdbusplus compatible interfaces
40sdbusPtr sdbusp;
41
42// Global Host Bound Command manager
43using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>;
44cmdManagerPtr cmdManager;
45
Ratan Gupta7a7f0122018-03-07 12:31:05 +053046// Global timer for network changes
47std::unique_ptr<phosphor::ipmi::Timer> networkTimer = nullptr;
48
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053049// Command and handler tuple. Used when clients ask the command to be put
50// into host message queue
51using CommandHandler = phosphor::host::command::CommandHandler;
52
Tom Joseph9a61b4f2016-07-11 06:56:11 -050053// Initialise restricted mode to true
54bool restricted_mode = true;
55
Chris Austen41a4b312015-10-25 03:45:42 -050056FILE *ipmiio, *ipmidbus, *ipmicmddetails;
vishwabmcba0bd5f2015-09-30 16:50:23 +053057
Patrick Venture0b02be92018-08-31 11:55:55 -070058void print_usage(void)
59{
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070060 std::fprintf(stderr, "Options: [-d mask]\n");
61 std::fprintf(stderr, " mask : 0x01 - Print ipmi packets\n");
62 std::fprintf(stderr, " mask : 0x02 - Print DBUS operations\n");
63 std::fprintf(stderr, " mask : 0x04 - Print ipmi command details\n");
64 std::fprintf(stderr, " mask : 0xFF - Print all trace\n");
Chris Austen99497312015-10-22 13:00:16 -050065}
66
Patrick Venture0b02be92018-08-31 11:55:55 -070067const char* DBUS_INTF = "org.openbmc.HostIpmi";
vishwabmcba0bd5f2015-09-30 16:50:23 +053068
Patrick Venture0b02be92018-08-31 11:55:55 -070069const char* FILTER =
70 "type='signal',interface='org.openbmc.HostIpmi',member='ReceivedMessage'";
Chris Austen0ba649e2015-10-13 12:28:13 -050071
vishwabmcba0bd5f2015-09-30 16:50:23 +053072typedef std::pair<ipmi_netfn_t, ipmi_cmd_t> ipmi_fn_cmd_t;
73typedef std::pair<ipmid_callback_t, ipmi_context_t> ipmi_fn_context_t;
74
75// Global data structure that contains the IPMI command handler's registrations.
76std::map<ipmi_fn_cmd_t, ipmi_fn_context_t> g_ipmid_router_map;
77
Nan Li36c0cb62016-03-31 11:16:08 +080078// IPMI Spec, shared Reservation ID.
79unsigned short g_sel_reserve = 0xFFFF;
80
81unsigned short get_sel_reserve_id(void)
82{
83 return g_sel_reserve;
84}
Chris Austen0ba649e2015-10-13 12:28:13 -050085
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050086namespace internal
87{
88
89constexpr auto restrictionModeIntf =
90 "xyz.openbmc_project.Control.Security.RestrictionMode";
91
92namespace cache
93{
94
95std::unique_ptr<settings::Objects> objects = nullptr;
96
97} // namespace cache
98} // namespace internal
99
Chris Austen0ba649e2015-10-13 12:28:13 -0500100#ifndef HEXDUMP_COLS
101#define HEXDUMP_COLS 16
102#endif
103
Patrick Venture0b02be92018-08-31 11:55:55 -0700104void hexdump(FILE* s, void* mem, size_t len)
Chris Austen0ba649e2015-10-13 12:28:13 -0500105{
Patrick Venture0b02be92018-08-31 11:55:55 -0700106 unsigned int i, j;
Chris Austen120f7322015-10-14 23:27:31 -0500107
Patrick Venture0b02be92018-08-31 11:55:55 -0700108 for (i = 0;
109 i <
110 len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0);
111 i++)
112 {
113 /* print offset */
114 if (i % HEXDUMP_COLS == 0)
Chris Austen0ba649e2015-10-13 12:28:13 -0500115 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700116 std::fprintf(s, "0x%06x: ", i);
Chris Austen0ba649e2015-10-13 12:28:13 -0500117 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700118
119 /* print hex data */
120 if (i < len)
121 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700122 std::fprintf(s, "%02x ", 0xFF & ((char*)mem)[i]);
Patrick Venture0b02be92018-08-31 11:55:55 -0700123 }
124 else /* end of block, just aligning for ASCII dump */
125 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700126 std::fprintf(s, " ");
Patrick Venture0b02be92018-08-31 11:55:55 -0700127 }
128
129 /* print ASCII dump */
130 if (i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
131 {
132 for (j = i - (HEXDUMP_COLS - 1); j <= i; j++)
133 {
134 if (j >= len) /* end of block, not really printing */
135 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700136 std::fputc(' ', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700137 }
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700138 else if (std::isprint(((char*)mem)[j])) /* printable char */
Patrick Venture0b02be92018-08-31 11:55:55 -0700139 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700140 std::fputc(0xFF & ((char*)mem)[j], s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700141 }
142 else /* other char */
143 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700144 std::fputc('.', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700145 }
146 }
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700147 std::fputc('\n', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700148 }
149 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500150}
151
Patrick Venture0b02be92018-08-31 11:55:55 -0700152// Method that gets called by shared libraries to get their command handlers
153// registered
154void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
155 ipmi_context_t context, ipmid_callback_t handler,
156 ipmi_cmd_privilege_t priv)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530157{
158 // Pack NetFn and Command in one.
159 auto netfn_and_cmd = std::make_pair(netfn, cmd);
160
161 // Pack Function handler and Data in another.
162 auto handler_and_context = std::make_pair(handler, context);
163
164 // Check if the registration has already been made..
165 auto iter = g_ipmid_router_map.find(netfn_and_cmd);
Patrick Venture0b02be92018-08-31 11:55:55 -0700166 if (iter != g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530167 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700168 log<level::ERR>("Duplicate registration", entry("NETFN=0x%X", netfn),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530169 entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530170 }
171 else
172 {
173 // This is a fresh registration.. Add it to the map.
174 g_ipmid_router_map.emplace(netfn_and_cmd, handler_and_context);
175 }
176
177 return;
178}
179
180// Looks at the map and calls corresponding handler functions.
Patrick Venture0b02be92018-08-31 11:55:55 -0700181ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
182 ipmi_request_t request, ipmi_response_t response,
183 ipmi_data_len_t data_len)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530184{
185 // return from the Command handlers.
186 ipmi_ret_t rc = IPMI_CC_INVALID;
187
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500188 // If restricted mode is true and command is not whitelisted, don't
189 // execute the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700190 if (restricted_mode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500191 {
192 if (!std::binary_search(whitelist.cbegin(), whitelist.cend(),
Patrick Venture0b02be92018-08-31 11:55:55 -0700193 std::make_pair(netfn, cmd)))
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500194 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530195 log<level::ERR>("Net function not whitelisted",
Patrick Venture0b02be92018-08-31 11:55:55 -0700196 entry("NETFN=0x%X", netfn), entry("CMD=0x%X", cmd));
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500197 rc = IPMI_CC_INSUFFICIENT_PRIVILEGE;
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700198 std::memcpy(response, &rc, IPMI_CC_LEN);
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500199 *data_len = IPMI_CC_LEN;
200 return rc;
201 }
202 }
203
vishwabmcba0bd5f2015-09-30 16:50:23 +0530204 // Walk the map that has the registered handlers and invoke the approprite
205 // handlers for matching commands.
206 auto iter = g_ipmid_router_map.find(std::make_pair(netfn, cmd));
Patrick Venture0b02be92018-08-31 11:55:55 -0700207 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530208 {
Patrick Venture03f84ba2017-09-20 09:15:33 -0700209 /* By default should only print on failure to find wildcard command. */
210#ifdef __IPMI_DEBUG__
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530211 log<level::ERR>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700212 "No registered handlers for NetFn, trying Wilcard implementation",
213 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", IPMI_CMD_WILDCARD));
Patrick Venture03f84ba2017-09-20 09:15:33 -0700214#endif
vishwabmcba0bd5f2015-09-30 16:50:23 +0530215
216 // Now that we did not find any specific [NetFn,Cmd], tuple, check for
217 // NetFn, WildCard command present.
Patrick Venture0b02be92018-08-31 11:55:55 -0700218 iter =
219 g_ipmid_router_map.find(std::make_pair(netfn, IPMI_CMD_WILDCARD));
220 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530221 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530222 log<level::ERR>("No Registered handlers for NetFn",
223 entry("NET_FUN=0x%X", netfn),
224 entry("CMD=0x%X", IPMI_CMD_WILDCARD));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530225
226 // Respond with a 0xC1
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700227 std::memcpy(response, &rc, IPMI_CC_LEN);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530228 *data_len = IPMI_CC_LEN;
229 return rc;
230 }
231 }
232
233#ifdef __IPMI_DEBUG__
234 // We have either a perfect match -OR- a wild card atleast,
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530235 log<level::ERR>("Calling Net function",
Patrick Venture0b02be92018-08-31 11:55:55 -0700236 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530237#endif
238
239 // Extract the map data onto appropriate containers
240 auto handler_and_context = iter->second;
241
242 // Creating a pointer type casted to char* to make sure we advance 1 byte
243 // when we advance pointer to next's address. advancing void * would not
244 // make sense.
Patrick Venture0b02be92018-08-31 11:55:55 -0700245 char* respo = &((char*)response)[IPMI_CC_LEN];
vishwabmcba0bd5f2015-09-30 16:50:23 +0530246
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530247 try
248 {
249 // Response message from the plugin goes into a byte post the base
250 // response
Patrick Venture0b02be92018-08-31 11:55:55 -0700251 rc = (handler_and_context.first)(netfn, cmd, request, respo, data_len,
252 handler_and_context.second);
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530253 }
254 // IPMI command handlers can throw unhandled exceptions, catch those
255 // and return sane error code.
Patrick Venture0b02be92018-08-31 11:55:55 -0700256 catch (const std::exception& e)
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530257 {
258 log<level::ERR>(e.what(), entry("NET_FUN=0x%X", netfn),
259 entry("CMD=0x%X", cmd));
260 rc = IPMI_CC_UNSPECIFIED_ERROR;
261 *data_len = 0;
262 // fall through
263 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530264 // Now copy the return code that we got from handler and pack it in first
265 // byte.
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700266 std::memcpy(response, &rc, IPMI_CC_LEN);
Chris Austen120f7322015-10-14 23:27:31 -0500267
vishwabmcba0bd5f2015-09-30 16:50:23 +0530268 // Data length is now actual data + completion code.
269 *data_len = *data_len + IPMI_CC_LEN;
270
271 return rc;
272}
273
Patrick Venture0b02be92018-08-31 11:55:55 -0700274static int send_ipmi_message(sd_bus_message* req, unsigned char seq,
275 unsigned char netfn, unsigned char lun,
276 unsigned char cmd, unsigned char cc,
277 unsigned char* buf, unsigned char len)
278{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530279
Chris Austen0ba649e2015-10-13 12:28:13 -0500280 sd_bus_error error = SD_BUS_ERROR_NULL;
Patrick Venture0b02be92018-08-31 11:55:55 -0700281 sd_bus_message *reply = NULL, *m = NULL;
Jeremy Kerre41081f2015-10-27 12:11:36 +0800282 const char *dest, *path;
Chris Austen0ba649e2015-10-13 12:28:13 -0500283 int r, pty;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530284
Jeremy Kerre41081f2015-10-27 12:11:36 +0800285 dest = sd_bus_message_get_sender(req);
286 path = sd_bus_message_get_path(req);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530287
Patrick Venture0b02be92018-08-31 11:55:55 -0700288 r = sd_bus_message_new_method_call(bus, &m, dest, path, DBUS_INTF,
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530289 "sendMessage");
Patrick Venture0b02be92018-08-31 11:55:55 -0700290 if (r < 0)
291 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530292 log<level::ERR>("Failed to add the method object",
293 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500294 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530295 }
296
Chris Austenabfb5e82015-10-13 12:29:24 -0500297 // Responses in IPMI require a bit set. So there ya go...
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800298 netfn |= 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530299
Chris Austen0ba649e2015-10-13 12:28:13 -0500300 // Add the bytes needed for the methods to be called
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800301 r = sd_bus_message_append(m, "yyyyy", seq, netfn, lun, cmd, cc);
Patrick Venture0b02be92018-08-31 11:55:55 -0700302 if (r < 0)
303 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530304 log<level::ERR>("Failed add the netfn and others",
305 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600306 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500307 }
Chris Austen120f7322015-10-14 23:27:31 -0500308
Chris Austen0ba649e2015-10-13 12:28:13 -0500309 r = sd_bus_message_append_array(m, 'y', buf, len);
Patrick Venture0b02be92018-08-31 11:55:55 -0700310 if (r < 0)
311 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530312 log<level::ERR>("Failed to add the string of response bytes",
313 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600314 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500315 }
316
Chris Austen0ba649e2015-10-13 12:28:13 -0500317 // Call the IPMI responder on the bus so the message can be sent to the CEC
318 r = sd_bus_call(bus, m, 0, &error, &reply);
Patrick Venture0b02be92018-08-31 11:55:55 -0700319 if (r < 0)
320 {
321 log<level::ERR>("Failed to call the method", entry("DEST=%s", dest),
322 entry("PATH=%s", path), entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600323 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500324 }
325
326 r = sd_bus_message_read(reply, "x", &pty);
Patrick Venture0b02be92018-08-31 11:55:55 -0700327 if (r < 0)
328 {
329 log<level::ERR>("Failed to get a reply from the method",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530330 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500331 }
332
Chris Austen169395e2015-12-02 20:56:15 -0600333final:
Chris Austen0ba649e2015-10-13 12:28:13 -0500334 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600335 m = sd_bus_message_unref(m);
336 reply = sd_bus_message_unref(reply);
Chris Austen0ba649e2015-10-13 12:28:13 -0500337
Chris Austen0ba649e2015-10-13 12:28:13 -0500338 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Chris Austen0ba649e2015-10-13 12:28:13 -0500339}
340
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500341void cache_restricted_mode()
342{
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500343 restricted_mode = false;
344 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
345 using namespace internal;
346 using namespace internal::cache;
347 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
348 const auto& restrictionModeSetting =
Deepak Kodihallie6027092017-08-27 08:13:37 -0500349 objects->map.at(restrictionModeIntf).front();
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500350 auto method = dbus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700351 objects->service(restrictionModeSetting, restrictionModeIntf).c_str(),
352 restrictionModeSetting.c_str(), "org.freedesktop.DBus.Properties",
353 "Get");
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500354 method.append(restrictionModeIntf, "RestrictionMode");
355 auto resp = dbus.call(method);
356 if (resp.is_method_error())
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500357 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500358 log<level::ERR>("Error in RestrictionMode Get");
359 // Fail-safe to true.
360 restricted_mode = true;
361 return;
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500362 }
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500363 sdbusplus::message::variant<std::string> result;
364 resp.read(result);
365 auto restrictionMode =
366 RestrictionMode::convertModesFromString(result.get<std::string>());
Patrick Venture0b02be92018-08-31 11:55:55 -0700367 if (RestrictionMode::Modes::Whitelist == restrictionMode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500368 {
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500369 restricted_mode = true;
370 }
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500371}
372
Patrick Venture0b02be92018-08-31 11:55:55 -0700373static int handle_restricted_mode_change(sd_bus_message* m, void* user_data,
374 sd_bus_error* ret_error)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500375{
376 cache_restricted_mode();
377 return 0;
378}
379
Patrick Venture0b02be92018-08-31 11:55:55 -0700380static int handle_ipmi_command(sd_bus_message* m, void* user_data,
381 sd_bus_error* ret_error)
382{
Chris Austen0ba649e2015-10-13 12:28:13 -0500383 int r = 0;
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800384 unsigned char sequence, netfn, lun, cmd;
Patrick Venture0b02be92018-08-31 11:55:55 -0700385 const void* request;
Chris Austen0ba649e2015-10-13 12:28:13 -0500386 size_t sz;
Patrick Venture0b02be92018-08-31 11:55:55 -0700387 size_t resplen = MAX_IPMI_BUFFER;
Chris Austen0ba649e2015-10-13 12:28:13 -0500388 unsigned char response[MAX_IPMI_BUFFER];
389
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700390 std::memset(response, 0, MAX_IPMI_BUFFER);
Chris Austen0ba649e2015-10-13 12:28:13 -0500391
Patrick Venture0b02be92018-08-31 11:55:55 -0700392 r = sd_bus_message_read(m, "yyyy", &sequence, &netfn, &lun, &cmd);
393 if (r < 0)
394 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530395 log<level::ERR>("Failed to parse signal message",
396 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500397 return -1;
398 }
399
Patrick Venture0b02be92018-08-31 11:55:55 -0700400 r = sd_bus_message_read_array(m, 'y', &request, &sz);
401 if (r < 0)
402 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530403 log<level::ERR>("Failed to parse signal message",
404 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500405 return -1;
406 }
407
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700408 std::fprintf(ipmiio,
409 "IPMI Incoming: Seq 0x%02x, NetFn 0x%02x, CMD: 0x%02x \n",
410 sequence, netfn, cmd);
Chris Austen99497312015-10-22 13:00:16 -0500411 hexdump(ipmiio, (void*)request, sz);
Chris Austen0ba649e2015-10-13 12:28:13 -0500412
Chris Austen120f7322015-10-14 23:27:31 -0500413 // Allow the length field to be used for both input and output of the
Chris Austen0ba649e2015-10-13 12:28:13 -0500414 // ipmi call
415 resplen = sz;
416
Chris Austen120f7322015-10-14 23:27:31 -0500417 // Now that we have parsed the entire byte array from the caller
vishwabmcba0bd5f2015-09-30 16:50:23 +0530418 // we can call the ipmi router to do the work...
Patrick Venture0b02be92018-08-31 11:55:55 -0700419 r = ipmi_netfn_router(netfn, cmd, (void*)request, (void*)response,
420 &resplen);
421 if (r != 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530422 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530423#ifdef __IPMI_DEBUG__
Patrick Venture0b02be92018-08-31 11:55:55 -0700424 log<level::ERR>("ERROR in handling NetFn", entry("ERRNO=0x%X", -r),
425 entry("NET_FUN=0x%X", netfn), entry("CMD=0x%X", cmd));
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530426#endif
Ratan Guptae0cc8552018-01-22 14:23:04 +0530427 resplen = 0;
428 }
429 else
430 {
431 resplen = resplen - 1; // first byte is for return code.
vishwabmcba0bd5f2015-09-30 16:50:23 +0530432 }
433
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700434 std::fprintf(ipmiio, "IPMI Response:\n");
Patrick Venture0b02be92018-08-31 11:55:55 -0700435 hexdump(ipmiio, (void*)response, resplen);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530436
Chris Austen0ba649e2015-10-13 12:28:13 -0500437 // Send the response buffer from the ipmi command
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800438 r = send_ipmi_message(m, sequence, netfn, lun, cmd, response[0],
Patrick Venture0b02be92018-08-31 11:55:55 -0700439 ((unsigned char*)response) + 1, resplen);
440 if (r < 0)
441 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530442 log<level::ERR>("Failed to send the response message");
Chris Austen0ba649e2015-10-13 12:28:13 -0500443 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530444 }
445
Chris Austen0ba649e2015-10-13 12:28:13 -0500446 return 0;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530447}
448
449//----------------------------------------------------------------------
450// handler_select
451// Select all the files ending with with .so. in the given diretcory
452// @d: dirent structure containing the file name
453//----------------------------------------------------------------------
Patrick Venture0b02be92018-08-31 11:55:55 -0700454int handler_select(const struct dirent* entry)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530455{
456 // To hold ".so" from entry->d_name;
457 char dname_copy[4] = {0};
458
459 // We want to avoid checking for everything and isolate to the ones having
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500460 // .so.* or .so in them.
461 // Check for versioned libraries .so.*
Patrick Venture0b02be92018-08-31 11:55:55 -0700462 if (strstr(entry->d_name, IPMI_PLUGIN_SONAME_EXTN))
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500463 {
464 return 1;
465 }
466 // Check for non versioned libraries .so
Patrick Venture0b02be92018-08-31 11:55:55 -0700467 else if (strstr(entry->d_name, IPMI_PLUGIN_EXTN))
vishwabmcba0bd5f2015-09-30 16:50:23 +0530468 {
469 // It is possible that .so could be anywhere in the string but unlikely
Chris Austen120f7322015-10-14 23:27:31 -0500470 // But being careful here. Get the base address of the string, move
vishwabmcba0bd5f2015-09-30 16:50:23 +0530471 // until end and come back 3 steps and that gets what we need.
Patrick Venture0b02be92018-08-31 11:55:55 -0700472 strcpy(dname_copy, (entry->d_name + strlen(entry->d_name) -
473 strlen(IPMI_PLUGIN_EXTN)));
474 if (strcmp(dname_copy, IPMI_PLUGIN_EXTN) == 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530475 {
476 return 1;
477 }
478 }
479 return 0;
480}
481
Patrick Venture0b02be92018-08-31 11:55:55 -0700482// This will do a dlopen of every .so in ipmi_lib_path and will dlopen
483// everything so that they will register a callback handler
vishwabmcba0bd5f2015-09-30 16:50:23 +0530484void ipmi_register_callback_handlers(const char* ipmi_lib_path)
485{
486 // For walking the ipmi_lib_path
Patrick Venture0b02be92018-08-31 11:55:55 -0700487 struct dirent** handler_list;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530488 int num_handlers = 0;
489
490 // This is used to check and abort if someone tries to register a bad one.
Patrick Venture0b02be92018-08-31 11:55:55 -0700491 void* lib_handler = NULL;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530492
Patrick Venture0b02be92018-08-31 11:55:55 -0700493 if (ipmi_lib_path == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530494 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530495 log<level::ERR>("No handlers to be registered for ipmi.. Aborting");
vishwabmcba0bd5f2015-09-30 16:50:23 +0530496 assert(0);
497 }
498 else
499 {
500 // 1: Open ipmi_lib_path. Its usually "/usr/lib/phosphor-host-ipmid"
501 // 2: Scan the directory for the files that end with .so
Chris Austen120f7322015-10-14 23:27:31 -0500502 // 3: For each one of them, just do a 'dlopen' so that they register
vishwabmcba0bd5f2015-09-30 16:50:23 +0530503 // the handlers for callback routines.
504
505 std::string handler_fqdn = ipmi_lib_path;
Chris Austen120f7322015-10-14 23:27:31 -0500506
vishwabmcba0bd5f2015-09-30 16:50:23 +0530507 // Append a "/" since we need to add the name of the .so. If there is
508 // already a .so, adding one more is not any harm.
509 handler_fqdn += "/";
510
Patrick Venture0b02be92018-08-31 11:55:55 -0700511 num_handlers =
512 scandir(ipmi_lib_path, &handler_list, handler_select, alphasort);
Nan Li36c0cb62016-03-31 11:16:08 +0800513 if (num_handlers < 0)
514 return;
Jeremy Kerr5e8f85e2015-10-27 13:43:54 +0800515
Patrick Venture0b02be92018-08-31 11:55:55 -0700516 while (num_handlers--)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530517 {
Chris Austen54030262015-10-13 12:30:46 -0500518 handler_fqdn = ipmi_lib_path;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530519 handler_fqdn += handler_list[num_handlers]->d_name;
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530520#ifdef __IPMI_DEBUG__
521 log<level::DEBUG>("Registering handler",
522 entry("HANDLER=%s", handler_fqdn.c_str()));
523#endif
Chris Austen54030262015-10-13 12:30:46 -0500524
vishwabmcba0bd5f2015-09-30 16:50:23 +0530525 lib_handler = dlopen(handler_fqdn.c_str(), RTLD_NOW);
Nan Li36c0cb62016-03-31 11:16:08 +0800526
Patrick Venture0b02be92018-08-31 11:55:55 -0700527 if (lib_handler == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530528 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530529 log<level::ERR>("ERROR opening",
530 entry("HANDLER=%s", handler_fqdn.c_str()),
531 entry("ERROR=%s", dlerror()));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530532 }
533 // Wipe the memory allocated for this particular entry.
534 free(handler_list[num_handlers]);
535 }
Nan Li36c0cb62016-03-31 11:16:08 +0800536
vishwabmcba0bd5f2015-09-30 16:50:23 +0530537 // Done with all registration.
538 free(handler_list);
539 }
540
541 // TODO : What to be done on the memory that is given by dlopen ?.
542 return;
543}
544
Patrick Venture0b02be92018-08-31 11:55:55 -0700545sd_bus* ipmid_get_sd_bus_connection(void)
546{
Chris Austen30195fa2015-11-13 14:39:19 -0600547 return bus;
548}
549
Patrick Venture0b02be92018-08-31 11:55:55 -0700550sd_event* ipmid_get_sd_event_connection(void)
551{
Andrew Geissler93c679b2017-04-02 10:06:43 -0500552 return events;
553}
554
Patrick Venture0b02be92018-08-31 11:55:55 -0700555sd_bus_slot* ipmid_get_sd_bus_slot(void)
556{
vishwab9f559a2016-01-13 01:53:08 -0600557 return ipmid_slot;
558}
559
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530560// Calls host command manager to do the right thing for the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700561void ipmid_send_cmd_to_host(CommandHandler&& cmd)
562{
563 return cmdManager->execute(std::move(cmd));
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530564}
565
Patrick Venture0b02be92018-08-31 11:55:55 -0700566cmdManagerPtr& ipmid_get_host_cmd_manager()
567{
568 return cmdManager;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530569}
570
Patrick Venture0b02be92018-08-31 11:55:55 -0700571sdbusPtr& ipmid_get_sdbus_plus_handler()
572{
573 return sdbusp;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530574}
575
Patrick Venture0b02be92018-08-31 11:55:55 -0700576int main(int argc, char* argv[])
vishwabmcba0bd5f2015-09-30 16:50:23 +0530577{
Chris Austen0ba649e2015-10-13 12:28:13 -0500578 int r;
Chris Austen99497312015-10-22 13:00:16 -0500579 unsigned long tvalue;
580 int c;
581
Chris Austen99497312015-10-22 13:00:16 -0500582 // This file and subsequient switch is for turning on levels
583 // of trace
Patrick Venture0b02be92018-08-31 11:55:55 -0700584 ipmicmddetails = ipmiio = ipmidbus = fopen("/dev/null", "w");
Chris Austen99497312015-10-22 13:00:16 -0500585
Patrick Venture0b02be92018-08-31 11:55:55 -0700586 while ((c = getopt(argc, argv, "h:d:")) != -1)
587 switch (c)
588 {
Chris Austen99497312015-10-22 13:00:16 -0500589 case 'd':
Patrick Venture0b02be92018-08-31 11:55:55 -0700590 tvalue = strtoul(optarg, NULL, 16);
591 if (1 & tvalue)
592 {
Chris Austen99497312015-10-22 13:00:16 -0500593 ipmiio = stdout;
594 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700595 if (2 & tvalue)
596 {
Chris Austen99497312015-10-22 13:00:16 -0500597 ipmidbus = stdout;
598 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700599 if (4 & tvalue)
600 {
Chris Austen99497312015-10-22 13:00:16 -0500601 ipmicmddetails = stdout;
602 }
603 break;
Patrick Venture0b02be92018-08-31 11:55:55 -0700604 case 'h':
605 case '?':
Chris Austen99497312015-10-22 13:00:16 -0500606 print_usage();
607 return 1;
608 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500609
Chris Austen0ba649e2015-10-13 12:28:13 -0500610 /* Connect to system bus */
611 r = sd_bus_open_system(&bus);
Patrick Venture0b02be92018-08-31 11:55:55 -0700612 if (r < 0)
613 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530614 log<level::ERR>("Failed to connect to system bus",
615 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500616 goto finish;
617 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530618
Andrew Geissler93c679b2017-04-02 10:06:43 -0500619 /* Get an sd event handler */
620 r = sd_event_default(&events);
621 if (r < 0)
622 {
623 log<level::ERR>("Failure to create sd_event handler",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530624 entry("ERRNO=0x%X", -r));
Andrew Geissler93c679b2017-04-02 10:06:43 -0500625 goto finish;
626 }
627
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530628 // Now create the Host Bound Command manager. Need sdbusplus
629 // to use the generated bindings
630 sdbusp = std::make_unique<sdbusplus::bus::bus>(bus);
Patrick Venture0b02be92018-08-31 11:55:55 -0700631 cmdManager =
632 std::make_unique<phosphor::host::command::Manager>(*sdbusp, events);
Andrew Geissler93c679b2017-04-02 10:06:43 -0500633
Peter Hanson4a589852017-06-07 17:40:45 -0700634 // Activate OemRouter.
635 oem::mutableRouter()->activate();
636
Chris Austen30195fa2015-11-13 14:39:19 -0600637 // Register all the handlers that provider implementation to IPMI commands.
638 ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
639
Patrick Venture0b02be92018-08-31 11:55:55 -0700640 // Watch for BT messages
vishwab9f559a2016-01-13 01:53:08 -0600641 r = sd_bus_add_match(bus, &ipmid_slot, FILTER, handle_ipmi_command, NULL);
Patrick Venture0b02be92018-08-31 11:55:55 -0700642 if (r < 0)
643 {
644 log<level::ERR>("Failed: sd_bus_add_match", entry("FILTER=%s", FILTER),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530645 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500646 goto finish;
647 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530648
Andrew Geissler93c679b2017-04-02 10:06:43 -0500649 // Attach the bus to sd_event to service user requests
650 sd_bus_attach_event(bus, events, SD_EVENT_PRIORITY_NORMAL);
651
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500652 {
653 using namespace internal;
654 using namespace internal::cache;
655 sdbusplus::bus::bus dbus{bus};
656 objects = std::make_unique<settings::Objects>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700657 dbus, std::vector<settings::Interface>({restrictionModeIntf}));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500658 // Initialize restricted mode
659 cache_restricted_mode();
660 // Wait for changes on Restricted mode
661 sdbusplus::bus::match_t restrictedModeMatch(
662 dbus,
663 sdbusRule::propertiesChanged(
Deepak Kodihallie6027092017-08-27 08:13:37 -0500664 objects->map.at(restrictionModeIntf).front(),
665 restrictionModeIntf),
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500666 handle_restricted_mode_change);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530667
Patrick Venture0b02be92018-08-31 11:55:55 -0700668 for (;;)
669 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500670 /* Process requests */
671 r = sd_event_run(events, (uint64_t)-1);
672 if (r < 0)
673 {
674 log<level::ERR>("Failure in processing request",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530675 entry("ERRNO=0x%X", -r));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500676 goto finish;
677 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500678 }
679 }
680
681finish:
Andrew Geissler93c679b2017-04-02 10:06:43 -0500682 sd_event_unref(events);
683 sd_bus_detach_event(bus);
vishwab9f559a2016-01-13 01:53:08 -0600684 sd_bus_slot_unref(ipmid_slot);
Chris Austen0ba649e2015-10-13 12:28:13 -0500685 sd_bus_unref(bus);
686 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530687}