blob: 207a5cf2244b3a7bece0ce69a153f9c850f0a484 [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 Venture0b02be92018-08-31 11:55:55 -070019#include <host-ipmid/ipmid-host-cmd.hpp>
Patrick Venture46470a32018-09-07 19:26:25 -070020#include <host-ipmid/oemrouter.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070021#include <iostream>
Patrick Venture0b02be92018-08-31 11:55:55 -070022#include <iterator>
vishwabmcba0bd5f2015-09-30 16:50:23 +053023#include <map>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050024#include <memory>
Andrew Geissler93c679b2017-04-02 10:06:43 -050025#include <phosphor-logging/log.hpp>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050026#include <sdbusplus/bus.hpp>
27#include <sdbusplus/bus/match.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070028#include <vector>
29#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
30
Andrew Geissler93c679b2017-04-02 10:06:43 -050031using namespace phosphor::logging;
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050032namespace sdbusRule = sdbusplus::bus::match::rules;
Andrew Geissler93c679b2017-04-02 10:06:43 -050033
Patrick Venture0b02be92018-08-31 11:55:55 -070034sd_bus* bus = NULL;
35sd_bus_slot* ipmid_slot = NULL;
36sd_event* events = nullptr;
Chris Austen30195fa2015-11-13 14:39:19 -060037
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053038// Need this to use new sdbusplus compatible interfaces
39sdbusPtr sdbusp;
40
41// Global Host Bound Command manager
42using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>;
43cmdManagerPtr cmdManager;
44
Ratan Gupta7a7f0122018-03-07 12:31:05 +053045// Global timer for network changes
46std::unique_ptr<phosphor::ipmi::Timer> networkTimer = nullptr;
47
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053048// Command and handler tuple. Used when clients ask the command to be put
49// into host message queue
50using CommandHandler = phosphor::host::command::CommandHandler;
51
Tom Joseph9a61b4f2016-07-11 06:56:11 -050052// Initialise restricted mode to true
53bool restricted_mode = true;
54
Chris Austen41a4b312015-10-25 03:45:42 -050055FILE *ipmiio, *ipmidbus, *ipmicmddetails;
vishwabmcba0bd5f2015-09-30 16:50:23 +053056
Patrick Venture0b02be92018-08-31 11:55:55 -070057void print_usage(void)
58{
59 fprintf(stderr, "Options: [-d mask]\n");
60 fprintf(stderr, " mask : 0x01 - Print ipmi packets\n");
61 fprintf(stderr, " mask : 0x02 - Print DBUS operations\n");
62 fprintf(stderr, " mask : 0x04 - Print ipmi command details\n");
63 fprintf(stderr, " mask : 0xFF - Print all trace\n");
Chris Austen99497312015-10-22 13:00:16 -050064}
65
Patrick Venture0b02be92018-08-31 11:55:55 -070066const char* DBUS_INTF = "org.openbmc.HostIpmi";
vishwabmcba0bd5f2015-09-30 16:50:23 +053067
Patrick Venture0b02be92018-08-31 11:55:55 -070068const char* FILTER =
69 "type='signal',interface='org.openbmc.HostIpmi',member='ReceivedMessage'";
Chris Austen0ba649e2015-10-13 12:28:13 -050070
vishwabmcba0bd5f2015-09-30 16:50:23 +053071typedef std::pair<ipmi_netfn_t, ipmi_cmd_t> ipmi_fn_cmd_t;
72typedef std::pair<ipmid_callback_t, ipmi_context_t> ipmi_fn_context_t;
73
74// Global data structure that contains the IPMI command handler's registrations.
75std::map<ipmi_fn_cmd_t, ipmi_fn_context_t> g_ipmid_router_map;
76
Nan Li36c0cb62016-03-31 11:16:08 +080077// IPMI Spec, shared Reservation ID.
78unsigned short g_sel_reserve = 0xFFFF;
79
80unsigned short get_sel_reserve_id(void)
81{
82 return g_sel_reserve;
83}
Chris Austen0ba649e2015-10-13 12:28:13 -050084
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050085namespace internal
86{
87
88constexpr auto restrictionModeIntf =
89 "xyz.openbmc_project.Control.Security.RestrictionMode";
90
91namespace cache
92{
93
94std::unique_ptr<settings::Objects> objects = nullptr;
95
96} // namespace cache
97} // namespace internal
98
Chris Austen0ba649e2015-10-13 12:28:13 -050099#ifndef HEXDUMP_COLS
100#define HEXDUMP_COLS 16
101#endif
102
Patrick Venture0b02be92018-08-31 11:55:55 -0700103void hexdump(FILE* s, void* mem, size_t len)
Chris Austen0ba649e2015-10-13 12:28:13 -0500104{
Patrick Venture0b02be92018-08-31 11:55:55 -0700105 unsigned int i, j;
Chris Austen120f7322015-10-14 23:27:31 -0500106
Patrick Venture0b02be92018-08-31 11:55:55 -0700107 for (i = 0;
108 i <
109 len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0);
110 i++)
111 {
112 /* print offset */
113 if (i % HEXDUMP_COLS == 0)
Chris Austen0ba649e2015-10-13 12:28:13 -0500114 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700115 fprintf(s, "0x%06x: ", i);
Chris Austen0ba649e2015-10-13 12:28:13 -0500116 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700117
118 /* print hex data */
119 if (i < len)
120 {
121 fprintf(s, "%02x ", 0xFF & ((char*)mem)[i]);
122 }
123 else /* end of block, just aligning for ASCII dump */
124 {
125 fprintf(s, " ");
126 }
127
128 /* print ASCII dump */
129 if (i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
130 {
131 for (j = i - (HEXDUMP_COLS - 1); j <= i; j++)
132 {
133 if (j >= len) /* end of block, not really printing */
134 {
135 fputc(' ', s);
136 }
137 else if (isprint(((char*)mem)[j])) /* printable char */
138 {
139 fputc(0xFF & ((char*)mem)[j], s);
140 }
141 else /* other char */
142 {
143 fputc('.', s);
144 }
145 }
146 fputc('\n', s);
147 }
148 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500149}
150
Patrick Venture0b02be92018-08-31 11:55:55 -0700151// Method that gets called by shared libraries to get their command handlers
152// registered
153void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
154 ipmi_context_t context, ipmid_callback_t handler,
155 ipmi_cmd_privilege_t priv)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530156{
157 // Pack NetFn and Command in one.
158 auto netfn_and_cmd = std::make_pair(netfn, cmd);
159
160 // Pack Function handler and Data in another.
161 auto handler_and_context = std::make_pair(handler, context);
162
163 // Check if the registration has already been made..
164 auto iter = g_ipmid_router_map.find(netfn_and_cmd);
Patrick Venture0b02be92018-08-31 11:55:55 -0700165 if (iter != g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530166 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700167 log<level::ERR>("Duplicate registration", entry("NETFN=0x%X", netfn),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530168 entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530169 }
170 else
171 {
172 // This is a fresh registration.. Add it to the map.
173 g_ipmid_router_map.emplace(netfn_and_cmd, handler_and_context);
174 }
175
176 return;
177}
178
179// Looks at the map and calls corresponding handler functions.
Patrick Venture0b02be92018-08-31 11:55:55 -0700180ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
181 ipmi_request_t request, ipmi_response_t response,
182 ipmi_data_len_t data_len)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530183{
184 // return from the Command handlers.
185 ipmi_ret_t rc = IPMI_CC_INVALID;
186
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500187 // If restricted mode is true and command is not whitelisted, don't
188 // execute the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700189 if (restricted_mode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500190 {
191 if (!std::binary_search(whitelist.cbegin(), whitelist.cend(),
Patrick Venture0b02be92018-08-31 11:55:55 -0700192 std::make_pair(netfn, cmd)))
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500193 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530194 log<level::ERR>("Net function not whitelisted",
Patrick Venture0b02be92018-08-31 11:55:55 -0700195 entry("NETFN=0x%X", netfn), entry("CMD=0x%X", cmd));
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500196 rc = IPMI_CC_INSUFFICIENT_PRIVILEGE;
197 memcpy(response, &rc, IPMI_CC_LEN);
198 *data_len = IPMI_CC_LEN;
199 return rc;
200 }
201 }
202
vishwabmcba0bd5f2015-09-30 16:50:23 +0530203 // Walk the map that has the registered handlers and invoke the approprite
204 // handlers for matching commands.
205 auto iter = g_ipmid_router_map.find(std::make_pair(netfn, cmd));
Patrick Venture0b02be92018-08-31 11:55:55 -0700206 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530207 {
Patrick Venture03f84ba2017-09-20 09:15:33 -0700208 /* By default should only print on failure to find wildcard command. */
209#ifdef __IPMI_DEBUG__
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530210 log<level::ERR>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700211 "No registered handlers for NetFn, trying Wilcard implementation",
212 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", IPMI_CMD_WILDCARD));
Patrick Venture03f84ba2017-09-20 09:15:33 -0700213#endif
vishwabmcba0bd5f2015-09-30 16:50:23 +0530214
215 // Now that we did not find any specific [NetFn,Cmd], tuple, check for
216 // NetFn, WildCard command present.
Patrick Venture0b02be92018-08-31 11:55:55 -0700217 iter =
218 g_ipmid_router_map.find(std::make_pair(netfn, IPMI_CMD_WILDCARD));
219 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530220 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530221 log<level::ERR>("No Registered handlers for NetFn",
222 entry("NET_FUN=0x%X", netfn),
223 entry("CMD=0x%X", IPMI_CMD_WILDCARD));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530224
225 // Respond with a 0xC1
226 memcpy(response, &rc, IPMI_CC_LEN);
227 *data_len = IPMI_CC_LEN;
228 return rc;
229 }
230 }
231
232#ifdef __IPMI_DEBUG__
233 // We have either a perfect match -OR- a wild card atleast,
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530234 log<level::ERR>("Calling Net function",
Patrick Venture0b02be92018-08-31 11:55:55 -0700235 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530236#endif
237
238 // Extract the map data onto appropriate containers
239 auto handler_and_context = iter->second;
240
241 // Creating a pointer type casted to char* to make sure we advance 1 byte
242 // when we advance pointer to next's address. advancing void * would not
243 // make sense.
Patrick Venture0b02be92018-08-31 11:55:55 -0700244 char* respo = &((char*)response)[IPMI_CC_LEN];
vishwabmcba0bd5f2015-09-30 16:50:23 +0530245
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530246 try
247 {
248 // Response message from the plugin goes into a byte post the base
249 // response
Patrick Venture0b02be92018-08-31 11:55:55 -0700250 rc = (handler_and_context.first)(netfn, cmd, request, respo, data_len,
251 handler_and_context.second);
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530252 }
253 // IPMI command handlers can throw unhandled exceptions, catch those
254 // and return sane error code.
Patrick Venture0b02be92018-08-31 11:55:55 -0700255 catch (const std::exception& e)
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530256 {
257 log<level::ERR>(e.what(), entry("NET_FUN=0x%X", netfn),
258 entry("CMD=0x%X", cmd));
259 rc = IPMI_CC_UNSPECIFIED_ERROR;
260 *data_len = 0;
261 // fall through
262 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530263 // Now copy the return code that we got from handler and pack it in first
264 // byte.
265 memcpy(response, &rc, IPMI_CC_LEN);
Chris Austen120f7322015-10-14 23:27:31 -0500266
vishwabmcba0bd5f2015-09-30 16:50:23 +0530267 // Data length is now actual data + completion code.
268 *data_len = *data_len + IPMI_CC_LEN;
269
270 return rc;
271}
272
Patrick Venture0b02be92018-08-31 11:55:55 -0700273static int send_ipmi_message(sd_bus_message* req, unsigned char seq,
274 unsigned char netfn, unsigned char lun,
275 unsigned char cmd, unsigned char cc,
276 unsigned char* buf, unsigned char len)
277{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530278
Chris Austen0ba649e2015-10-13 12:28:13 -0500279 sd_bus_error error = SD_BUS_ERROR_NULL;
Patrick Venture0b02be92018-08-31 11:55:55 -0700280 sd_bus_message *reply = NULL, *m = NULL;
Jeremy Kerre41081f2015-10-27 12:11:36 +0800281 const char *dest, *path;
Chris Austen0ba649e2015-10-13 12:28:13 -0500282 int r, pty;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530283
Jeremy Kerre41081f2015-10-27 12:11:36 +0800284 dest = sd_bus_message_get_sender(req);
285 path = sd_bus_message_get_path(req);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530286
Patrick Venture0b02be92018-08-31 11:55:55 -0700287 r = sd_bus_message_new_method_call(bus, &m, dest, path, DBUS_INTF,
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530288 "sendMessage");
Patrick Venture0b02be92018-08-31 11:55:55 -0700289 if (r < 0)
290 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530291 log<level::ERR>("Failed to add the method object",
292 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500293 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530294 }
295
Chris Austenabfb5e82015-10-13 12:29:24 -0500296 // Responses in IPMI require a bit set. So there ya go...
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800297 netfn |= 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530298
Chris Austen0ba649e2015-10-13 12:28:13 -0500299 // Add the bytes needed for the methods to be called
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800300 r = sd_bus_message_append(m, "yyyyy", seq, netfn, lun, cmd, cc);
Patrick Venture0b02be92018-08-31 11:55:55 -0700301 if (r < 0)
302 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530303 log<level::ERR>("Failed add the netfn and others",
304 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600305 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500306 }
Chris Austen120f7322015-10-14 23:27:31 -0500307
Chris Austen0ba649e2015-10-13 12:28:13 -0500308 r = sd_bus_message_append_array(m, 'y', buf, len);
Patrick Venture0b02be92018-08-31 11:55:55 -0700309 if (r < 0)
310 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530311 log<level::ERR>("Failed to add the string of response bytes",
312 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600313 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500314 }
315
Chris Austen0ba649e2015-10-13 12:28:13 -0500316 // Call the IPMI responder on the bus so the message can be sent to the CEC
317 r = sd_bus_call(bus, m, 0, &error, &reply);
Patrick Venture0b02be92018-08-31 11:55:55 -0700318 if (r < 0)
319 {
320 log<level::ERR>("Failed to call the method", entry("DEST=%s", dest),
321 entry("PATH=%s", path), entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600322 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500323 }
324
325 r = sd_bus_message_read(reply, "x", &pty);
Patrick Venture0b02be92018-08-31 11:55:55 -0700326 if (r < 0)
327 {
328 log<level::ERR>("Failed to get a reply from the method",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530329 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500330 }
331
Chris Austen169395e2015-12-02 20:56:15 -0600332final:
Chris Austen0ba649e2015-10-13 12:28:13 -0500333 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600334 m = sd_bus_message_unref(m);
335 reply = sd_bus_message_unref(reply);
Chris Austen0ba649e2015-10-13 12:28:13 -0500336
Chris Austen0ba649e2015-10-13 12:28:13 -0500337 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Chris Austen0ba649e2015-10-13 12:28:13 -0500338}
339
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500340void cache_restricted_mode()
341{
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500342 restricted_mode = false;
343 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
344 using namespace internal;
345 using namespace internal::cache;
346 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
347 const auto& restrictionModeSetting =
Deepak Kodihallie6027092017-08-27 08:13:37 -0500348 objects->map.at(restrictionModeIntf).front();
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500349 auto method = dbus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700350 objects->service(restrictionModeSetting, restrictionModeIntf).c_str(),
351 restrictionModeSetting.c_str(), "org.freedesktop.DBus.Properties",
352 "Get");
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500353 method.append(restrictionModeIntf, "RestrictionMode");
354 auto resp = dbus.call(method);
355 if (resp.is_method_error())
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500356 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500357 log<level::ERR>("Error in RestrictionMode Get");
358 // Fail-safe to true.
359 restricted_mode = true;
360 return;
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500361 }
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500362 sdbusplus::message::variant<std::string> result;
363 resp.read(result);
364 auto restrictionMode =
365 RestrictionMode::convertModesFromString(result.get<std::string>());
Patrick Venture0b02be92018-08-31 11:55:55 -0700366 if (RestrictionMode::Modes::Whitelist == restrictionMode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500367 {
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500368 restricted_mode = true;
369 }
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500370}
371
Patrick Venture0b02be92018-08-31 11:55:55 -0700372static int handle_restricted_mode_change(sd_bus_message* m, void* user_data,
373 sd_bus_error* ret_error)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500374{
375 cache_restricted_mode();
376 return 0;
377}
378
Patrick Venture0b02be92018-08-31 11:55:55 -0700379static int handle_ipmi_command(sd_bus_message* m, void* user_data,
380 sd_bus_error* ret_error)
381{
Chris Austen0ba649e2015-10-13 12:28:13 -0500382 int r = 0;
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800383 unsigned char sequence, netfn, lun, cmd;
Patrick Venture0b02be92018-08-31 11:55:55 -0700384 const void* request;
Chris Austen0ba649e2015-10-13 12:28:13 -0500385 size_t sz;
Patrick Venture0b02be92018-08-31 11:55:55 -0700386 size_t resplen = MAX_IPMI_BUFFER;
Chris Austen0ba649e2015-10-13 12:28:13 -0500387 unsigned char response[MAX_IPMI_BUFFER];
388
Chris Austen0ba649e2015-10-13 12:28:13 -0500389 memset(response, 0, MAX_IPMI_BUFFER);
390
Patrick Venture0b02be92018-08-31 11:55:55 -0700391 r = sd_bus_message_read(m, "yyyy", &sequence, &netfn, &lun, &cmd);
392 if (r < 0)
393 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530394 log<level::ERR>("Failed to parse signal message",
395 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500396 return -1;
397 }
398
Patrick Venture0b02be92018-08-31 11:55:55 -0700399 r = sd_bus_message_read_array(m, 'y', &request, &sz);
400 if (r < 0)
401 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530402 log<level::ERR>("Failed to parse signal message",
403 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500404 return -1;
405 }
406
Patrick Venture0b02be92018-08-31 11:55:55 -0700407 fprintf(ipmiio, "IPMI Incoming: Seq 0x%02x, NetFn 0x%02x, CMD: 0x%02x \n",
408 sequence, netfn, cmd);
Chris Austen99497312015-10-22 13:00:16 -0500409 hexdump(ipmiio, (void*)request, sz);
Chris Austen0ba649e2015-10-13 12:28:13 -0500410
Chris Austen120f7322015-10-14 23:27:31 -0500411 // Allow the length field to be used for both input and output of the
Chris Austen0ba649e2015-10-13 12:28:13 -0500412 // ipmi call
413 resplen = sz;
414
Chris Austen120f7322015-10-14 23:27:31 -0500415 // Now that we have parsed the entire byte array from the caller
vishwabmcba0bd5f2015-09-30 16:50:23 +0530416 // we can call the ipmi router to do the work...
Patrick Venture0b02be92018-08-31 11:55:55 -0700417 r = ipmi_netfn_router(netfn, cmd, (void*)request, (void*)response,
418 &resplen);
419 if (r != 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530420 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530421#ifdef __IPMI_DEBUG__
Patrick Venture0b02be92018-08-31 11:55:55 -0700422 log<level::ERR>("ERROR in handling NetFn", entry("ERRNO=0x%X", -r),
423 entry("NET_FUN=0x%X", netfn), entry("CMD=0x%X", cmd));
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530424#endif
Ratan Guptae0cc8552018-01-22 14:23:04 +0530425 resplen = 0;
426 }
427 else
428 {
429 resplen = resplen - 1; // first byte is for return code.
vishwabmcba0bd5f2015-09-30 16:50:23 +0530430 }
431
Chris Austen99497312015-10-22 13:00:16 -0500432 fprintf(ipmiio, "IPMI Response:\n");
Patrick Venture0b02be92018-08-31 11:55:55 -0700433 hexdump(ipmiio, (void*)response, resplen);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530434
Chris Austen0ba649e2015-10-13 12:28:13 -0500435 // Send the response buffer from the ipmi command
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800436 r = send_ipmi_message(m, sequence, netfn, lun, cmd, response[0],
Patrick Venture0b02be92018-08-31 11:55:55 -0700437 ((unsigned char*)response) + 1, resplen);
438 if (r < 0)
439 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530440 log<level::ERR>("Failed to send the response message");
Chris Austen0ba649e2015-10-13 12:28:13 -0500441 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530442 }
443
Chris Austen0ba649e2015-10-13 12:28:13 -0500444 return 0;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530445}
446
447//----------------------------------------------------------------------
448// handler_select
449// Select all the files ending with with .so. in the given diretcory
450// @d: dirent structure containing the file name
451//----------------------------------------------------------------------
Patrick Venture0b02be92018-08-31 11:55:55 -0700452int handler_select(const struct dirent* entry)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530453{
454 // To hold ".so" from entry->d_name;
455 char dname_copy[4] = {0};
456
457 // We want to avoid checking for everything and isolate to the ones having
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500458 // .so.* or .so in them.
459 // Check for versioned libraries .so.*
Patrick Venture0b02be92018-08-31 11:55:55 -0700460 if (strstr(entry->d_name, IPMI_PLUGIN_SONAME_EXTN))
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500461 {
462 return 1;
463 }
464 // Check for non versioned libraries .so
Patrick Venture0b02be92018-08-31 11:55:55 -0700465 else if (strstr(entry->d_name, IPMI_PLUGIN_EXTN))
vishwabmcba0bd5f2015-09-30 16:50:23 +0530466 {
467 // It is possible that .so could be anywhere in the string but unlikely
Chris Austen120f7322015-10-14 23:27:31 -0500468 // But being careful here. Get the base address of the string, move
vishwabmcba0bd5f2015-09-30 16:50:23 +0530469 // until end and come back 3 steps and that gets what we need.
Patrick Venture0b02be92018-08-31 11:55:55 -0700470 strcpy(dname_copy, (entry->d_name + strlen(entry->d_name) -
471 strlen(IPMI_PLUGIN_EXTN)));
472 if (strcmp(dname_copy, IPMI_PLUGIN_EXTN) == 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530473 {
474 return 1;
475 }
476 }
477 return 0;
478}
479
Patrick Venture0b02be92018-08-31 11:55:55 -0700480// This will do a dlopen of every .so in ipmi_lib_path and will dlopen
481// everything so that they will register a callback handler
vishwabmcba0bd5f2015-09-30 16:50:23 +0530482void ipmi_register_callback_handlers(const char* ipmi_lib_path)
483{
484 // For walking the ipmi_lib_path
Patrick Venture0b02be92018-08-31 11:55:55 -0700485 struct dirent** handler_list;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530486 int num_handlers = 0;
487
488 // This is used to check and abort if someone tries to register a bad one.
Patrick Venture0b02be92018-08-31 11:55:55 -0700489 void* lib_handler = NULL;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530490
Patrick Venture0b02be92018-08-31 11:55:55 -0700491 if (ipmi_lib_path == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530492 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530493 log<level::ERR>("No handlers to be registered for ipmi.. Aborting");
vishwabmcba0bd5f2015-09-30 16:50:23 +0530494 assert(0);
495 }
496 else
497 {
498 // 1: Open ipmi_lib_path. Its usually "/usr/lib/phosphor-host-ipmid"
499 // 2: Scan the directory for the files that end with .so
Chris Austen120f7322015-10-14 23:27:31 -0500500 // 3: For each one of them, just do a 'dlopen' so that they register
vishwabmcba0bd5f2015-09-30 16:50:23 +0530501 // the handlers for callback routines.
502
503 std::string handler_fqdn = ipmi_lib_path;
Chris Austen120f7322015-10-14 23:27:31 -0500504
vishwabmcba0bd5f2015-09-30 16:50:23 +0530505 // Append a "/" since we need to add the name of the .so. If there is
506 // already a .so, adding one more is not any harm.
507 handler_fqdn += "/";
508
Patrick Venture0b02be92018-08-31 11:55:55 -0700509 num_handlers =
510 scandir(ipmi_lib_path, &handler_list, handler_select, alphasort);
Nan Li36c0cb62016-03-31 11:16:08 +0800511 if (num_handlers < 0)
512 return;
Jeremy Kerr5e8f85e2015-10-27 13:43:54 +0800513
Patrick Venture0b02be92018-08-31 11:55:55 -0700514 while (num_handlers--)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530515 {
Chris Austen54030262015-10-13 12:30:46 -0500516 handler_fqdn = ipmi_lib_path;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530517 handler_fqdn += handler_list[num_handlers]->d_name;
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530518#ifdef __IPMI_DEBUG__
519 log<level::DEBUG>("Registering handler",
520 entry("HANDLER=%s", handler_fqdn.c_str()));
521#endif
Chris Austen54030262015-10-13 12:30:46 -0500522
vishwabmcba0bd5f2015-09-30 16:50:23 +0530523 lib_handler = dlopen(handler_fqdn.c_str(), RTLD_NOW);
Nan Li36c0cb62016-03-31 11:16:08 +0800524
Patrick Venture0b02be92018-08-31 11:55:55 -0700525 if (lib_handler == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530526 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530527 log<level::ERR>("ERROR opening",
528 entry("HANDLER=%s", handler_fqdn.c_str()),
529 entry("ERROR=%s", dlerror()));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530530 }
531 // Wipe the memory allocated for this particular entry.
532 free(handler_list[num_handlers]);
533 }
Nan Li36c0cb62016-03-31 11:16:08 +0800534
vishwabmcba0bd5f2015-09-30 16:50:23 +0530535 // Done with all registration.
536 free(handler_list);
537 }
538
539 // TODO : What to be done on the memory that is given by dlopen ?.
540 return;
541}
542
Patrick Venture0b02be92018-08-31 11:55:55 -0700543sd_bus* ipmid_get_sd_bus_connection(void)
544{
Chris Austen30195fa2015-11-13 14:39:19 -0600545 return bus;
546}
547
Patrick Venture0b02be92018-08-31 11:55:55 -0700548sd_event* ipmid_get_sd_event_connection(void)
549{
Andrew Geissler93c679b2017-04-02 10:06:43 -0500550 return events;
551}
552
Patrick Venture0b02be92018-08-31 11:55:55 -0700553sd_bus_slot* ipmid_get_sd_bus_slot(void)
554{
vishwab9f559a2016-01-13 01:53:08 -0600555 return ipmid_slot;
556}
557
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530558// Calls host command manager to do the right thing for the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700559void ipmid_send_cmd_to_host(CommandHandler&& cmd)
560{
561 return cmdManager->execute(std::move(cmd));
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530562}
563
Patrick Venture0b02be92018-08-31 11:55:55 -0700564cmdManagerPtr& ipmid_get_host_cmd_manager()
565{
566 return cmdManager;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530567}
568
Patrick Venture0b02be92018-08-31 11:55:55 -0700569sdbusPtr& ipmid_get_sdbus_plus_handler()
570{
571 return sdbusp;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530572}
573
Patrick Venture0b02be92018-08-31 11:55:55 -0700574int main(int argc, char* argv[])
vishwabmcba0bd5f2015-09-30 16:50:23 +0530575{
Chris Austen0ba649e2015-10-13 12:28:13 -0500576 int r;
Chris Austen99497312015-10-22 13:00:16 -0500577 unsigned long tvalue;
578 int c;
579
Chris Austen99497312015-10-22 13:00:16 -0500580 // This file and subsequient switch is for turning on levels
581 // of trace
Patrick Venture0b02be92018-08-31 11:55:55 -0700582 ipmicmddetails = ipmiio = ipmidbus = fopen("/dev/null", "w");
Chris Austen99497312015-10-22 13:00:16 -0500583
Patrick Venture0b02be92018-08-31 11:55:55 -0700584 while ((c = getopt(argc, argv, "h:d:")) != -1)
585 switch (c)
586 {
Chris Austen99497312015-10-22 13:00:16 -0500587 case 'd':
Patrick Venture0b02be92018-08-31 11:55:55 -0700588 tvalue = strtoul(optarg, NULL, 16);
589 if (1 & tvalue)
590 {
Chris Austen99497312015-10-22 13:00:16 -0500591 ipmiio = stdout;
592 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700593 if (2 & tvalue)
594 {
Chris Austen99497312015-10-22 13:00:16 -0500595 ipmidbus = stdout;
596 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700597 if (4 & tvalue)
598 {
Chris Austen99497312015-10-22 13:00:16 -0500599 ipmicmddetails = stdout;
600 }
601 break;
Patrick Venture0b02be92018-08-31 11:55:55 -0700602 case 'h':
603 case '?':
Chris Austen99497312015-10-22 13:00:16 -0500604 print_usage();
605 return 1;
606 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500607
Chris Austen0ba649e2015-10-13 12:28:13 -0500608 /* Connect to system bus */
609 r = sd_bus_open_system(&bus);
Patrick Venture0b02be92018-08-31 11:55:55 -0700610 if (r < 0)
611 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530612 log<level::ERR>("Failed to connect to system bus",
613 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500614 goto finish;
615 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530616
Andrew Geissler93c679b2017-04-02 10:06:43 -0500617 /* Get an sd event handler */
618 r = sd_event_default(&events);
619 if (r < 0)
620 {
621 log<level::ERR>("Failure to create sd_event handler",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530622 entry("ERRNO=0x%X", -r));
Andrew Geissler93c679b2017-04-02 10:06:43 -0500623 goto finish;
624 }
625
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530626 // Now create the Host Bound Command manager. Need sdbusplus
627 // to use the generated bindings
628 sdbusp = std::make_unique<sdbusplus::bus::bus>(bus);
Patrick Venture0b02be92018-08-31 11:55:55 -0700629 cmdManager =
630 std::make_unique<phosphor::host::command::Manager>(*sdbusp, events);
Andrew Geissler93c679b2017-04-02 10:06:43 -0500631
Peter Hanson4a589852017-06-07 17:40:45 -0700632 // Activate OemRouter.
633 oem::mutableRouter()->activate();
634
Chris Austen30195fa2015-11-13 14:39:19 -0600635 // Register all the handlers that provider implementation to IPMI commands.
636 ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
637
Patrick Venture0b02be92018-08-31 11:55:55 -0700638 // Watch for BT messages
vishwab9f559a2016-01-13 01:53:08 -0600639 r = sd_bus_add_match(bus, &ipmid_slot, FILTER, handle_ipmi_command, NULL);
Patrick Venture0b02be92018-08-31 11:55:55 -0700640 if (r < 0)
641 {
642 log<level::ERR>("Failed: sd_bus_add_match", entry("FILTER=%s", FILTER),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530643 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500644 goto finish;
645 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530646
Andrew Geissler93c679b2017-04-02 10:06:43 -0500647 // Attach the bus to sd_event to service user requests
648 sd_bus_attach_event(bus, events, SD_EVENT_PRIORITY_NORMAL);
649
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500650 {
651 using namespace internal;
652 using namespace internal::cache;
653 sdbusplus::bus::bus dbus{bus};
654 objects = std::make_unique<settings::Objects>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700655 dbus, std::vector<settings::Interface>({restrictionModeIntf}));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500656 // Initialize restricted mode
657 cache_restricted_mode();
658 // Wait for changes on Restricted mode
659 sdbusplus::bus::match_t restrictedModeMatch(
660 dbus,
661 sdbusRule::propertiesChanged(
Deepak Kodihallie6027092017-08-27 08:13:37 -0500662 objects->map.at(restrictionModeIntf).front(),
663 restrictionModeIntf),
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500664 handle_restricted_mode_change);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530665
Patrick Venture0b02be92018-08-31 11:55:55 -0700666 for (;;)
667 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500668 /* Process requests */
669 r = sd_event_run(events, (uint64_t)-1);
670 if (r < 0)
671 {
672 log<level::ERR>("Failure in processing request",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530673 entry("ERRNO=0x%X", -r));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500674 goto finish;
675 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500676 }
677 }
678
679finish:
Andrew Geissler93c679b2017-04-02 10:06:43 -0500680 sd_event_unref(events);
681 sd_bus_detach_event(bus);
vishwab9f559a2016-01-13 01:53:08 -0600682 sd_bus_slot_unref(ipmid_slot);
Chris Austen0ba649e2015-10-13 12:28:13 -0500683 sd_bus_unref(bus);
684 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530685}