blob: c867e3c642a831fb560fcea1c8c83d26dd085697 [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>
14#include <stdio.h>
vishwabmcba0bd5f2015-09-30 16:50:23 +053015#include <stdlib.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070016#include <string.h>
17#include <sys/time.h>
18#include <systemd/sd-bus.h>
19#include <unistd.h>
20
21#include <algorithm>
Patrick Venture0b02be92018-08-31 11:55:55 -070022#include <host-ipmid/ipmid-host-cmd.hpp>
Patrick Venture46470a32018-09-07 19:26:25 -070023#include <host-ipmid/oemrouter.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070024#include <iostream>
Patrick Venture0b02be92018-08-31 11:55:55 -070025#include <iterator>
vishwabmcba0bd5f2015-09-30 16:50:23 +053026#include <map>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050027#include <memory>
Andrew Geissler93c679b2017-04-02 10:06:43 -050028#include <phosphor-logging/log.hpp>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050029#include <sdbusplus/bus.hpp>
30#include <sdbusplus/bus/match.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070031#include <vector>
32#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
33
Andrew Geissler93c679b2017-04-02 10:06:43 -050034using namespace phosphor::logging;
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050035namespace sdbusRule = sdbusplus::bus::match::rules;
Andrew Geissler93c679b2017-04-02 10:06:43 -050036
Patrick Venture0b02be92018-08-31 11:55:55 -070037sd_bus* bus = NULL;
38sd_bus_slot* ipmid_slot = NULL;
39sd_event* events = nullptr;
Chris Austen30195fa2015-11-13 14:39:19 -060040
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053041// Need this to use new sdbusplus compatible interfaces
42sdbusPtr sdbusp;
43
44// Global Host Bound Command manager
45using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>;
46cmdManagerPtr cmdManager;
47
Ratan Gupta7a7f0122018-03-07 12:31:05 +053048// Global timer for network changes
49std::unique_ptr<phosphor::ipmi::Timer> networkTimer = nullptr;
50
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053051// Command and handler tuple. Used when clients ask the command to be put
52// into host message queue
53using CommandHandler = phosphor::host::command::CommandHandler;
54
Tom Joseph9a61b4f2016-07-11 06:56:11 -050055// Initialise restricted mode to true
56bool restricted_mode = true;
57
Chris Austen41a4b312015-10-25 03:45:42 -050058FILE *ipmiio, *ipmidbus, *ipmicmddetails;
vishwabmcba0bd5f2015-09-30 16:50:23 +053059
Patrick Venture0b02be92018-08-31 11:55:55 -070060void print_usage(void)
61{
62 fprintf(stderr, "Options: [-d mask]\n");
63 fprintf(stderr, " mask : 0x01 - Print ipmi packets\n");
64 fprintf(stderr, " mask : 0x02 - Print DBUS operations\n");
65 fprintf(stderr, " mask : 0x04 - Print ipmi command details\n");
66 fprintf(stderr, " mask : 0xFF - Print all trace\n");
Chris Austen99497312015-10-22 13:00:16 -050067}
68
Patrick Venture0b02be92018-08-31 11:55:55 -070069const char* DBUS_INTF = "org.openbmc.HostIpmi";
vishwabmcba0bd5f2015-09-30 16:50:23 +053070
Patrick Venture0b02be92018-08-31 11:55:55 -070071const char* FILTER =
72 "type='signal',interface='org.openbmc.HostIpmi',member='ReceivedMessage'";
Chris Austen0ba649e2015-10-13 12:28:13 -050073
vishwabmcba0bd5f2015-09-30 16:50:23 +053074typedef std::pair<ipmi_netfn_t, ipmi_cmd_t> ipmi_fn_cmd_t;
75typedef std::pair<ipmid_callback_t, ipmi_context_t> ipmi_fn_context_t;
76
77// Global data structure that contains the IPMI command handler's registrations.
78std::map<ipmi_fn_cmd_t, ipmi_fn_context_t> g_ipmid_router_map;
79
Nan Li36c0cb62016-03-31 11:16:08 +080080// IPMI Spec, shared Reservation ID.
81unsigned short g_sel_reserve = 0xFFFF;
82
83unsigned short get_sel_reserve_id(void)
84{
85 return g_sel_reserve;
86}
Chris Austen0ba649e2015-10-13 12:28:13 -050087
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050088namespace internal
89{
90
91constexpr auto restrictionModeIntf =
92 "xyz.openbmc_project.Control.Security.RestrictionMode";
93
94namespace cache
95{
96
97std::unique_ptr<settings::Objects> objects = nullptr;
98
99} // namespace cache
100} // namespace internal
101
Chris Austen0ba649e2015-10-13 12:28:13 -0500102#ifndef HEXDUMP_COLS
103#define HEXDUMP_COLS 16
104#endif
105
Patrick Venture0b02be92018-08-31 11:55:55 -0700106void hexdump(FILE* s, void* mem, size_t len)
Chris Austen0ba649e2015-10-13 12:28:13 -0500107{
Patrick Venture0b02be92018-08-31 11:55:55 -0700108 unsigned int i, j;
Chris Austen120f7322015-10-14 23:27:31 -0500109
Patrick Venture0b02be92018-08-31 11:55:55 -0700110 for (i = 0;
111 i <
112 len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0);
113 i++)
114 {
115 /* print offset */
116 if (i % HEXDUMP_COLS == 0)
Chris Austen0ba649e2015-10-13 12:28:13 -0500117 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700118 fprintf(s, "0x%06x: ", i);
Chris Austen0ba649e2015-10-13 12:28:13 -0500119 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700120
121 /* print hex data */
122 if (i < len)
123 {
124 fprintf(s, "%02x ", 0xFF & ((char*)mem)[i]);
125 }
126 else /* end of block, just aligning for ASCII dump */
127 {
128 fprintf(s, " ");
129 }
130
131 /* print ASCII dump */
132 if (i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
133 {
134 for (j = i - (HEXDUMP_COLS - 1); j <= i; j++)
135 {
136 if (j >= len) /* end of block, not really printing */
137 {
138 fputc(' ', s);
139 }
140 else if (isprint(((char*)mem)[j])) /* printable char */
141 {
142 fputc(0xFF & ((char*)mem)[j], s);
143 }
144 else /* other char */
145 {
146 fputc('.', s);
147 }
148 }
149 fputc('\n', s);
150 }
151 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500152}
153
Patrick Venture0b02be92018-08-31 11:55:55 -0700154// Method that gets called by shared libraries to get their command handlers
155// registered
156void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
157 ipmi_context_t context, ipmid_callback_t handler,
158 ipmi_cmd_privilege_t priv)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530159{
160 // Pack NetFn and Command in one.
161 auto netfn_and_cmd = std::make_pair(netfn, cmd);
162
163 // Pack Function handler and Data in another.
164 auto handler_and_context = std::make_pair(handler, context);
165
166 // Check if the registration has already been made..
167 auto iter = g_ipmid_router_map.find(netfn_and_cmd);
Patrick Venture0b02be92018-08-31 11:55:55 -0700168 if (iter != g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530169 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700170 log<level::ERR>("Duplicate registration", entry("NETFN=0x%X", netfn),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530171 entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530172 }
173 else
174 {
175 // This is a fresh registration.. Add it to the map.
176 g_ipmid_router_map.emplace(netfn_and_cmd, handler_and_context);
177 }
178
179 return;
180}
181
182// Looks at the map and calls corresponding handler functions.
Patrick Venture0b02be92018-08-31 11:55:55 -0700183ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
184 ipmi_request_t request, ipmi_response_t response,
185 ipmi_data_len_t data_len)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530186{
187 // return from the Command handlers.
188 ipmi_ret_t rc = IPMI_CC_INVALID;
189
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500190 // If restricted mode is true and command is not whitelisted, don't
191 // execute the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700192 if (restricted_mode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500193 {
194 if (!std::binary_search(whitelist.cbegin(), whitelist.cend(),
Patrick Venture0b02be92018-08-31 11:55:55 -0700195 std::make_pair(netfn, cmd)))
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500196 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530197 log<level::ERR>("Net function not whitelisted",
Patrick Venture0b02be92018-08-31 11:55:55 -0700198 entry("NETFN=0x%X", netfn), entry("CMD=0x%X", cmd));
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500199 rc = IPMI_CC_INSUFFICIENT_PRIVILEGE;
200 memcpy(response, &rc, IPMI_CC_LEN);
201 *data_len = IPMI_CC_LEN;
202 return rc;
203 }
204 }
205
vishwabmcba0bd5f2015-09-30 16:50:23 +0530206 // Walk the map that has the registered handlers and invoke the approprite
207 // handlers for matching commands.
208 auto iter = g_ipmid_router_map.find(std::make_pair(netfn, cmd));
Patrick Venture0b02be92018-08-31 11:55:55 -0700209 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530210 {
Patrick Venture03f84ba2017-09-20 09:15:33 -0700211 /* By default should only print on failure to find wildcard command. */
212#ifdef __IPMI_DEBUG__
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530213 log<level::ERR>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700214 "No registered handlers for NetFn, trying Wilcard implementation",
215 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", IPMI_CMD_WILDCARD));
Patrick Venture03f84ba2017-09-20 09:15:33 -0700216#endif
vishwabmcba0bd5f2015-09-30 16:50:23 +0530217
218 // Now that we did not find any specific [NetFn,Cmd], tuple, check for
219 // NetFn, WildCard command present.
Patrick Venture0b02be92018-08-31 11:55:55 -0700220 iter =
221 g_ipmid_router_map.find(std::make_pair(netfn, IPMI_CMD_WILDCARD));
222 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530223 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530224 log<level::ERR>("No Registered handlers for NetFn",
225 entry("NET_FUN=0x%X", netfn),
226 entry("CMD=0x%X", IPMI_CMD_WILDCARD));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530227
228 // Respond with a 0xC1
229 memcpy(response, &rc, IPMI_CC_LEN);
230 *data_len = IPMI_CC_LEN;
231 return rc;
232 }
233 }
234
235#ifdef __IPMI_DEBUG__
236 // We have either a perfect match -OR- a wild card atleast,
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530237 log<level::ERR>("Calling Net function",
Patrick Venture0b02be92018-08-31 11:55:55 -0700238 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530239#endif
240
241 // Extract the map data onto appropriate containers
242 auto handler_and_context = iter->second;
243
244 // Creating a pointer type casted to char* to make sure we advance 1 byte
245 // when we advance pointer to next's address. advancing void * would not
246 // make sense.
Patrick Venture0b02be92018-08-31 11:55:55 -0700247 char* respo = &((char*)response)[IPMI_CC_LEN];
vishwabmcba0bd5f2015-09-30 16:50:23 +0530248
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530249 try
250 {
251 // Response message from the plugin goes into a byte post the base
252 // response
Patrick Venture0b02be92018-08-31 11:55:55 -0700253 rc = (handler_and_context.first)(netfn, cmd, request, respo, data_len,
254 handler_and_context.second);
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530255 }
256 // IPMI command handlers can throw unhandled exceptions, catch those
257 // and return sane error code.
Patrick Venture0b02be92018-08-31 11:55:55 -0700258 catch (const std::exception& e)
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530259 {
260 log<level::ERR>(e.what(), entry("NET_FUN=0x%X", netfn),
261 entry("CMD=0x%X", cmd));
262 rc = IPMI_CC_UNSPECIFIED_ERROR;
263 *data_len = 0;
264 // fall through
265 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530266 // Now copy the return code that we got from handler and pack it in first
267 // byte.
268 memcpy(response, &rc, IPMI_CC_LEN);
Chris Austen120f7322015-10-14 23:27:31 -0500269
vishwabmcba0bd5f2015-09-30 16:50:23 +0530270 // Data length is now actual data + completion code.
271 *data_len = *data_len + IPMI_CC_LEN;
272
273 return rc;
274}
275
Patrick Venture0b02be92018-08-31 11:55:55 -0700276static int send_ipmi_message(sd_bus_message* req, unsigned char seq,
277 unsigned char netfn, unsigned char lun,
278 unsigned char cmd, unsigned char cc,
279 unsigned char* buf, unsigned char len)
280{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530281
Chris Austen0ba649e2015-10-13 12:28:13 -0500282 sd_bus_error error = SD_BUS_ERROR_NULL;
Patrick Venture0b02be92018-08-31 11:55:55 -0700283 sd_bus_message *reply = NULL, *m = NULL;
Jeremy Kerre41081f2015-10-27 12:11:36 +0800284 const char *dest, *path;
Chris Austen0ba649e2015-10-13 12:28:13 -0500285 int r, pty;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530286
Jeremy Kerre41081f2015-10-27 12:11:36 +0800287 dest = sd_bus_message_get_sender(req);
288 path = sd_bus_message_get_path(req);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530289
Patrick Venture0b02be92018-08-31 11:55:55 -0700290 r = sd_bus_message_new_method_call(bus, &m, dest, path, DBUS_INTF,
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530291 "sendMessage");
Patrick Venture0b02be92018-08-31 11:55:55 -0700292 if (r < 0)
293 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530294 log<level::ERR>("Failed to add the method object",
295 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500296 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530297 }
298
Chris Austenabfb5e82015-10-13 12:29:24 -0500299 // Responses in IPMI require a bit set. So there ya go...
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800300 netfn |= 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530301
Chris Austen0ba649e2015-10-13 12:28:13 -0500302 // Add the bytes needed for the methods to be called
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800303 r = sd_bus_message_append(m, "yyyyy", seq, netfn, lun, cmd, cc);
Patrick Venture0b02be92018-08-31 11:55:55 -0700304 if (r < 0)
305 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530306 log<level::ERR>("Failed add the netfn and others",
307 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600308 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500309 }
Chris Austen120f7322015-10-14 23:27:31 -0500310
Chris Austen0ba649e2015-10-13 12:28:13 -0500311 r = sd_bus_message_append_array(m, 'y', buf, len);
Patrick Venture0b02be92018-08-31 11:55:55 -0700312 if (r < 0)
313 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530314 log<level::ERR>("Failed to add the string of response bytes",
315 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600316 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500317 }
318
Chris Austen0ba649e2015-10-13 12:28:13 -0500319 // Call the IPMI responder on the bus so the message can be sent to the CEC
320 r = sd_bus_call(bus, m, 0, &error, &reply);
Patrick Venture0b02be92018-08-31 11:55:55 -0700321 if (r < 0)
322 {
323 log<level::ERR>("Failed to call the method", entry("DEST=%s", dest),
324 entry("PATH=%s", path), entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600325 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500326 }
327
328 r = sd_bus_message_read(reply, "x", &pty);
Patrick Venture0b02be92018-08-31 11:55:55 -0700329 if (r < 0)
330 {
331 log<level::ERR>("Failed to get a reply from the method",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530332 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500333 }
334
Chris Austen169395e2015-12-02 20:56:15 -0600335final:
Chris Austen0ba649e2015-10-13 12:28:13 -0500336 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600337 m = sd_bus_message_unref(m);
338 reply = sd_bus_message_unref(reply);
Chris Austen0ba649e2015-10-13 12:28:13 -0500339
Chris Austen0ba649e2015-10-13 12:28:13 -0500340 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Chris Austen0ba649e2015-10-13 12:28:13 -0500341}
342
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500343void cache_restricted_mode()
344{
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500345 restricted_mode = false;
346 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
347 using namespace internal;
348 using namespace internal::cache;
349 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
350 const auto& restrictionModeSetting =
Deepak Kodihallie6027092017-08-27 08:13:37 -0500351 objects->map.at(restrictionModeIntf).front();
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500352 auto method = dbus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700353 objects->service(restrictionModeSetting, restrictionModeIntf).c_str(),
354 restrictionModeSetting.c_str(), "org.freedesktop.DBus.Properties",
355 "Get");
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500356 method.append(restrictionModeIntf, "RestrictionMode");
357 auto resp = dbus.call(method);
358 if (resp.is_method_error())
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500359 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500360 log<level::ERR>("Error in RestrictionMode Get");
361 // Fail-safe to true.
362 restricted_mode = true;
363 return;
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500364 }
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500365 sdbusplus::message::variant<std::string> result;
366 resp.read(result);
367 auto restrictionMode =
368 RestrictionMode::convertModesFromString(result.get<std::string>());
Patrick Venture0b02be92018-08-31 11:55:55 -0700369 if (RestrictionMode::Modes::Whitelist == restrictionMode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500370 {
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500371 restricted_mode = true;
372 }
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500373}
374
Patrick Venture0b02be92018-08-31 11:55:55 -0700375static int handle_restricted_mode_change(sd_bus_message* m, void* user_data,
376 sd_bus_error* ret_error)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500377{
378 cache_restricted_mode();
379 return 0;
380}
381
Patrick Venture0b02be92018-08-31 11:55:55 -0700382static int handle_ipmi_command(sd_bus_message* m, void* user_data,
383 sd_bus_error* ret_error)
384{
Chris Austen0ba649e2015-10-13 12:28:13 -0500385 int r = 0;
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800386 unsigned char sequence, netfn, lun, cmd;
Patrick Venture0b02be92018-08-31 11:55:55 -0700387 const void* request;
Chris Austen0ba649e2015-10-13 12:28:13 -0500388 size_t sz;
Patrick Venture0b02be92018-08-31 11:55:55 -0700389 size_t resplen = MAX_IPMI_BUFFER;
Chris Austen0ba649e2015-10-13 12:28:13 -0500390 unsigned char response[MAX_IPMI_BUFFER];
391
Chris Austen0ba649e2015-10-13 12:28:13 -0500392 memset(response, 0, MAX_IPMI_BUFFER);
393
Patrick Venture0b02be92018-08-31 11:55:55 -0700394 r = sd_bus_message_read(m, "yyyy", &sequence, &netfn, &lun, &cmd);
395 if (r < 0)
396 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530397 log<level::ERR>("Failed to parse signal message",
398 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500399 return -1;
400 }
401
Patrick Venture0b02be92018-08-31 11:55:55 -0700402 r = sd_bus_message_read_array(m, 'y', &request, &sz);
403 if (r < 0)
404 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530405 log<level::ERR>("Failed to parse signal message",
406 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500407 return -1;
408 }
409
Patrick Venture0b02be92018-08-31 11:55:55 -0700410 fprintf(ipmiio, "IPMI Incoming: Seq 0x%02x, NetFn 0x%02x, CMD: 0x%02x \n",
411 sequence, netfn, cmd);
Chris Austen99497312015-10-22 13:00:16 -0500412 hexdump(ipmiio, (void*)request, sz);
Chris Austen0ba649e2015-10-13 12:28:13 -0500413
Chris Austen120f7322015-10-14 23:27:31 -0500414 // Allow the length field to be used for both input and output of the
Chris Austen0ba649e2015-10-13 12:28:13 -0500415 // ipmi call
416 resplen = sz;
417
Chris Austen120f7322015-10-14 23:27:31 -0500418 // Now that we have parsed the entire byte array from the caller
vishwabmcba0bd5f2015-09-30 16:50:23 +0530419 // we can call the ipmi router to do the work...
Patrick Venture0b02be92018-08-31 11:55:55 -0700420 r = ipmi_netfn_router(netfn, cmd, (void*)request, (void*)response,
421 &resplen);
422 if (r != 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530423 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530424#ifdef __IPMI_DEBUG__
Patrick Venture0b02be92018-08-31 11:55:55 -0700425 log<level::ERR>("ERROR in handling NetFn", entry("ERRNO=0x%X", -r),
426 entry("NET_FUN=0x%X", netfn), entry("CMD=0x%X", cmd));
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530427#endif
Ratan Guptae0cc8552018-01-22 14:23:04 +0530428 resplen = 0;
429 }
430 else
431 {
432 resplen = resplen - 1; // first byte is for return code.
vishwabmcba0bd5f2015-09-30 16:50:23 +0530433 }
434
Chris Austen99497312015-10-22 13:00:16 -0500435 fprintf(ipmiio, "IPMI Response:\n");
Patrick Venture0b02be92018-08-31 11:55:55 -0700436 hexdump(ipmiio, (void*)response, resplen);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530437
Chris Austen0ba649e2015-10-13 12:28:13 -0500438 // Send the response buffer from the ipmi command
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800439 r = send_ipmi_message(m, sequence, netfn, lun, cmd, response[0],
Patrick Venture0b02be92018-08-31 11:55:55 -0700440 ((unsigned char*)response) + 1, resplen);
441 if (r < 0)
442 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530443 log<level::ERR>("Failed to send the response message");
Chris Austen0ba649e2015-10-13 12:28:13 -0500444 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530445 }
446
Chris Austen0ba649e2015-10-13 12:28:13 -0500447 return 0;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530448}
449
450//----------------------------------------------------------------------
451// handler_select
452// Select all the files ending with with .so. in the given diretcory
453// @d: dirent structure containing the file name
454//----------------------------------------------------------------------
Patrick Venture0b02be92018-08-31 11:55:55 -0700455int handler_select(const struct dirent* entry)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530456{
457 // To hold ".so" from entry->d_name;
458 char dname_copy[4] = {0};
459
460 // We want to avoid checking for everything and isolate to the ones having
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500461 // .so.* or .so in them.
462 // Check for versioned libraries .so.*
Patrick Venture0b02be92018-08-31 11:55:55 -0700463 if (strstr(entry->d_name, IPMI_PLUGIN_SONAME_EXTN))
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500464 {
465 return 1;
466 }
467 // Check for non versioned libraries .so
Patrick Venture0b02be92018-08-31 11:55:55 -0700468 else if (strstr(entry->d_name, IPMI_PLUGIN_EXTN))
vishwabmcba0bd5f2015-09-30 16:50:23 +0530469 {
470 // It is possible that .so could be anywhere in the string but unlikely
Chris Austen120f7322015-10-14 23:27:31 -0500471 // But being careful here. Get the base address of the string, move
vishwabmcba0bd5f2015-09-30 16:50:23 +0530472 // until end and come back 3 steps and that gets what we need.
Patrick Venture0b02be92018-08-31 11:55:55 -0700473 strcpy(dname_copy, (entry->d_name + strlen(entry->d_name) -
474 strlen(IPMI_PLUGIN_EXTN)));
475 if (strcmp(dname_copy, IPMI_PLUGIN_EXTN) == 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530476 {
477 return 1;
478 }
479 }
480 return 0;
481}
482
Patrick Venture0b02be92018-08-31 11:55:55 -0700483// This will do a dlopen of every .so in ipmi_lib_path and will dlopen
484// everything so that they will register a callback handler
vishwabmcba0bd5f2015-09-30 16:50:23 +0530485void ipmi_register_callback_handlers(const char* ipmi_lib_path)
486{
487 // For walking the ipmi_lib_path
Patrick Venture0b02be92018-08-31 11:55:55 -0700488 struct dirent** handler_list;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530489 int num_handlers = 0;
490
491 // This is used to check and abort if someone tries to register a bad one.
Patrick Venture0b02be92018-08-31 11:55:55 -0700492 void* lib_handler = NULL;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530493
Patrick Venture0b02be92018-08-31 11:55:55 -0700494 if (ipmi_lib_path == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530495 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530496 log<level::ERR>("No handlers to be registered for ipmi.. Aborting");
vishwabmcba0bd5f2015-09-30 16:50:23 +0530497 assert(0);
498 }
499 else
500 {
501 // 1: Open ipmi_lib_path. Its usually "/usr/lib/phosphor-host-ipmid"
502 // 2: Scan the directory for the files that end with .so
Chris Austen120f7322015-10-14 23:27:31 -0500503 // 3: For each one of them, just do a 'dlopen' so that they register
vishwabmcba0bd5f2015-09-30 16:50:23 +0530504 // the handlers for callback routines.
505
506 std::string handler_fqdn = ipmi_lib_path;
Chris Austen120f7322015-10-14 23:27:31 -0500507
vishwabmcba0bd5f2015-09-30 16:50:23 +0530508 // Append a "/" since we need to add the name of the .so. If there is
509 // already a .so, adding one more is not any harm.
510 handler_fqdn += "/";
511
Patrick Venture0b02be92018-08-31 11:55:55 -0700512 num_handlers =
513 scandir(ipmi_lib_path, &handler_list, handler_select, alphasort);
Nan Li36c0cb62016-03-31 11:16:08 +0800514 if (num_handlers < 0)
515 return;
Jeremy Kerr5e8f85e2015-10-27 13:43:54 +0800516
Patrick Venture0b02be92018-08-31 11:55:55 -0700517 while (num_handlers--)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530518 {
Chris Austen54030262015-10-13 12:30:46 -0500519 handler_fqdn = ipmi_lib_path;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530520 handler_fqdn += handler_list[num_handlers]->d_name;
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530521#ifdef __IPMI_DEBUG__
522 log<level::DEBUG>("Registering handler",
523 entry("HANDLER=%s", handler_fqdn.c_str()));
524#endif
Chris Austen54030262015-10-13 12:30:46 -0500525
vishwabmcba0bd5f2015-09-30 16:50:23 +0530526 lib_handler = dlopen(handler_fqdn.c_str(), RTLD_NOW);
Nan Li36c0cb62016-03-31 11:16:08 +0800527
Patrick Venture0b02be92018-08-31 11:55:55 -0700528 if (lib_handler == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530529 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530530 log<level::ERR>("ERROR opening",
531 entry("HANDLER=%s", handler_fqdn.c_str()),
532 entry("ERROR=%s", dlerror()));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530533 }
534 // Wipe the memory allocated for this particular entry.
535 free(handler_list[num_handlers]);
536 }
Nan Li36c0cb62016-03-31 11:16:08 +0800537
vishwabmcba0bd5f2015-09-30 16:50:23 +0530538 // Done with all registration.
539 free(handler_list);
540 }
541
542 // TODO : What to be done on the memory that is given by dlopen ?.
543 return;
544}
545
Patrick Venture0b02be92018-08-31 11:55:55 -0700546sd_bus* ipmid_get_sd_bus_connection(void)
547{
Chris Austen30195fa2015-11-13 14:39:19 -0600548 return bus;
549}
550
Patrick Venture0b02be92018-08-31 11:55:55 -0700551sd_event* ipmid_get_sd_event_connection(void)
552{
Andrew Geissler93c679b2017-04-02 10:06:43 -0500553 return events;
554}
555
Patrick Venture0b02be92018-08-31 11:55:55 -0700556sd_bus_slot* ipmid_get_sd_bus_slot(void)
557{
vishwab9f559a2016-01-13 01:53:08 -0600558 return ipmid_slot;
559}
560
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530561// Calls host command manager to do the right thing for the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700562void ipmid_send_cmd_to_host(CommandHandler&& cmd)
563{
564 return cmdManager->execute(std::move(cmd));
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530565}
566
Patrick Venture0b02be92018-08-31 11:55:55 -0700567cmdManagerPtr& ipmid_get_host_cmd_manager()
568{
569 return cmdManager;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530570}
571
Patrick Venture0b02be92018-08-31 11:55:55 -0700572sdbusPtr& ipmid_get_sdbus_plus_handler()
573{
574 return sdbusp;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530575}
576
Patrick Venture0b02be92018-08-31 11:55:55 -0700577int main(int argc, char* argv[])
vishwabmcba0bd5f2015-09-30 16:50:23 +0530578{
Chris Austen0ba649e2015-10-13 12:28:13 -0500579 int r;
Chris Austen99497312015-10-22 13:00:16 -0500580 unsigned long tvalue;
581 int c;
582
Chris Austen99497312015-10-22 13:00:16 -0500583 // This file and subsequient switch is for turning on levels
584 // of trace
Patrick Venture0b02be92018-08-31 11:55:55 -0700585 ipmicmddetails = ipmiio = ipmidbus = fopen("/dev/null", "w");
Chris Austen99497312015-10-22 13:00:16 -0500586
Patrick Venture0b02be92018-08-31 11:55:55 -0700587 while ((c = getopt(argc, argv, "h:d:")) != -1)
588 switch (c)
589 {
Chris Austen99497312015-10-22 13:00:16 -0500590 case 'd':
Patrick Venture0b02be92018-08-31 11:55:55 -0700591 tvalue = strtoul(optarg, NULL, 16);
592 if (1 & tvalue)
593 {
Chris Austen99497312015-10-22 13:00:16 -0500594 ipmiio = stdout;
595 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700596 if (2 & tvalue)
597 {
Chris Austen99497312015-10-22 13:00:16 -0500598 ipmidbus = stdout;
599 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700600 if (4 & tvalue)
601 {
Chris Austen99497312015-10-22 13:00:16 -0500602 ipmicmddetails = stdout;
603 }
604 break;
Patrick Venture0b02be92018-08-31 11:55:55 -0700605 case 'h':
606 case '?':
Chris Austen99497312015-10-22 13:00:16 -0500607 print_usage();
608 return 1;
609 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500610
Chris Austen0ba649e2015-10-13 12:28:13 -0500611 /* Connect to system bus */
612 r = sd_bus_open_system(&bus);
Patrick Venture0b02be92018-08-31 11:55:55 -0700613 if (r < 0)
614 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530615 log<level::ERR>("Failed to connect to system bus",
616 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500617 goto finish;
618 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530619
Andrew Geissler93c679b2017-04-02 10:06:43 -0500620 /* Get an sd event handler */
621 r = sd_event_default(&events);
622 if (r < 0)
623 {
624 log<level::ERR>("Failure to create sd_event handler",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530625 entry("ERRNO=0x%X", -r));
Andrew Geissler93c679b2017-04-02 10:06:43 -0500626 goto finish;
627 }
628
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530629 // Now create the Host Bound Command manager. Need sdbusplus
630 // to use the generated bindings
631 sdbusp = std::make_unique<sdbusplus::bus::bus>(bus);
Patrick Venture0b02be92018-08-31 11:55:55 -0700632 cmdManager =
633 std::make_unique<phosphor::host::command::Manager>(*sdbusp, events);
Andrew Geissler93c679b2017-04-02 10:06:43 -0500634
Peter Hanson4a589852017-06-07 17:40:45 -0700635 // Activate OemRouter.
636 oem::mutableRouter()->activate();
637
Chris Austen30195fa2015-11-13 14:39:19 -0600638 // Register all the handlers that provider implementation to IPMI commands.
639 ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
640
Patrick Venture0b02be92018-08-31 11:55:55 -0700641 // Watch for BT messages
vishwab9f559a2016-01-13 01:53:08 -0600642 r = sd_bus_add_match(bus, &ipmid_slot, FILTER, handle_ipmi_command, NULL);
Patrick Venture0b02be92018-08-31 11:55:55 -0700643 if (r < 0)
644 {
645 log<level::ERR>("Failed: sd_bus_add_match", entry("FILTER=%s", FILTER),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530646 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500647 goto finish;
648 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530649
Andrew Geissler93c679b2017-04-02 10:06:43 -0500650 // Attach the bus to sd_event to service user requests
651 sd_bus_attach_event(bus, events, SD_EVENT_PRIORITY_NORMAL);
652
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500653 {
654 using namespace internal;
655 using namespace internal::cache;
656 sdbusplus::bus::bus dbus{bus};
657 objects = std::make_unique<settings::Objects>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700658 dbus, std::vector<settings::Interface>({restrictionModeIntf}));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500659 // Initialize restricted mode
660 cache_restricted_mode();
661 // Wait for changes on Restricted mode
662 sdbusplus::bus::match_t restrictedModeMatch(
663 dbus,
664 sdbusRule::propertiesChanged(
Deepak Kodihallie6027092017-08-27 08:13:37 -0500665 objects->map.at(restrictionModeIntf).front(),
666 restrictionModeIntf),
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500667 handle_restricted_mode_change);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530668
Patrick Venture0b02be92018-08-31 11:55:55 -0700669 for (;;)
670 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500671 /* Process requests */
672 r = sd_event_run(events, (uint64_t)-1);
673 if (r < 0)
674 {
675 log<level::ERR>("Failure in processing request",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530676 entry("ERRNO=0x%X", -r));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500677 goto finish;
678 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500679 }
680 }
681
682finish:
Andrew Geissler93c679b2017-04-02 10:06:43 -0500683 sd_event_unref(events);
684 sd_bus_detach_event(bus);
vishwab9f559a2016-01-13 01:53:08 -0600685 sd_bus_slot_unref(ipmid_slot);
Chris Austen0ba649e2015-10-13 12:28:13 -0500686 sd_bus_unref(bus);
687 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530688}