blob: be6b4d451c1efef201d12fcc9775c3c556afdc70 [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.
Jason M. Bills13e67c82018-09-10 14:12:16 -070079static unsigned short selReservationID = 0xFFFF;
80static bool selReservationValid = false;
Nan Li36c0cb62016-03-31 11:16:08 +080081
Jason M. Bills13e67c82018-09-10 14:12:16 -070082unsigned short reserveSel(void)
Nan Li36c0cb62016-03-31 11:16:08 +080083{
Jason M. Bills13e67c82018-09-10 14:12:16 -070084 // IPMI spec, Reservation ID, the value simply increases against each
85 // execution of the Reserve SEL command.
86 if (++selReservationID == 0)
87 {
88 selReservationID = 1;
89 }
90 selReservationValid = true;
91 return selReservationID;
92}
93
94bool checkSELReservation(unsigned short id)
95{
96 return (selReservationValid && selReservationID == id);
97}
98
99void cancelSELReservation(void)
100{
101 selReservationValid = false;
Nan Li36c0cb62016-03-31 11:16:08 +0800102}
Chris Austen0ba649e2015-10-13 12:28:13 -0500103
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500104namespace internal
105{
106
107constexpr auto restrictionModeIntf =
108 "xyz.openbmc_project.Control.Security.RestrictionMode";
109
110namespace cache
111{
112
113std::unique_ptr<settings::Objects> objects = nullptr;
114
115} // namespace cache
116} // namespace internal
117
Chris Austen0ba649e2015-10-13 12:28:13 -0500118#ifndef HEXDUMP_COLS
119#define HEXDUMP_COLS 16
120#endif
121
Patrick Venture0b02be92018-08-31 11:55:55 -0700122void hexdump(FILE* s, void* mem, size_t len)
Chris Austen0ba649e2015-10-13 12:28:13 -0500123{
Patrick Venture0b02be92018-08-31 11:55:55 -0700124 unsigned int i, j;
Chris Austen120f7322015-10-14 23:27:31 -0500125
Patrick Venture0b02be92018-08-31 11:55:55 -0700126 for (i = 0;
127 i <
128 len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0);
129 i++)
130 {
131 /* print offset */
132 if (i % HEXDUMP_COLS == 0)
Chris Austen0ba649e2015-10-13 12:28:13 -0500133 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700134 std::fprintf(s, "0x%06x: ", i);
Chris Austen0ba649e2015-10-13 12:28:13 -0500135 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700136
137 /* print hex data */
138 if (i < len)
139 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700140 std::fprintf(s, "%02x ", 0xFF & ((char*)mem)[i]);
Patrick Venture0b02be92018-08-31 11:55:55 -0700141 }
142 else /* end of block, just aligning for ASCII dump */
143 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700144 std::fprintf(s, " ");
Patrick Venture0b02be92018-08-31 11:55:55 -0700145 }
146
147 /* print ASCII dump */
148 if (i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
149 {
150 for (j = i - (HEXDUMP_COLS - 1); j <= i; j++)
151 {
152 if (j >= len) /* end of block, not really printing */
153 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700154 std::fputc(' ', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700155 }
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700156 else if (std::isprint(((char*)mem)[j])) /* printable char */
Patrick Venture0b02be92018-08-31 11:55:55 -0700157 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700158 std::fputc(0xFF & ((char*)mem)[j], s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700159 }
160 else /* other char */
161 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700162 std::fputc('.', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700163 }
164 }
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700165 std::fputc('\n', s);
Patrick Venture0b02be92018-08-31 11:55:55 -0700166 }
167 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500168}
169
Patrick Venture0b02be92018-08-31 11:55:55 -0700170// Method that gets called by shared libraries to get their command handlers
171// registered
172void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
173 ipmi_context_t context, ipmid_callback_t handler,
174 ipmi_cmd_privilege_t priv)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530175{
176 // Pack NetFn and Command in one.
177 auto netfn_and_cmd = std::make_pair(netfn, cmd);
178
179 // Pack Function handler and Data in another.
180 auto handler_and_context = std::make_pair(handler, context);
181
182 // Check if the registration has already been made..
183 auto iter = g_ipmid_router_map.find(netfn_and_cmd);
Patrick Venture0b02be92018-08-31 11:55:55 -0700184 if (iter != g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530185 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700186 log<level::ERR>("Duplicate registration", entry("NETFN=0x%X", netfn),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530187 entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530188 }
189 else
190 {
191 // This is a fresh registration.. Add it to the map.
192 g_ipmid_router_map.emplace(netfn_and_cmd, handler_and_context);
193 }
194
195 return;
196}
197
198// Looks at the map and calls corresponding handler functions.
Patrick Venture0b02be92018-08-31 11:55:55 -0700199ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
200 ipmi_request_t request, ipmi_response_t response,
201 ipmi_data_len_t data_len)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530202{
203 // return from the Command handlers.
204 ipmi_ret_t rc = IPMI_CC_INVALID;
205
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500206 // If restricted mode is true and command is not whitelisted, don't
207 // execute the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700208 if (restricted_mode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500209 {
210 if (!std::binary_search(whitelist.cbegin(), whitelist.cend(),
Patrick Venture0b02be92018-08-31 11:55:55 -0700211 std::make_pair(netfn, cmd)))
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500212 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530213 log<level::ERR>("Net function not whitelisted",
Patrick Venture0b02be92018-08-31 11:55:55 -0700214 entry("NETFN=0x%X", netfn), entry("CMD=0x%X", cmd));
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500215 rc = IPMI_CC_INSUFFICIENT_PRIVILEGE;
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700216 std::memcpy(response, &rc, IPMI_CC_LEN);
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500217 *data_len = IPMI_CC_LEN;
218 return rc;
219 }
220 }
221
vishwabmcba0bd5f2015-09-30 16:50:23 +0530222 // Walk the map that has the registered handlers and invoke the approprite
223 // handlers for matching commands.
224 auto iter = g_ipmid_router_map.find(std::make_pair(netfn, cmd));
Patrick Venture0b02be92018-08-31 11:55:55 -0700225 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530226 {
Patrick Venture03f84ba2017-09-20 09:15:33 -0700227 /* By default should only print on failure to find wildcard command. */
228#ifdef __IPMI_DEBUG__
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530229 log<level::ERR>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700230 "No registered handlers for NetFn, trying Wilcard implementation",
231 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", IPMI_CMD_WILDCARD));
Patrick Venture03f84ba2017-09-20 09:15:33 -0700232#endif
vishwabmcba0bd5f2015-09-30 16:50:23 +0530233
234 // Now that we did not find any specific [NetFn,Cmd], tuple, check for
235 // NetFn, WildCard command present.
Patrick Venture0b02be92018-08-31 11:55:55 -0700236 iter =
237 g_ipmid_router_map.find(std::make_pair(netfn, IPMI_CMD_WILDCARD));
238 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530239 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530240 log<level::ERR>("No Registered handlers for NetFn",
241 entry("NET_FUN=0x%X", netfn),
242 entry("CMD=0x%X", IPMI_CMD_WILDCARD));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530243
244 // Respond with a 0xC1
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700245 std::memcpy(response, &rc, IPMI_CC_LEN);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530246 *data_len = IPMI_CC_LEN;
247 return rc;
248 }
249 }
250
251#ifdef __IPMI_DEBUG__
252 // We have either a perfect match -OR- a wild card atleast,
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530253 log<level::ERR>("Calling Net function",
Patrick Venture0b02be92018-08-31 11:55:55 -0700254 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530255#endif
256
257 // Extract the map data onto appropriate containers
258 auto handler_and_context = iter->second;
259
260 // Creating a pointer type casted to char* to make sure we advance 1 byte
261 // when we advance pointer to next's address. advancing void * would not
262 // make sense.
Patrick Venture0b02be92018-08-31 11:55:55 -0700263 char* respo = &((char*)response)[IPMI_CC_LEN];
vishwabmcba0bd5f2015-09-30 16:50:23 +0530264
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530265 try
266 {
267 // Response message from the plugin goes into a byte post the base
268 // response
Patrick Venture0b02be92018-08-31 11:55:55 -0700269 rc = (handler_and_context.first)(netfn, cmd, request, respo, data_len,
270 handler_and_context.second);
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530271 }
272 // IPMI command handlers can throw unhandled exceptions, catch those
273 // and return sane error code.
Patrick Venture0b02be92018-08-31 11:55:55 -0700274 catch (const std::exception& e)
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530275 {
276 log<level::ERR>(e.what(), entry("NET_FUN=0x%X", netfn),
277 entry("CMD=0x%X", cmd));
278 rc = IPMI_CC_UNSPECIFIED_ERROR;
279 *data_len = 0;
280 // fall through
281 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530282 // Now copy the return code that we got from handler and pack it in first
283 // byte.
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700284 std::memcpy(response, &rc, IPMI_CC_LEN);
Chris Austen120f7322015-10-14 23:27:31 -0500285
vishwabmcba0bd5f2015-09-30 16:50:23 +0530286 // Data length is now actual data + completion code.
287 *data_len = *data_len + IPMI_CC_LEN;
288
289 return rc;
290}
291
Patrick Venture0b02be92018-08-31 11:55:55 -0700292static int send_ipmi_message(sd_bus_message* req, unsigned char seq,
293 unsigned char netfn, unsigned char lun,
294 unsigned char cmd, unsigned char cc,
295 unsigned char* buf, unsigned char len)
296{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530297
Chris Austen0ba649e2015-10-13 12:28:13 -0500298 sd_bus_error error = SD_BUS_ERROR_NULL;
Patrick Venture0b02be92018-08-31 11:55:55 -0700299 sd_bus_message *reply = NULL, *m = NULL;
Jeremy Kerre41081f2015-10-27 12:11:36 +0800300 const char *dest, *path;
Chris Austen0ba649e2015-10-13 12:28:13 -0500301 int r, pty;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530302
Jeremy Kerre41081f2015-10-27 12:11:36 +0800303 dest = sd_bus_message_get_sender(req);
304 path = sd_bus_message_get_path(req);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530305
Patrick Venture0b02be92018-08-31 11:55:55 -0700306 r = sd_bus_message_new_method_call(bus, &m, dest, path, DBUS_INTF,
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530307 "sendMessage");
Patrick Venture0b02be92018-08-31 11:55:55 -0700308 if (r < 0)
309 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530310 log<level::ERR>("Failed to add the method object",
311 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500312 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530313 }
314
Chris Austenabfb5e82015-10-13 12:29:24 -0500315 // Responses in IPMI require a bit set. So there ya go...
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800316 netfn |= 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530317
Chris Austen0ba649e2015-10-13 12:28:13 -0500318 // Add the bytes needed for the methods to be called
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800319 r = sd_bus_message_append(m, "yyyyy", seq, netfn, lun, cmd, cc);
Patrick Venture0b02be92018-08-31 11:55:55 -0700320 if (r < 0)
321 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530322 log<level::ERR>("Failed add the netfn and others",
323 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600324 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500325 }
Chris Austen120f7322015-10-14 23:27:31 -0500326
Chris Austen0ba649e2015-10-13 12:28:13 -0500327 r = sd_bus_message_append_array(m, 'y', buf, len);
Patrick Venture0b02be92018-08-31 11:55:55 -0700328 if (r < 0)
329 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530330 log<level::ERR>("Failed to add the string of response bytes",
331 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600332 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500333 }
334
Chris Austen0ba649e2015-10-13 12:28:13 -0500335 // Call the IPMI responder on the bus so the message can be sent to the CEC
336 r = sd_bus_call(bus, m, 0, &error, &reply);
Patrick Venture0b02be92018-08-31 11:55:55 -0700337 if (r < 0)
338 {
339 log<level::ERR>("Failed to call the method", entry("DEST=%s", dest),
340 entry("PATH=%s", path), entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600341 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500342 }
343
344 r = sd_bus_message_read(reply, "x", &pty);
Patrick Venture0b02be92018-08-31 11:55:55 -0700345 if (r < 0)
346 {
347 log<level::ERR>("Failed to get a reply from the method",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530348 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500349 }
350
Chris Austen169395e2015-12-02 20:56:15 -0600351final:
Chris Austen0ba649e2015-10-13 12:28:13 -0500352 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600353 m = sd_bus_message_unref(m);
354 reply = sd_bus_message_unref(reply);
Chris Austen0ba649e2015-10-13 12:28:13 -0500355
Chris Austen0ba649e2015-10-13 12:28:13 -0500356 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Chris Austen0ba649e2015-10-13 12:28:13 -0500357}
358
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500359void cache_restricted_mode()
360{
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500361 restricted_mode = false;
362 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
363 using namespace internal;
364 using namespace internal::cache;
365 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
366 const auto& restrictionModeSetting =
Deepak Kodihallie6027092017-08-27 08:13:37 -0500367 objects->map.at(restrictionModeIntf).front();
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500368 auto method = dbus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700369 objects->service(restrictionModeSetting, restrictionModeIntf).c_str(),
370 restrictionModeSetting.c_str(), "org.freedesktop.DBus.Properties",
371 "Get");
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500372 method.append(restrictionModeIntf, "RestrictionMode");
373 auto resp = dbus.call(method);
374 if (resp.is_method_error())
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500375 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500376 log<level::ERR>("Error in RestrictionMode Get");
377 // Fail-safe to true.
378 restricted_mode = true;
379 return;
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500380 }
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500381 sdbusplus::message::variant<std::string> result;
382 resp.read(result);
383 auto restrictionMode =
384 RestrictionMode::convertModesFromString(result.get<std::string>());
Patrick Venture0b02be92018-08-31 11:55:55 -0700385 if (RestrictionMode::Modes::Whitelist == restrictionMode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500386 {
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500387 restricted_mode = true;
388 }
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500389}
390
Patrick Venture0b02be92018-08-31 11:55:55 -0700391static int handle_restricted_mode_change(sd_bus_message* m, void* user_data,
392 sd_bus_error* ret_error)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500393{
394 cache_restricted_mode();
395 return 0;
396}
397
Patrick Venture0b02be92018-08-31 11:55:55 -0700398static int handle_ipmi_command(sd_bus_message* m, void* user_data,
399 sd_bus_error* ret_error)
400{
Chris Austen0ba649e2015-10-13 12:28:13 -0500401 int r = 0;
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800402 unsigned char sequence, netfn, lun, cmd;
Patrick Venture0b02be92018-08-31 11:55:55 -0700403 const void* request;
Chris Austen0ba649e2015-10-13 12:28:13 -0500404 size_t sz;
Patrick Venture0b02be92018-08-31 11:55:55 -0700405 size_t resplen = MAX_IPMI_BUFFER;
Chris Austen0ba649e2015-10-13 12:28:13 -0500406 unsigned char response[MAX_IPMI_BUFFER];
407
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700408 std::memset(response, 0, MAX_IPMI_BUFFER);
Chris Austen0ba649e2015-10-13 12:28:13 -0500409
Patrick Venture0b02be92018-08-31 11:55:55 -0700410 r = sd_bus_message_read(m, "yyyy", &sequence, &netfn, &lun, &cmd);
411 if (r < 0)
412 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530413 log<level::ERR>("Failed to parse signal message",
414 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500415 return -1;
416 }
417
Patrick Venture0b02be92018-08-31 11:55:55 -0700418 r = sd_bus_message_read_array(m, 'y', &request, &sz);
419 if (r < 0)
420 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530421 log<level::ERR>("Failed to parse signal message",
422 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500423 return -1;
424 }
425
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700426 std::fprintf(ipmiio,
427 "IPMI Incoming: Seq 0x%02x, NetFn 0x%02x, CMD: 0x%02x \n",
428 sequence, netfn, cmd);
Chris Austen99497312015-10-22 13:00:16 -0500429 hexdump(ipmiio, (void*)request, sz);
Chris Austen0ba649e2015-10-13 12:28:13 -0500430
Chris Austen120f7322015-10-14 23:27:31 -0500431 // Allow the length field to be used for both input and output of the
Chris Austen0ba649e2015-10-13 12:28:13 -0500432 // ipmi call
433 resplen = sz;
434
Chris Austen120f7322015-10-14 23:27:31 -0500435 // Now that we have parsed the entire byte array from the caller
vishwabmcba0bd5f2015-09-30 16:50:23 +0530436 // we can call the ipmi router to do the work...
Patrick Venture0b02be92018-08-31 11:55:55 -0700437 r = ipmi_netfn_router(netfn, cmd, (void*)request, (void*)response,
438 &resplen);
439 if (r != 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530440 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530441#ifdef __IPMI_DEBUG__
Patrick Venture0b02be92018-08-31 11:55:55 -0700442 log<level::ERR>("ERROR in handling NetFn", entry("ERRNO=0x%X", -r),
443 entry("NET_FUN=0x%X", netfn), entry("CMD=0x%X", cmd));
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530444#endif
Ratan Guptae0cc8552018-01-22 14:23:04 +0530445 resplen = 0;
446 }
447 else
448 {
449 resplen = resplen - 1; // first byte is for return code.
vishwabmcba0bd5f2015-09-30 16:50:23 +0530450 }
451
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700452 std::fprintf(ipmiio, "IPMI Response:\n");
Patrick Venture0b02be92018-08-31 11:55:55 -0700453 hexdump(ipmiio, (void*)response, resplen);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530454
Chris Austen0ba649e2015-10-13 12:28:13 -0500455 // Send the response buffer from the ipmi command
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800456 r = send_ipmi_message(m, sequence, netfn, lun, cmd, response[0],
Patrick Venture0b02be92018-08-31 11:55:55 -0700457 ((unsigned char*)response) + 1, resplen);
458 if (r < 0)
459 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530460 log<level::ERR>("Failed to send the response message");
Chris Austen0ba649e2015-10-13 12:28:13 -0500461 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530462 }
463
Chris Austen0ba649e2015-10-13 12:28:13 -0500464 return 0;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530465}
466
467//----------------------------------------------------------------------
468// handler_select
469// Select all the files ending with with .so. in the given diretcory
470// @d: dirent structure containing the file name
471//----------------------------------------------------------------------
Patrick Venture0b02be92018-08-31 11:55:55 -0700472int handler_select(const struct dirent* entry)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530473{
474 // To hold ".so" from entry->d_name;
475 char dname_copy[4] = {0};
476
477 // We want to avoid checking for everything and isolate to the ones having
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500478 // .so.* or .so in them.
479 // Check for versioned libraries .so.*
Patrick Venture0b02be92018-08-31 11:55:55 -0700480 if (strstr(entry->d_name, IPMI_PLUGIN_SONAME_EXTN))
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500481 {
482 return 1;
483 }
484 // Check for non versioned libraries .so
Patrick Venture0b02be92018-08-31 11:55:55 -0700485 else if (strstr(entry->d_name, IPMI_PLUGIN_EXTN))
vishwabmcba0bd5f2015-09-30 16:50:23 +0530486 {
487 // It is possible that .so could be anywhere in the string but unlikely
Chris Austen120f7322015-10-14 23:27:31 -0500488 // But being careful here. Get the base address of the string, move
vishwabmcba0bd5f2015-09-30 16:50:23 +0530489 // until end and come back 3 steps and that gets what we need.
Patrick Venture0b02be92018-08-31 11:55:55 -0700490 strcpy(dname_copy, (entry->d_name + strlen(entry->d_name) -
491 strlen(IPMI_PLUGIN_EXTN)));
492 if (strcmp(dname_copy, IPMI_PLUGIN_EXTN) == 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530493 {
494 return 1;
495 }
496 }
497 return 0;
498}
499
Patrick Venture0b02be92018-08-31 11:55:55 -0700500// This will do a dlopen of every .so in ipmi_lib_path and will dlopen
501// everything so that they will register a callback handler
vishwabmcba0bd5f2015-09-30 16:50:23 +0530502void ipmi_register_callback_handlers(const char* ipmi_lib_path)
503{
504 // For walking the ipmi_lib_path
Patrick Venture0b02be92018-08-31 11:55:55 -0700505 struct dirent** handler_list;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530506 int num_handlers = 0;
507
508 // This is used to check and abort if someone tries to register a bad one.
Patrick Venture0b02be92018-08-31 11:55:55 -0700509 void* lib_handler = NULL;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530510
Patrick Venture0b02be92018-08-31 11:55:55 -0700511 if (ipmi_lib_path == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530512 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530513 log<level::ERR>("No handlers to be registered for ipmi.. Aborting");
vishwabmcba0bd5f2015-09-30 16:50:23 +0530514 assert(0);
515 }
516 else
517 {
518 // 1: Open ipmi_lib_path. Its usually "/usr/lib/phosphor-host-ipmid"
519 // 2: Scan the directory for the files that end with .so
Chris Austen120f7322015-10-14 23:27:31 -0500520 // 3: For each one of them, just do a 'dlopen' so that they register
vishwabmcba0bd5f2015-09-30 16:50:23 +0530521 // the handlers for callback routines.
522
523 std::string handler_fqdn = ipmi_lib_path;
Chris Austen120f7322015-10-14 23:27:31 -0500524
vishwabmcba0bd5f2015-09-30 16:50:23 +0530525 // Append a "/" since we need to add the name of the .so. If there is
526 // already a .so, adding one more is not any harm.
527 handler_fqdn += "/";
528
Patrick Venture0b02be92018-08-31 11:55:55 -0700529 num_handlers =
530 scandir(ipmi_lib_path, &handler_list, handler_select, alphasort);
Nan Li36c0cb62016-03-31 11:16:08 +0800531 if (num_handlers < 0)
532 return;
Jeremy Kerr5e8f85e2015-10-27 13:43:54 +0800533
Patrick Venture0b02be92018-08-31 11:55:55 -0700534 while (num_handlers--)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530535 {
Chris Austen54030262015-10-13 12:30:46 -0500536 handler_fqdn = ipmi_lib_path;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530537 handler_fqdn += handler_list[num_handlers]->d_name;
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530538#ifdef __IPMI_DEBUG__
539 log<level::DEBUG>("Registering handler",
540 entry("HANDLER=%s", handler_fqdn.c_str()));
541#endif
Chris Austen54030262015-10-13 12:30:46 -0500542
vishwabmcba0bd5f2015-09-30 16:50:23 +0530543 lib_handler = dlopen(handler_fqdn.c_str(), RTLD_NOW);
Nan Li36c0cb62016-03-31 11:16:08 +0800544
Patrick Venture0b02be92018-08-31 11:55:55 -0700545 if (lib_handler == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530546 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530547 log<level::ERR>("ERROR opening",
548 entry("HANDLER=%s", handler_fqdn.c_str()),
549 entry("ERROR=%s", dlerror()));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530550 }
551 // Wipe the memory allocated for this particular entry.
552 free(handler_list[num_handlers]);
553 }
Nan Li36c0cb62016-03-31 11:16:08 +0800554
vishwabmcba0bd5f2015-09-30 16:50:23 +0530555 // Done with all registration.
556 free(handler_list);
557 }
558
559 // TODO : What to be done on the memory that is given by dlopen ?.
560 return;
561}
562
Patrick Venture0b02be92018-08-31 11:55:55 -0700563sd_bus* ipmid_get_sd_bus_connection(void)
564{
Chris Austen30195fa2015-11-13 14:39:19 -0600565 return bus;
566}
567
Patrick Venture0b02be92018-08-31 11:55:55 -0700568sd_event* ipmid_get_sd_event_connection(void)
569{
Andrew Geissler93c679b2017-04-02 10:06:43 -0500570 return events;
571}
572
Patrick Venture0b02be92018-08-31 11:55:55 -0700573sd_bus_slot* ipmid_get_sd_bus_slot(void)
574{
vishwab9f559a2016-01-13 01:53:08 -0600575 return ipmid_slot;
576}
577
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530578// Calls host command manager to do the right thing for the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700579void ipmid_send_cmd_to_host(CommandHandler&& cmd)
580{
581 return cmdManager->execute(std::move(cmd));
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530582}
583
Patrick Venture0b02be92018-08-31 11:55:55 -0700584cmdManagerPtr& ipmid_get_host_cmd_manager()
585{
586 return cmdManager;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530587}
588
Patrick Venture0b02be92018-08-31 11:55:55 -0700589sdbusPtr& ipmid_get_sdbus_plus_handler()
590{
591 return sdbusp;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530592}
593
Patrick Venture0b02be92018-08-31 11:55:55 -0700594int main(int argc, char* argv[])
vishwabmcba0bd5f2015-09-30 16:50:23 +0530595{
Chris Austen0ba649e2015-10-13 12:28:13 -0500596 int r;
Chris Austen99497312015-10-22 13:00:16 -0500597 unsigned long tvalue;
598 int c;
599
Chris Austen99497312015-10-22 13:00:16 -0500600 // This file and subsequient switch is for turning on levels
601 // of trace
Patrick Venture0b02be92018-08-31 11:55:55 -0700602 ipmicmddetails = ipmiio = ipmidbus = fopen("/dev/null", "w");
Chris Austen99497312015-10-22 13:00:16 -0500603
Patrick Venture0b02be92018-08-31 11:55:55 -0700604 while ((c = getopt(argc, argv, "h:d:")) != -1)
605 switch (c)
606 {
Chris Austen99497312015-10-22 13:00:16 -0500607 case 'd':
Patrick Venture0b02be92018-08-31 11:55:55 -0700608 tvalue = strtoul(optarg, NULL, 16);
609 if (1 & tvalue)
610 {
Chris Austen99497312015-10-22 13:00:16 -0500611 ipmiio = stdout;
612 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700613 if (2 & tvalue)
614 {
Chris Austen99497312015-10-22 13:00:16 -0500615 ipmidbus = stdout;
616 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700617 if (4 & tvalue)
618 {
Chris Austen99497312015-10-22 13:00:16 -0500619 ipmicmddetails = stdout;
620 }
621 break;
Patrick Venture0b02be92018-08-31 11:55:55 -0700622 case 'h':
623 case '?':
Chris Austen99497312015-10-22 13:00:16 -0500624 print_usage();
625 return 1;
626 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500627
Chris Austen0ba649e2015-10-13 12:28:13 -0500628 /* Connect to system bus */
629 r = sd_bus_open_system(&bus);
Patrick Venture0b02be92018-08-31 11:55:55 -0700630 if (r < 0)
631 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530632 log<level::ERR>("Failed to connect to system bus",
633 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500634 goto finish;
635 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530636
Andrew Geissler93c679b2017-04-02 10:06:43 -0500637 /* Get an sd event handler */
638 r = sd_event_default(&events);
639 if (r < 0)
640 {
641 log<level::ERR>("Failure to create sd_event handler",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530642 entry("ERRNO=0x%X", -r));
Andrew Geissler93c679b2017-04-02 10:06:43 -0500643 goto finish;
644 }
645
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530646 // Now create the Host Bound Command manager. Need sdbusplus
647 // to use the generated bindings
648 sdbusp = std::make_unique<sdbusplus::bus::bus>(bus);
Patrick Venture0b02be92018-08-31 11:55:55 -0700649 cmdManager =
650 std::make_unique<phosphor::host::command::Manager>(*sdbusp, events);
Andrew Geissler93c679b2017-04-02 10:06:43 -0500651
Peter Hanson4a589852017-06-07 17:40:45 -0700652 // Activate OemRouter.
653 oem::mutableRouter()->activate();
654
Chris Austen30195fa2015-11-13 14:39:19 -0600655 // Register all the handlers that provider implementation to IPMI commands.
656 ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
657
Patrick Venture0b02be92018-08-31 11:55:55 -0700658 // Watch for BT messages
vishwab9f559a2016-01-13 01:53:08 -0600659 r = sd_bus_add_match(bus, &ipmid_slot, FILTER, handle_ipmi_command, NULL);
Patrick Venture0b02be92018-08-31 11:55:55 -0700660 if (r < 0)
661 {
662 log<level::ERR>("Failed: sd_bus_add_match", entry("FILTER=%s", FILTER),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530663 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500664 goto finish;
665 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530666
Andrew Geissler93c679b2017-04-02 10:06:43 -0500667 // Attach the bus to sd_event to service user requests
668 sd_bus_attach_event(bus, events, SD_EVENT_PRIORITY_NORMAL);
669
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500670 {
671 using namespace internal;
672 using namespace internal::cache;
673 sdbusplus::bus::bus dbus{bus};
674 objects = std::make_unique<settings::Objects>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700675 dbus, std::vector<settings::Interface>({restrictionModeIntf}));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500676 // Initialize restricted mode
677 cache_restricted_mode();
678 // Wait for changes on Restricted mode
679 sdbusplus::bus::match_t restrictedModeMatch(
680 dbus,
681 sdbusRule::propertiesChanged(
Deepak Kodihallie6027092017-08-27 08:13:37 -0500682 objects->map.at(restrictionModeIntf).front(),
683 restrictionModeIntf),
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500684 handle_restricted_mode_change);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530685
Patrick Venture0b02be92018-08-31 11:55:55 -0700686 for (;;)
687 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500688 /* Process requests */
689 r = sd_event_run(events, (uint64_t)-1);
690 if (r < 0)
691 {
692 log<level::ERR>("Failure in processing request",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530693 entry("ERRNO=0x%X", -r));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500694 goto finish;
695 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500696 }
697 }
698
699finish:
Andrew Geissler93c679b2017-04-02 10:06:43 -0500700 sd_event_unref(events);
701 sd_bus_detach_event(bus);
vishwab9f559a2016-01-13 01:53:08 -0600702 sd_bus_slot_unref(ipmid_slot);
Chris Austen0ba649e2015-10-13 12:28:13 -0500703 sd_bus_unref(bus);
704 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530705}