blob: 11d6796fc0d1e4b522e5571f918247f0918050bf [file] [log] [blame]
Patrick Venture15e95f22018-11-14 19:25:08 -08001#include "config.h"
2
Patrick Venture0b02be92018-08-31 11:55:55 -07003#include "ipmid.hpp"
4
Patrick Venture46470a32018-09-07 19:26:25 -07005#include "host-cmd-manager.hpp"
6#include "ipmiwhitelist.hpp"
7#include "sensorhandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07008#include "settings.hpp"
9
vishwabmcba0bd5f2015-09-30 16:50:23 +053010#include <assert.h>
11#include <dirent.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070012#include <dlfcn.h>
13#include <errno.h>
14#include <mapper.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070015#include <sys/time.h>
16#include <systemd/sd-bus.h>
17#include <unistd.h>
18
19#include <algorithm>
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070020#include <cstring>
Patrick Venture0b02be92018-08-31 11:55:55 -070021#include <host-ipmid/ipmid-host-cmd.hpp>
Patrick Venture46470a32018-09-07 19:26:25 -070022#include <host-ipmid/oemrouter.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070023#include <iostream>
Patrick Venture0b02be92018-08-31 11:55:55 -070024#include <iterator>
vishwabmcba0bd5f2015-09-30 16:50:23 +053025#include <map>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050026#include <memory>
Andrew Geissler93c679b2017-04-02 10:06:43 -050027#include <phosphor-logging/log.hpp>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050028#include <sdbusplus/bus.hpp>
29#include <sdbusplus/bus/match.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070030#include <sdbusplus/message/types.hpp>
Vernon Mauery1181af72018-10-08 12:05:00 -070031#include <sdbusplus/timer.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070032#include <vector>
33#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
34
Andrew Geissler93c679b2017-04-02 10:06:43 -050035using namespace phosphor::logging;
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050036namespace sdbusRule = sdbusplus::bus::match::rules;
William A. Kennington III4c008022018-10-12 17:18:14 -070037namespace variant_ns = sdbusplus::message::variant_ns;
Andrew Geissler93c679b2017-04-02 10:06:43 -050038
Patrick Venture0b02be92018-08-31 11:55:55 -070039sd_bus* bus = NULL;
40sd_bus_slot* ipmid_slot = NULL;
41sd_event* events = nullptr;
Chris Austen30195fa2015-11-13 14:39:19 -060042
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053043// Need this to use new sdbusplus compatible interfaces
44sdbusPtr sdbusp;
45
46// Global Host Bound Command manager
47using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>;
48cmdManagerPtr cmdManager;
49
Ratan Gupta7a7f0122018-03-07 12:31:05 +053050// Global timer for network changes
Vernon Mauery1181af72018-10-08 12:05:00 -070051std::unique_ptr<phosphor::Timer> networkTimer = nullptr;
Ratan Gupta7a7f0122018-03-07 12:31:05 +053052
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053053// Command and handler tuple. Used when clients ask the command to be put
54// into host message queue
55using CommandHandler = phosphor::host::command::CommandHandler;
56
Tom Joseph9a61b4f2016-07-11 06:56:11 -050057// Initialise restricted mode to true
58bool restricted_mode = true;
59
Chris Austen41a4b312015-10-25 03:45:42 -050060FILE *ipmiio, *ipmidbus, *ipmicmddetails;
vishwabmcba0bd5f2015-09-30 16:50:23 +053061
Patrick Venture0b02be92018-08-31 11:55:55 -070062void print_usage(void)
63{
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070064 std::fprintf(stderr, "Options: [-d mask]\n");
65 std::fprintf(stderr, " mask : 0x01 - Print ipmi packets\n");
66 std::fprintf(stderr, " mask : 0x02 - Print DBUS operations\n");
67 std::fprintf(stderr, " mask : 0x04 - Print ipmi command details\n");
68 std::fprintf(stderr, " mask : 0xFF - Print all trace\n");
Chris Austen99497312015-10-22 13:00:16 -050069}
70
Patrick Venture0b02be92018-08-31 11:55:55 -070071const char* DBUS_INTF = "org.openbmc.HostIpmi";
vishwabmcba0bd5f2015-09-30 16:50:23 +053072
Patrick Venture0b02be92018-08-31 11:55:55 -070073const char* FILTER =
74 "type='signal',interface='org.openbmc.HostIpmi',member='ReceivedMessage'";
Chris Austen0ba649e2015-10-13 12:28:13 -050075
vishwabmcba0bd5f2015-09-30 16:50:23 +053076typedef std::pair<ipmi_netfn_t, ipmi_cmd_t> ipmi_fn_cmd_t;
77typedef std::pair<ipmid_callback_t, ipmi_context_t> ipmi_fn_context_t;
78
79// Global data structure that contains the IPMI command handler's registrations.
80std::map<ipmi_fn_cmd_t, ipmi_fn_context_t> g_ipmid_router_map;
81
Nan Li36c0cb62016-03-31 11:16:08 +080082// IPMI Spec, shared Reservation ID.
Jason M. Bills13e67c82018-09-10 14:12:16 -070083static unsigned short selReservationID = 0xFFFF;
84static bool selReservationValid = false;
Nan Li36c0cb62016-03-31 11:16:08 +080085
Jason M. Bills13e67c82018-09-10 14:12:16 -070086unsigned short reserveSel(void)
Nan Li36c0cb62016-03-31 11:16:08 +080087{
Jason M. Bills13e67c82018-09-10 14:12:16 -070088 // IPMI spec, Reservation ID, the value simply increases against each
89 // execution of the Reserve SEL command.
90 if (++selReservationID == 0)
91 {
92 selReservationID = 1;
93 }
94 selReservationValid = true;
95 return selReservationID;
96}
97
98bool checkSELReservation(unsigned short id)
99{
100 return (selReservationValid && selReservationID == id);
101}
102
103void cancelSELReservation(void)
104{
105 selReservationValid = false;
Nan Li36c0cb62016-03-31 11:16:08 +0800106}
Chris Austen0ba649e2015-10-13 12:28:13 -0500107
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500108namespace internal
109{
110
111constexpr auto restrictionModeIntf =
112 "xyz.openbmc_project.Control.Security.RestrictionMode";
113
114namespace cache
115{
116
117std::unique_ptr<settings::Objects> objects = nullptr;
118
119} // namespace cache
120} // namespace internal
121
Chris Austen0ba649e2015-10-13 12:28:13 -0500122#ifndef HEXDUMP_COLS
123#define HEXDUMP_COLS 16
124#endif
125
Patrick Venture0b02be92018-08-31 11:55:55 -0700126void hexdump(FILE* s, void* mem, size_t len)
Chris Austen0ba649e2015-10-13 12:28:13 -0500127{
Patrick Venture0b02be92018-08-31 11:55:55 -0700128 unsigned int i, j;
Chris Austen120f7322015-10-14 23:27:31 -0500129
Patrick Venture0b02be92018-08-31 11:55:55 -0700130 for (i = 0;
131 i <
132 len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0);
133 i++)
134 {
135 /* print offset */
136 if (i % HEXDUMP_COLS == 0)
Chris Austen0ba649e2015-10-13 12:28:13 -0500137 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700138 std::fprintf(s, "0x%06x: ", i);
Chris Austen0ba649e2015-10-13 12:28:13 -0500139 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700140
141 /* print hex data */
142 if (i < len)
143 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700144 std::fprintf(s, "%02x ", 0xFF & ((char*)mem)[i]);
Patrick Venture0b02be92018-08-31 11:55:55 -0700145 }
146 else /* end of block, just aligning for ASCII dump */
147 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700148 std::fprintf(s, " ");
Patrick Venture0b02be92018-08-31 11:55:55 -0700149 }
150
151 /* print ASCII dump */
152 if (i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
153 {
154 for (j = i - (HEXDUMP_COLS - 1); j <= i; j++)
155 {
156 if (j >= len) /* end of block, not really printing */
157 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700158 std::fputc(' ', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700159 }
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700160 else if (std::isprint(((char*)mem)[j])) /* printable char */
Patrick Venture0b02be92018-08-31 11:55:55 -0700161 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700162 std::fputc(0xFF & ((char*)mem)[j], s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700163 }
164 else /* other char */
165 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700166 std::fputc('.', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700167 }
168 }
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700169 std::fputc('\n', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700170 }
171 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500172}
173
Patrick Venture0b02be92018-08-31 11:55:55 -0700174// Method that gets called by shared libraries to get their command handlers
175// registered
176void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
177 ipmi_context_t context, ipmid_callback_t handler,
178 ipmi_cmd_privilege_t priv)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530179{
180 // Pack NetFn and Command in one.
181 auto netfn_and_cmd = std::make_pair(netfn, cmd);
182
183 // Pack Function handler and Data in another.
184 auto handler_and_context = std::make_pair(handler, context);
185
186 // Check if the registration has already been made..
187 auto iter = g_ipmid_router_map.find(netfn_and_cmd);
Patrick Venture0b02be92018-08-31 11:55:55 -0700188 if (iter != g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530189 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700190 log<level::ERR>("Duplicate registration", entry("NETFN=0x%X", netfn),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530191 entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530192 }
193 else
194 {
195 // This is a fresh registration.. Add it to the map.
196 g_ipmid_router_map.emplace(netfn_and_cmd, handler_and_context);
197 }
198
199 return;
200}
201
202// Looks at the map and calls corresponding handler functions.
Patrick Venture0b02be92018-08-31 11:55:55 -0700203ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
204 ipmi_request_t request, ipmi_response_t response,
205 ipmi_data_len_t data_len)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530206{
207 // return from the Command handlers.
208 ipmi_ret_t rc = IPMI_CC_INVALID;
209
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500210 // If restricted mode is true and command is not whitelisted, don't
211 // execute the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700212 if (restricted_mode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500213 {
214 if (!std::binary_search(whitelist.cbegin(), whitelist.cend(),
Patrick Venture0b02be92018-08-31 11:55:55 -0700215 std::make_pair(netfn, cmd)))
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500216 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530217 log<level::ERR>("Net function not whitelisted",
Patrick Venture0b02be92018-08-31 11:55:55 -0700218 entry("NETFN=0x%X", netfn), entry("CMD=0x%X", cmd));
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500219 rc = IPMI_CC_INSUFFICIENT_PRIVILEGE;
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700220 std::memcpy(response, &rc, IPMI_CC_LEN);
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500221 *data_len = IPMI_CC_LEN;
222 return rc;
223 }
224 }
225
vishwabmcba0bd5f2015-09-30 16:50:23 +0530226 // Walk the map that has the registered handlers and invoke the approprite
227 // handlers for matching commands.
228 auto iter = g_ipmid_router_map.find(std::make_pair(netfn, cmd));
Patrick Venture0b02be92018-08-31 11:55:55 -0700229 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530230 {
Patrick Venture03f84ba2017-09-20 09:15:33 -0700231 /* By default should only print on failure to find wildcard command. */
232#ifdef __IPMI_DEBUG__
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530233 log<level::ERR>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700234 "No registered handlers for NetFn, trying Wilcard implementation",
235 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", IPMI_CMD_WILDCARD));
Patrick Venture03f84ba2017-09-20 09:15:33 -0700236#endif
vishwabmcba0bd5f2015-09-30 16:50:23 +0530237
238 // Now that we did not find any specific [NetFn,Cmd], tuple, check for
239 // NetFn, WildCard command present.
Patrick Venture0b02be92018-08-31 11:55:55 -0700240 iter =
241 g_ipmid_router_map.find(std::make_pair(netfn, IPMI_CMD_WILDCARD));
242 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530243 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530244 log<level::ERR>("No Registered handlers for NetFn",
245 entry("NET_FUN=0x%X", netfn),
246 entry("CMD=0x%X", IPMI_CMD_WILDCARD));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530247
248 // Respond with a 0xC1
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700249 std::memcpy(response, &rc, IPMI_CC_LEN);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530250 *data_len = IPMI_CC_LEN;
251 return rc;
252 }
253 }
254
255#ifdef __IPMI_DEBUG__
256 // We have either a perfect match -OR- a wild card atleast,
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530257 log<level::ERR>("Calling Net function",
Patrick Venture0b02be92018-08-31 11:55:55 -0700258 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530259#endif
260
261 // Extract the map data onto appropriate containers
262 auto handler_and_context = iter->second;
263
264 // Creating a pointer type casted to char* to make sure we advance 1 byte
265 // when we advance pointer to next's address. advancing void * would not
266 // make sense.
Patrick Venture0b02be92018-08-31 11:55:55 -0700267 char* respo = &((char*)response)[IPMI_CC_LEN];
vishwabmcba0bd5f2015-09-30 16:50:23 +0530268
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530269 try
270 {
271 // Response message from the plugin goes into a byte post the base
272 // response
Patrick Venture0b02be92018-08-31 11:55:55 -0700273 rc = (handler_and_context.first)(netfn, cmd, request, respo, data_len,
274 handler_and_context.second);
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530275 }
276 // IPMI command handlers can throw unhandled exceptions, catch those
277 // and return sane error code.
Patrick Venture0b02be92018-08-31 11:55:55 -0700278 catch (const std::exception& e)
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530279 {
280 log<level::ERR>(e.what(), entry("NET_FUN=0x%X", netfn),
281 entry("CMD=0x%X", cmd));
282 rc = IPMI_CC_UNSPECIFIED_ERROR;
283 *data_len = 0;
284 // fall through
285 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530286 // Now copy the return code that we got from handler and pack it in first
287 // byte.
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700288 std::memcpy(response, &rc, IPMI_CC_LEN);
Chris Austen120f7322015-10-14 23:27:31 -0500289
vishwabmcba0bd5f2015-09-30 16:50:23 +0530290 // Data length is now actual data + completion code.
291 *data_len = *data_len + IPMI_CC_LEN;
292
293 return rc;
294}
295
Patrick Venture0b02be92018-08-31 11:55:55 -0700296static int send_ipmi_message(sd_bus_message* req, unsigned char seq,
297 unsigned char netfn, unsigned char lun,
298 unsigned char cmd, unsigned char cc,
299 unsigned char* buf, unsigned char len)
300{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530301
Chris Austen0ba649e2015-10-13 12:28:13 -0500302 sd_bus_error error = SD_BUS_ERROR_NULL;
Patrick Venture0b02be92018-08-31 11:55:55 -0700303 sd_bus_message *reply = NULL, *m = NULL;
Jeremy Kerre41081f2015-10-27 12:11:36 +0800304 const char *dest, *path;
Chris Austen0ba649e2015-10-13 12:28:13 -0500305 int r, pty;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530306
Jeremy Kerre41081f2015-10-27 12:11:36 +0800307 dest = sd_bus_message_get_sender(req);
308 path = sd_bus_message_get_path(req);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530309
Patrick Venture0b02be92018-08-31 11:55:55 -0700310 r = sd_bus_message_new_method_call(bus, &m, dest, path, DBUS_INTF,
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530311 "sendMessage");
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 method object",
315 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500316 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530317 }
318
Chris Austenabfb5e82015-10-13 12:29:24 -0500319 // Responses in IPMI require a bit set. So there ya go...
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800320 netfn |= 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530321
Chris Austen0ba649e2015-10-13 12:28:13 -0500322 // Add the bytes needed for the methods to be called
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800323 r = sd_bus_message_append(m, "yyyyy", seq, netfn, lun, cmd, cc);
Patrick Venture0b02be92018-08-31 11:55:55 -0700324 if (r < 0)
325 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530326 log<level::ERR>("Failed add the netfn and others",
327 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600328 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500329 }
Chris Austen120f7322015-10-14 23:27:31 -0500330
Chris Austen0ba649e2015-10-13 12:28:13 -0500331 r = sd_bus_message_append_array(m, 'y', buf, len);
Patrick Venture0b02be92018-08-31 11:55:55 -0700332 if (r < 0)
333 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530334 log<level::ERR>("Failed to add the string of response bytes",
335 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600336 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500337 }
338
Chris Austen0ba649e2015-10-13 12:28:13 -0500339 // Call the IPMI responder on the bus so the message can be sent to the CEC
340 r = sd_bus_call(bus, m, 0, &error, &reply);
Patrick Venture0b02be92018-08-31 11:55:55 -0700341 if (r < 0)
342 {
343 log<level::ERR>("Failed to call the method", entry("DEST=%s", dest),
344 entry("PATH=%s", path), entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600345 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500346 }
347
348 r = sd_bus_message_read(reply, "x", &pty);
Patrick Venture0b02be92018-08-31 11:55:55 -0700349 if (r < 0)
350 {
351 log<level::ERR>("Failed to get a reply from the method",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530352 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500353 }
354
Chris Austen169395e2015-12-02 20:56:15 -0600355final:
Chris Austen0ba649e2015-10-13 12:28:13 -0500356 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600357 m = sd_bus_message_unref(m);
358 reply = sd_bus_message_unref(reply);
Chris Austen0ba649e2015-10-13 12:28:13 -0500359
Chris Austen0ba649e2015-10-13 12:28:13 -0500360 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Chris Austen0ba649e2015-10-13 12:28:13 -0500361}
362
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500363void cache_restricted_mode()
364{
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500365 restricted_mode = false;
366 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
367 using namespace internal;
368 using namespace internal::cache;
369 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
370 const auto& restrictionModeSetting =
Deepak Kodihallie6027092017-08-27 08:13:37 -0500371 objects->map.at(restrictionModeIntf).front();
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500372 auto method = dbus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700373 objects->service(restrictionModeSetting, restrictionModeIntf).c_str(),
374 restrictionModeSetting.c_str(), "org.freedesktop.DBus.Properties",
375 "Get");
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500376 method.append(restrictionModeIntf, "RestrictionMode");
377 auto resp = dbus.call(method);
378 if (resp.is_method_error())
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500379 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500380 log<level::ERR>("Error in RestrictionMode Get");
381 // Fail-safe to true.
382 restricted_mode = true;
383 return;
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500384 }
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500385 sdbusplus::message::variant<std::string> result;
386 resp.read(result);
William A. Kennington III4c008022018-10-12 17:18:14 -0700387 auto restrictionMode = RestrictionMode::convertModesFromString(
388 variant_ns::get<std::string>(result));
Patrick Venture0b02be92018-08-31 11:55:55 -0700389 if (RestrictionMode::Modes::Whitelist == restrictionMode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500390 {
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500391 restricted_mode = true;
392 }
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500393}
394
Patrick Venture0b02be92018-08-31 11:55:55 -0700395static int handle_restricted_mode_change(sd_bus_message* m, void* user_data,
396 sd_bus_error* ret_error)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500397{
398 cache_restricted_mode();
399 return 0;
400}
401
Patrick Venture0b02be92018-08-31 11:55:55 -0700402static int handle_ipmi_command(sd_bus_message* m, void* user_data,
403 sd_bus_error* ret_error)
404{
Chris Austen0ba649e2015-10-13 12:28:13 -0500405 int r = 0;
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800406 unsigned char sequence, netfn, lun, cmd;
Patrick Venture0b02be92018-08-31 11:55:55 -0700407 const void* request;
Chris Austen0ba649e2015-10-13 12:28:13 -0500408 size_t sz;
Patrick Venture0b02be92018-08-31 11:55:55 -0700409 size_t resplen = MAX_IPMI_BUFFER;
Chris Austen0ba649e2015-10-13 12:28:13 -0500410 unsigned char response[MAX_IPMI_BUFFER];
411
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700412 std::memset(response, 0, MAX_IPMI_BUFFER);
Chris Austen0ba649e2015-10-13 12:28:13 -0500413
Patrick Venture0b02be92018-08-31 11:55:55 -0700414 r = sd_bus_message_read(m, "yyyy", &sequence, &netfn, &lun, &cmd);
415 if (r < 0)
416 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530417 log<level::ERR>("Failed to parse signal message",
418 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500419 return -1;
420 }
421
Patrick Venture0b02be92018-08-31 11:55:55 -0700422 r = sd_bus_message_read_array(m, 'y', &request, &sz);
423 if (r < 0)
424 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530425 log<level::ERR>("Failed to parse signal message",
426 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500427 return -1;
428 }
429
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700430 std::fprintf(ipmiio,
431 "IPMI Incoming: Seq 0x%02x, NetFn 0x%02x, CMD: 0x%02x \n",
432 sequence, netfn, cmd);
Chris Austen99497312015-10-22 13:00:16 -0500433 hexdump(ipmiio, (void*)request, sz);
Chris Austen0ba649e2015-10-13 12:28:13 -0500434
Chris Austen120f7322015-10-14 23:27:31 -0500435 // Allow the length field to be used for both input and output of the
Chris Austen0ba649e2015-10-13 12:28:13 -0500436 // ipmi call
437 resplen = sz;
438
Chris Austen120f7322015-10-14 23:27:31 -0500439 // Now that we have parsed the entire byte array from the caller
vishwabmcba0bd5f2015-09-30 16:50:23 +0530440 // we can call the ipmi router to do the work...
Patrick Venture0b02be92018-08-31 11:55:55 -0700441 r = ipmi_netfn_router(netfn, cmd, (void*)request, (void*)response,
442 &resplen);
443 if (r != 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530444 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530445#ifdef __IPMI_DEBUG__
Patrick Venture0b02be92018-08-31 11:55:55 -0700446 log<level::ERR>("ERROR in handling NetFn", entry("ERRNO=0x%X", -r),
447 entry("NET_FUN=0x%X", netfn), entry("CMD=0x%X", cmd));
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530448#endif
Ratan Guptae0cc8552018-01-22 14:23:04 +0530449 resplen = 0;
450 }
451 else
452 {
453 resplen = resplen - 1; // first byte is for return code.
vishwabmcba0bd5f2015-09-30 16:50:23 +0530454 }
455
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700456 std::fprintf(ipmiio, "IPMI Response:\n");
Patrick Venture0b02be92018-08-31 11:55:55 -0700457 hexdump(ipmiio, (void*)response, resplen);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530458
Chris Austen0ba649e2015-10-13 12:28:13 -0500459 // Send the response buffer from the ipmi command
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800460 r = send_ipmi_message(m, sequence, netfn, lun, cmd, response[0],
Patrick Venture0b02be92018-08-31 11:55:55 -0700461 ((unsigned char*)response) + 1, resplen);
462 if (r < 0)
463 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530464 log<level::ERR>("Failed to send the response message");
Chris Austen0ba649e2015-10-13 12:28:13 -0500465 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530466 }
467
Chris Austen0ba649e2015-10-13 12:28:13 -0500468 return 0;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530469}
470
471//----------------------------------------------------------------------
472// handler_select
473// Select all the files ending with with .so. in the given diretcory
474// @d: dirent structure containing the file name
475//----------------------------------------------------------------------
Patrick Venture0b02be92018-08-31 11:55:55 -0700476int handler_select(const struct dirent* entry)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530477{
478 // To hold ".so" from entry->d_name;
479 char dname_copy[4] = {0};
480
481 // We want to avoid checking for everything and isolate to the ones having
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500482 // .so.* or .so in them.
483 // Check for versioned libraries .so.*
Patrick Venture0b02be92018-08-31 11:55:55 -0700484 if (strstr(entry->d_name, IPMI_PLUGIN_SONAME_EXTN))
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500485 {
486 return 1;
487 }
488 // Check for non versioned libraries .so
Patrick Venture0b02be92018-08-31 11:55:55 -0700489 else if (strstr(entry->d_name, IPMI_PLUGIN_EXTN))
vishwabmcba0bd5f2015-09-30 16:50:23 +0530490 {
491 // It is possible that .so could be anywhere in the string but unlikely
Chris Austen120f7322015-10-14 23:27:31 -0500492 // But being careful here. Get the base address of the string, move
vishwabmcba0bd5f2015-09-30 16:50:23 +0530493 // until end and come back 3 steps and that gets what we need.
Patrick Venture0b02be92018-08-31 11:55:55 -0700494 strcpy(dname_copy, (entry->d_name + strlen(entry->d_name) -
495 strlen(IPMI_PLUGIN_EXTN)));
496 if (strcmp(dname_copy, IPMI_PLUGIN_EXTN) == 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530497 {
498 return 1;
499 }
500 }
501 return 0;
502}
503
Patrick Venture0b02be92018-08-31 11:55:55 -0700504// This will do a dlopen of every .so in ipmi_lib_path and will dlopen
505// everything so that they will register a callback handler
vishwabmcba0bd5f2015-09-30 16:50:23 +0530506void ipmi_register_callback_handlers(const char* ipmi_lib_path)
507{
508 // For walking the ipmi_lib_path
Patrick Venture0b02be92018-08-31 11:55:55 -0700509 struct dirent** handler_list;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530510
511 // This is used to check and abort if someone tries to register a bad one.
Patrick Venture0b02be92018-08-31 11:55:55 -0700512 void* lib_handler = NULL;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530513
Patrick Venture0b02be92018-08-31 11:55:55 -0700514 if (ipmi_lib_path == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530515 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530516 log<level::ERR>("No handlers to be registered for ipmi.. Aborting");
vishwabmcba0bd5f2015-09-30 16:50:23 +0530517 assert(0);
518 }
519 else
520 {
521 // 1: Open ipmi_lib_path. Its usually "/usr/lib/phosphor-host-ipmid"
522 // 2: Scan the directory for the files that end with .so
Chris Austen120f7322015-10-14 23:27:31 -0500523 // 3: For each one of them, just do a 'dlopen' so that they register
vishwabmcba0bd5f2015-09-30 16:50:23 +0530524 // the handlers for callback routines.
525
526 std::string handler_fqdn = ipmi_lib_path;
Chris Austen120f7322015-10-14 23:27:31 -0500527
vishwabmcba0bd5f2015-09-30 16:50:23 +0530528 // Append a "/" since we need to add the name of the .so. If there is
529 // already a .so, adding one more is not any harm.
530 handler_fqdn += "/";
531
Patrick Venture4491a462018-10-13 13:00:42 -0700532 int num_handlers =
Patrick Venture0b02be92018-08-31 11:55:55 -0700533 scandir(ipmi_lib_path, &handler_list, handler_select, alphasort);
Nan Li36c0cb62016-03-31 11:16:08 +0800534 if (num_handlers < 0)
535 return;
Jeremy Kerr5e8f85e2015-10-27 13:43:54 +0800536
Patrick Venture0b02be92018-08-31 11:55:55 -0700537 while (num_handlers--)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530538 {
Chris Austen54030262015-10-13 12:30:46 -0500539 handler_fqdn = ipmi_lib_path;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530540 handler_fqdn += handler_list[num_handlers]->d_name;
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530541#ifdef __IPMI_DEBUG__
542 log<level::DEBUG>("Registering handler",
543 entry("HANDLER=%s", handler_fqdn.c_str()));
544#endif
Chris Austen54030262015-10-13 12:30:46 -0500545
vishwabmcba0bd5f2015-09-30 16:50:23 +0530546 lib_handler = dlopen(handler_fqdn.c_str(), RTLD_NOW);
Nan Li36c0cb62016-03-31 11:16:08 +0800547
Patrick Venture0b02be92018-08-31 11:55:55 -0700548 if (lib_handler == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530549 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530550 log<level::ERR>("ERROR opening",
551 entry("HANDLER=%s", handler_fqdn.c_str()),
552 entry("ERROR=%s", dlerror()));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530553 }
554 // Wipe the memory allocated for this particular entry.
555 free(handler_list[num_handlers]);
556 }
Nan Li36c0cb62016-03-31 11:16:08 +0800557
vishwabmcba0bd5f2015-09-30 16:50:23 +0530558 // Done with all registration.
559 free(handler_list);
560 }
561
562 // TODO : What to be done on the memory that is given by dlopen ?.
563 return;
564}
565
Patrick Venture0b02be92018-08-31 11:55:55 -0700566sd_bus* ipmid_get_sd_bus_connection(void)
567{
Chris Austen30195fa2015-11-13 14:39:19 -0600568 return bus;
569}
570
Patrick Venture0b02be92018-08-31 11:55:55 -0700571sd_event* ipmid_get_sd_event_connection(void)
572{
Andrew Geissler93c679b2017-04-02 10:06:43 -0500573 return events;
574}
575
Patrick Venture0b02be92018-08-31 11:55:55 -0700576sd_bus_slot* ipmid_get_sd_bus_slot(void)
577{
vishwab9f559a2016-01-13 01:53:08 -0600578 return ipmid_slot;
579}
580
ssekarb8491102018-08-16 17:31:43 +0530581EInterfaceIndex getInterfaceIndex(void)
582{
583 return interfaceKCS;
584}
585
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530586// Calls host command manager to do the right thing for the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700587void ipmid_send_cmd_to_host(CommandHandler&& cmd)
588{
589 return cmdManager->execute(std::move(cmd));
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530590}
591
Patrick Venture0b02be92018-08-31 11:55:55 -0700592cmdManagerPtr& ipmid_get_host_cmd_manager()
593{
594 return cmdManager;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530595}
596
Patrick Venture0b02be92018-08-31 11:55:55 -0700597sdbusPtr& ipmid_get_sdbus_plus_handler()
598{
599 return sdbusp;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530600}
601
Patrick Venture0b02be92018-08-31 11:55:55 -0700602int main(int argc, char* argv[])
vishwabmcba0bd5f2015-09-30 16:50:23 +0530603{
Chris Austen0ba649e2015-10-13 12:28:13 -0500604 int r;
Chris Austen99497312015-10-22 13:00:16 -0500605 unsigned long tvalue;
606 int c;
607
Chris Austen99497312015-10-22 13:00:16 -0500608 // This file and subsequient switch is for turning on levels
609 // of trace
Patrick Venture0b02be92018-08-31 11:55:55 -0700610 ipmicmddetails = ipmiio = ipmidbus = fopen("/dev/null", "w");
Chris Austen99497312015-10-22 13:00:16 -0500611
Patrick Venture0b02be92018-08-31 11:55:55 -0700612 while ((c = getopt(argc, argv, "h:d:")) != -1)
613 switch (c)
614 {
Chris Austen99497312015-10-22 13:00:16 -0500615 case 'd':
Patrick Venture0b02be92018-08-31 11:55:55 -0700616 tvalue = strtoul(optarg, NULL, 16);
617 if (1 & tvalue)
618 {
Chris Austen99497312015-10-22 13:00:16 -0500619 ipmiio = stdout;
620 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700621 if (2 & tvalue)
622 {
Chris Austen99497312015-10-22 13:00:16 -0500623 ipmidbus = stdout;
624 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700625 if (4 & tvalue)
626 {
Chris Austen99497312015-10-22 13:00:16 -0500627 ipmicmddetails = stdout;
628 }
629 break;
Patrick Venture0b02be92018-08-31 11:55:55 -0700630 case 'h':
631 case '?':
Chris Austen99497312015-10-22 13:00:16 -0500632 print_usage();
633 return 1;
634 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500635
Chris Austen0ba649e2015-10-13 12:28:13 -0500636 /* Connect to system bus */
Vernon Mauery46590a32018-11-08 15:29:56 -0800637 r = sd_bus_default_system(&bus);
Patrick Venture0b02be92018-08-31 11:55:55 -0700638 if (r < 0)
639 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530640 log<level::ERR>("Failed to connect to system bus",
641 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500642 goto finish;
643 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530644
Andrew Geissler93c679b2017-04-02 10:06:43 -0500645 /* Get an sd event handler */
646 r = sd_event_default(&events);
647 if (r < 0)
648 {
649 log<level::ERR>("Failure to create sd_event handler",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530650 entry("ERRNO=0x%X", -r));
Andrew Geissler93c679b2017-04-02 10:06:43 -0500651 goto finish;
652 }
653
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530654 // Now create the Host Bound Command manager. Need sdbusplus
655 // to use the generated bindings
656 sdbusp = std::make_unique<sdbusplus::bus::bus>(bus);
James Feist331f5d52018-11-01 11:03:40 -0700657 sdbusp->request_name("xyz.openbmc_project.Ipmi.Host");
658
Vernon Mauery316f23d2018-10-29 13:34:26 -0700659 cmdManager = std::make_unique<phosphor::host::command::Manager>(*sdbusp);
Andrew Geissler93c679b2017-04-02 10:06:43 -0500660
Peter Hanson4a589852017-06-07 17:40:45 -0700661 // Activate OemRouter.
662 oem::mutableRouter()->activate();
663
Chris Austen30195fa2015-11-13 14:39:19 -0600664 // Register all the handlers that provider implementation to IPMI commands.
665 ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
666
Patrick Venture0b02be92018-08-31 11:55:55 -0700667 // Watch for BT messages
vishwab9f559a2016-01-13 01:53:08 -0600668 r = sd_bus_add_match(bus, &ipmid_slot, FILTER, handle_ipmi_command, NULL);
Patrick Venture0b02be92018-08-31 11:55:55 -0700669 if (r < 0)
670 {
671 log<level::ERR>("Failed: sd_bus_add_match", entry("FILTER=%s", FILTER),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530672 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500673 goto finish;
674 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530675
Andrew Geissler93c679b2017-04-02 10:06:43 -0500676 // Attach the bus to sd_event to service user requests
677 sd_bus_attach_event(bus, events, SD_EVENT_PRIORITY_NORMAL);
678
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500679 {
680 using namespace internal;
681 using namespace internal::cache;
682 sdbusplus::bus::bus dbus{bus};
683 objects = std::make_unique<settings::Objects>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700684 dbus, std::vector<settings::Interface>({restrictionModeIntf}));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500685 // Initialize restricted mode
686 cache_restricted_mode();
687 // Wait for changes on Restricted mode
688 sdbusplus::bus::match_t restrictedModeMatch(
689 dbus,
690 sdbusRule::propertiesChanged(
Deepak Kodihallie6027092017-08-27 08:13:37 -0500691 objects->map.at(restrictionModeIntf).front(),
692 restrictionModeIntf),
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500693 handle_restricted_mode_change);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530694
Andrew Jefferyb975c402018-11-23 15:28:58 +1100695 r = sd_event_loop(events);
Chris Austen0ba649e2015-10-13 12:28:13 -0500696 }
697
698finish:
Andrew Geissler93c679b2017-04-02 10:06:43 -0500699 sd_event_unref(events);
700 sd_bus_detach_event(bus);
vishwab9f559a2016-01-13 01:53:08 -0600701 sd_bus_slot_unref(ipmid_slot);
Chris Austen0ba649e2015-10-13 12:28:13 -0500702 sd_bus_unref(bus);
703 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530704}