blob: 6da7ff2ceca02c3a02efba8733f2e829c28364be [file] [log] [blame]
Patrick Venture0b02be92018-08-31 11:55:55 -07001#include "ipmid.hpp"
2
3#include "host-ipmid/oemrouter.hpp"
4#include "settings.hpp"
5
vishwabmcba0bd5f2015-09-30 16:50:23 +05306#include <assert.h>
7#include <dirent.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07008#include <dlfcn.h>
9#include <errno.h>
10#include <mapper.h>
11#include <stdio.h>
vishwabmcba0bd5f2015-09-30 16:50:23 +053012#include <stdlib.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070013#include <string.h>
14#include <sys/time.h>
15#include <systemd/sd-bus.h>
16#include <unistd.h>
17
18#include <algorithm>
19#include <host-cmd-manager.hpp>
20#include <host-ipmid/ipmid-host-cmd.hpp>
21#include <iostream>
22#include <ipmiwhitelist.hpp>
23#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>
Vishwanatha Subbanna6e8979d2017-07-13 16:48:20 +053029#include <timer.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070030#include <vector>
31#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
32
33#include "sensorhandler.h"
Chris Austen0ba649e2015-10-13 12:28:13 -050034
Andrew Geissler93c679b2017-04-02 10:06:43 -050035using namespace phosphor::logging;
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050036namespace sdbusRule = sdbusplus::bus::match::rules;
Andrew Geissler93c679b2017-04-02 10:06:43 -050037
Patrick Venture0b02be92018-08-31 11:55:55 -070038sd_bus* bus = NULL;
39sd_bus_slot* ipmid_slot = NULL;
40sd_event* events = nullptr;
Chris Austen30195fa2015-11-13 14:39:19 -060041
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053042// Need this to use new sdbusplus compatible interfaces
43sdbusPtr sdbusp;
44
45// Global Host Bound Command manager
46using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>;
47cmdManagerPtr cmdManager;
48
Ratan Gupta7a7f0122018-03-07 12:31:05 +053049// Global timer for network changes
50std::unique_ptr<phosphor::ipmi::Timer> networkTimer = nullptr;
51
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053052// Command and handler tuple. Used when clients ask the command to be put
53// into host message queue
54using CommandHandler = phosphor::host::command::CommandHandler;
55
Tom Joseph9a61b4f2016-07-11 06:56:11 -050056// Initialise restricted mode to true
57bool restricted_mode = true;
58
Chris Austen41a4b312015-10-25 03:45:42 -050059FILE *ipmiio, *ipmidbus, *ipmicmddetails;
vishwabmcba0bd5f2015-09-30 16:50:23 +053060
Patrick Venture0b02be92018-08-31 11:55:55 -070061void print_usage(void)
62{
63 fprintf(stderr, "Options: [-d mask]\n");
64 fprintf(stderr, " mask : 0x01 - Print ipmi packets\n");
65 fprintf(stderr, " mask : 0x02 - Print DBUS operations\n");
66 fprintf(stderr, " mask : 0x04 - Print ipmi command details\n");
67 fprintf(stderr, " mask : 0xFF - Print all trace\n");
Chris Austen99497312015-10-22 13:00:16 -050068}
69
Patrick Venture0b02be92018-08-31 11:55:55 -070070const char* DBUS_INTF = "org.openbmc.HostIpmi";
vishwabmcba0bd5f2015-09-30 16:50:23 +053071
Patrick Venture0b02be92018-08-31 11:55:55 -070072const char* FILTER =
73 "type='signal',interface='org.openbmc.HostIpmi',member='ReceivedMessage'";
Chris Austen0ba649e2015-10-13 12:28:13 -050074
vishwabmcba0bd5f2015-09-30 16:50:23 +053075typedef std::pair<ipmi_netfn_t, ipmi_cmd_t> ipmi_fn_cmd_t;
76typedef std::pair<ipmid_callback_t, ipmi_context_t> ipmi_fn_context_t;
77
78// Global data structure that contains the IPMI command handler's registrations.
79std::map<ipmi_fn_cmd_t, ipmi_fn_context_t> g_ipmid_router_map;
80
Nan Li36c0cb62016-03-31 11:16:08 +080081// IPMI Spec, shared Reservation ID.
82unsigned short g_sel_reserve = 0xFFFF;
83
84unsigned short get_sel_reserve_id(void)
85{
86 return g_sel_reserve;
87}
Chris Austen0ba649e2015-10-13 12:28:13 -050088
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050089namespace internal
90{
91
92constexpr auto restrictionModeIntf =
93 "xyz.openbmc_project.Control.Security.RestrictionMode";
94
95namespace cache
96{
97
98std::unique_ptr<settings::Objects> objects = nullptr;
99
100} // namespace cache
101} // namespace internal
102
Chris Austen0ba649e2015-10-13 12:28:13 -0500103#ifndef HEXDUMP_COLS
104#define HEXDUMP_COLS 16
105#endif
106
Patrick Venture0b02be92018-08-31 11:55:55 -0700107void hexdump(FILE* s, void* mem, size_t len)
Chris Austen0ba649e2015-10-13 12:28:13 -0500108{
Patrick Venture0b02be92018-08-31 11:55:55 -0700109 unsigned int i, j;
Chris Austen120f7322015-10-14 23:27:31 -0500110
Patrick Venture0b02be92018-08-31 11:55:55 -0700111 for (i = 0;
112 i <
113 len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0);
114 i++)
115 {
116 /* print offset */
117 if (i % HEXDUMP_COLS == 0)
Chris Austen0ba649e2015-10-13 12:28:13 -0500118 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700119 fprintf(s, "0x%06x: ", i);
Chris Austen0ba649e2015-10-13 12:28:13 -0500120 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700121
122 /* print hex data */
123 if (i < len)
124 {
125 fprintf(s, "%02x ", 0xFF & ((char*)mem)[i]);
126 }
127 else /* end of block, just aligning for ASCII dump */
128 {
129 fprintf(s, " ");
130 }
131
132 /* print ASCII dump */
133 if (i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
134 {
135 for (j = i - (HEXDUMP_COLS - 1); j <= i; j++)
136 {
137 if (j >= len) /* end of block, not really printing */
138 {
139 fputc(' ', s);
140 }
141 else if (isprint(((char*)mem)[j])) /* printable char */
142 {
143 fputc(0xFF & ((char*)mem)[j], s);
144 }
145 else /* other char */
146 {
147 fputc('.', s);
148 }
149 }
150 fputc('\n', s);
151 }
152 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500153}
154
Patrick Venture0b02be92018-08-31 11:55:55 -0700155// Method that gets called by shared libraries to get their command handlers
156// registered
157void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
158 ipmi_context_t context, ipmid_callback_t handler,
159 ipmi_cmd_privilege_t priv)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530160{
161 // Pack NetFn and Command in one.
162 auto netfn_and_cmd = std::make_pair(netfn, cmd);
163
164 // Pack Function handler and Data in another.
165 auto handler_and_context = std::make_pair(handler, context);
166
167 // Check if the registration has already been made..
168 auto iter = g_ipmid_router_map.find(netfn_and_cmd);
Patrick Venture0b02be92018-08-31 11:55:55 -0700169 if (iter != g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530170 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700171 log<level::ERR>("Duplicate registration", entry("NETFN=0x%X", netfn),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530172 entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530173 }
174 else
175 {
176 // This is a fresh registration.. Add it to the map.
177 g_ipmid_router_map.emplace(netfn_and_cmd, handler_and_context);
178 }
179
180 return;
181}
182
183// Looks at the map and calls corresponding handler functions.
Patrick Venture0b02be92018-08-31 11:55:55 -0700184ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
185 ipmi_request_t request, ipmi_response_t response,
186 ipmi_data_len_t data_len)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530187{
188 // return from the Command handlers.
189 ipmi_ret_t rc = IPMI_CC_INVALID;
190
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500191 // If restricted mode is true and command is not whitelisted, don't
192 // execute the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700193 if (restricted_mode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500194 {
195 if (!std::binary_search(whitelist.cbegin(), whitelist.cend(),
Patrick Venture0b02be92018-08-31 11:55:55 -0700196 std::make_pair(netfn, cmd)))
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500197 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530198 log<level::ERR>("Net function not whitelisted",
Patrick Venture0b02be92018-08-31 11:55:55 -0700199 entry("NETFN=0x%X", netfn), entry("CMD=0x%X", cmd));
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500200 rc = IPMI_CC_INSUFFICIENT_PRIVILEGE;
201 memcpy(response, &rc, IPMI_CC_LEN);
202 *data_len = IPMI_CC_LEN;
203 return rc;
204 }
205 }
206
vishwabmcba0bd5f2015-09-30 16:50:23 +0530207 // Walk the map that has the registered handlers and invoke the approprite
208 // handlers for matching commands.
209 auto iter = g_ipmid_router_map.find(std::make_pair(netfn, cmd));
Patrick Venture0b02be92018-08-31 11:55:55 -0700210 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530211 {
Patrick Venture03f84ba2017-09-20 09:15:33 -0700212 /* By default should only print on failure to find wildcard command. */
213#ifdef __IPMI_DEBUG__
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530214 log<level::ERR>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700215 "No registered handlers for NetFn, trying Wilcard implementation",
216 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", IPMI_CMD_WILDCARD));
Patrick Venture03f84ba2017-09-20 09:15:33 -0700217#endif
vishwabmcba0bd5f2015-09-30 16:50:23 +0530218
219 // Now that we did not find any specific [NetFn,Cmd], tuple, check for
220 // NetFn, WildCard command present.
Patrick Venture0b02be92018-08-31 11:55:55 -0700221 iter =
222 g_ipmid_router_map.find(std::make_pair(netfn, IPMI_CMD_WILDCARD));
223 if (iter == g_ipmid_router_map.end())
vishwabmcba0bd5f2015-09-30 16:50:23 +0530224 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530225 log<level::ERR>("No Registered handlers for NetFn",
226 entry("NET_FUN=0x%X", netfn),
227 entry("CMD=0x%X", IPMI_CMD_WILDCARD));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530228
229 // Respond with a 0xC1
230 memcpy(response, &rc, IPMI_CC_LEN);
231 *data_len = IPMI_CC_LEN;
232 return rc;
233 }
234 }
235
236#ifdef __IPMI_DEBUG__
237 // We have either a perfect match -OR- a wild card atleast,
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530238 log<level::ERR>("Calling Net function",
Patrick Venture0b02be92018-08-31 11:55:55 -0700239 entry("NET_FUN=0x%X", netfn) entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530240#endif
241
242 // Extract the map data onto appropriate containers
243 auto handler_and_context = iter->second;
244
245 // Creating a pointer type casted to char* to make sure we advance 1 byte
246 // when we advance pointer to next's address. advancing void * would not
247 // make sense.
Patrick Venture0b02be92018-08-31 11:55:55 -0700248 char* respo = &((char*)response)[IPMI_CC_LEN];
vishwabmcba0bd5f2015-09-30 16:50:23 +0530249
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530250 try
251 {
252 // Response message from the plugin goes into a byte post the base
253 // response
Patrick Venture0b02be92018-08-31 11:55:55 -0700254 rc = (handler_and_context.first)(netfn, cmd, request, respo, data_len,
255 handler_and_context.second);
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530256 }
257 // IPMI command handlers can throw unhandled exceptions, catch those
258 // and return sane error code.
Patrick Venture0b02be92018-08-31 11:55:55 -0700259 catch (const std::exception& e)
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530260 {
261 log<level::ERR>(e.what(), entry("NET_FUN=0x%X", netfn),
262 entry("CMD=0x%X", cmd));
263 rc = IPMI_CC_UNSPECIFIED_ERROR;
264 *data_len = 0;
265 // fall through
266 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530267 // Now copy the return code that we got from handler and pack it in first
268 // byte.
269 memcpy(response, &rc, IPMI_CC_LEN);
Chris Austen120f7322015-10-14 23:27:31 -0500270
vishwabmcba0bd5f2015-09-30 16:50:23 +0530271 // Data length is now actual data + completion code.
272 *data_len = *data_len + IPMI_CC_LEN;
273
274 return rc;
275}
276
Patrick Venture0b02be92018-08-31 11:55:55 -0700277static int send_ipmi_message(sd_bus_message* req, unsigned char seq,
278 unsigned char netfn, unsigned char lun,
279 unsigned char cmd, unsigned char cc,
280 unsigned char* buf, unsigned char len)
281{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530282
Chris Austen0ba649e2015-10-13 12:28:13 -0500283 sd_bus_error error = SD_BUS_ERROR_NULL;
Patrick Venture0b02be92018-08-31 11:55:55 -0700284 sd_bus_message *reply = NULL, *m = NULL;
Jeremy Kerre41081f2015-10-27 12:11:36 +0800285 const char *dest, *path;
Chris Austen0ba649e2015-10-13 12:28:13 -0500286 int r, pty;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530287
Jeremy Kerre41081f2015-10-27 12:11:36 +0800288 dest = sd_bus_message_get_sender(req);
289 path = sd_bus_message_get_path(req);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530290
Patrick Venture0b02be92018-08-31 11:55:55 -0700291 r = sd_bus_message_new_method_call(bus, &m, dest, path, DBUS_INTF,
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530292 "sendMessage");
Patrick Venture0b02be92018-08-31 11:55:55 -0700293 if (r < 0)
294 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530295 log<level::ERR>("Failed to add the method object",
296 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500297 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530298 }
299
Chris Austenabfb5e82015-10-13 12:29:24 -0500300 // Responses in IPMI require a bit set. So there ya go...
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800301 netfn |= 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530302
Chris Austen0ba649e2015-10-13 12:28:13 -0500303 // Add the bytes needed for the methods to be called
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800304 r = sd_bus_message_append(m, "yyyyy", seq, netfn, lun, cmd, cc);
Patrick Venture0b02be92018-08-31 11:55:55 -0700305 if (r < 0)
306 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530307 log<level::ERR>("Failed add the netfn and others",
308 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600309 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500310 }
Chris Austen120f7322015-10-14 23:27:31 -0500311
Chris Austen0ba649e2015-10-13 12:28:13 -0500312 r = sd_bus_message_append_array(m, 'y', buf, len);
Patrick Venture0b02be92018-08-31 11:55:55 -0700313 if (r < 0)
314 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530315 log<level::ERR>("Failed to add the string of response bytes",
316 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600317 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500318 }
319
Chris Austen0ba649e2015-10-13 12:28:13 -0500320 // Call the IPMI responder on the bus so the message can be sent to the CEC
321 r = sd_bus_call(bus, m, 0, &error, &reply);
Patrick Venture0b02be92018-08-31 11:55:55 -0700322 if (r < 0)
323 {
324 log<level::ERR>("Failed to call the method", entry("DEST=%s", dest),
325 entry("PATH=%s", path), entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600326 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500327 }
328
329 r = sd_bus_message_read(reply, "x", &pty);
Patrick Venture0b02be92018-08-31 11:55:55 -0700330 if (r < 0)
331 {
332 log<level::ERR>("Failed to get a reply from the method",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530333 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500334 }
335
Chris Austen169395e2015-12-02 20:56:15 -0600336final:
Chris Austen0ba649e2015-10-13 12:28:13 -0500337 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600338 m = sd_bus_message_unref(m);
339 reply = sd_bus_message_unref(reply);
Chris Austen0ba649e2015-10-13 12:28:13 -0500340
Chris Austen0ba649e2015-10-13 12:28:13 -0500341 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Chris Austen0ba649e2015-10-13 12:28:13 -0500342}
343
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500344void cache_restricted_mode()
345{
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500346 restricted_mode = false;
347 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
348 using namespace internal;
349 using namespace internal::cache;
350 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
351 const auto& restrictionModeSetting =
Deepak Kodihallie6027092017-08-27 08:13:37 -0500352 objects->map.at(restrictionModeIntf).front();
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500353 auto method = dbus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700354 objects->service(restrictionModeSetting, restrictionModeIntf).c_str(),
355 restrictionModeSetting.c_str(), "org.freedesktop.DBus.Properties",
356 "Get");
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500357 method.append(restrictionModeIntf, "RestrictionMode");
358 auto resp = dbus.call(method);
359 if (resp.is_method_error())
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500360 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500361 log<level::ERR>("Error in RestrictionMode Get");
362 // Fail-safe to true.
363 restricted_mode = true;
364 return;
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500365 }
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500366 sdbusplus::message::variant<std::string> result;
367 resp.read(result);
368 auto restrictionMode =
369 RestrictionMode::convertModesFromString(result.get<std::string>());
Patrick Venture0b02be92018-08-31 11:55:55 -0700370 if (RestrictionMode::Modes::Whitelist == restrictionMode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500371 {
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500372 restricted_mode = true;
373 }
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500374}
375
Patrick Venture0b02be92018-08-31 11:55:55 -0700376static int handle_restricted_mode_change(sd_bus_message* m, void* user_data,
377 sd_bus_error* ret_error)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500378{
379 cache_restricted_mode();
380 return 0;
381}
382
Patrick Venture0b02be92018-08-31 11:55:55 -0700383static int handle_ipmi_command(sd_bus_message* m, void* user_data,
384 sd_bus_error* ret_error)
385{
Chris Austen0ba649e2015-10-13 12:28:13 -0500386 int r = 0;
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800387 unsigned char sequence, netfn, lun, cmd;
Patrick Venture0b02be92018-08-31 11:55:55 -0700388 const void* request;
Chris Austen0ba649e2015-10-13 12:28:13 -0500389 size_t sz;
Patrick Venture0b02be92018-08-31 11:55:55 -0700390 size_t resplen = MAX_IPMI_BUFFER;
Chris Austen0ba649e2015-10-13 12:28:13 -0500391 unsigned char response[MAX_IPMI_BUFFER];
392
Chris Austen0ba649e2015-10-13 12:28:13 -0500393 memset(response, 0, MAX_IPMI_BUFFER);
394
Patrick Venture0b02be92018-08-31 11:55:55 -0700395 r = sd_bus_message_read(m, "yyyy", &sequence, &netfn, &lun, &cmd);
396 if (r < 0)
397 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530398 log<level::ERR>("Failed to parse signal message",
399 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500400 return -1;
401 }
402
Patrick Venture0b02be92018-08-31 11:55:55 -0700403 r = sd_bus_message_read_array(m, 'y', &request, &sz);
404 if (r < 0)
405 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530406 log<level::ERR>("Failed to parse signal message",
407 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500408 return -1;
409 }
410
Patrick Venture0b02be92018-08-31 11:55:55 -0700411 fprintf(ipmiio, "IPMI Incoming: Seq 0x%02x, NetFn 0x%02x, CMD: 0x%02x \n",
412 sequence, netfn, cmd);
Chris Austen99497312015-10-22 13:00:16 -0500413 hexdump(ipmiio, (void*)request, sz);
Chris Austen0ba649e2015-10-13 12:28:13 -0500414
Chris Austen120f7322015-10-14 23:27:31 -0500415 // Allow the length field to be used for both input and output of the
Chris Austen0ba649e2015-10-13 12:28:13 -0500416 // ipmi call
417 resplen = sz;
418
Chris Austen120f7322015-10-14 23:27:31 -0500419 // Now that we have parsed the entire byte array from the caller
vishwabmcba0bd5f2015-09-30 16:50:23 +0530420 // we can call the ipmi router to do the work...
Patrick Venture0b02be92018-08-31 11:55:55 -0700421 r = ipmi_netfn_router(netfn, cmd, (void*)request, (void*)response,
422 &resplen);
423 if (r != 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530424 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530425#ifdef __IPMI_DEBUG__
Patrick Venture0b02be92018-08-31 11:55:55 -0700426 log<level::ERR>("ERROR in handling NetFn", entry("ERRNO=0x%X", -r),
427 entry("NET_FUN=0x%X", netfn), entry("CMD=0x%X", cmd));
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530428#endif
Ratan Guptae0cc8552018-01-22 14:23:04 +0530429 resplen = 0;
430 }
431 else
432 {
433 resplen = resplen - 1; // first byte is for return code.
vishwabmcba0bd5f2015-09-30 16:50:23 +0530434 }
435
Chris Austen99497312015-10-22 13:00:16 -0500436 fprintf(ipmiio, "IPMI Response:\n");
Patrick Venture0b02be92018-08-31 11:55:55 -0700437 hexdump(ipmiio, (void*)response, resplen);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530438
Chris Austen0ba649e2015-10-13 12:28:13 -0500439 // Send the response buffer from the ipmi command
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800440 r = send_ipmi_message(m, sequence, netfn, lun, cmd, response[0],
Patrick Venture0b02be92018-08-31 11:55:55 -0700441 ((unsigned char*)response) + 1, resplen);
442 if (r < 0)
443 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530444 log<level::ERR>("Failed to send the response message");
Chris Austen0ba649e2015-10-13 12:28:13 -0500445 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530446 }
447
Chris Austen0ba649e2015-10-13 12:28:13 -0500448 return 0;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530449}
450
451//----------------------------------------------------------------------
452// handler_select
453// Select all the files ending with with .so. in the given diretcory
454// @d: dirent structure containing the file name
455//----------------------------------------------------------------------
Patrick Venture0b02be92018-08-31 11:55:55 -0700456int handler_select(const struct dirent* entry)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530457{
458 // To hold ".so" from entry->d_name;
459 char dname_copy[4] = {0};
460
461 // We want to avoid checking for everything and isolate to the ones having
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500462 // .so.* or .so in them.
463 // Check for versioned libraries .so.*
Patrick Venture0b02be92018-08-31 11:55:55 -0700464 if (strstr(entry->d_name, IPMI_PLUGIN_SONAME_EXTN))
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500465 {
466 return 1;
467 }
468 // Check for non versioned libraries .so
Patrick Venture0b02be92018-08-31 11:55:55 -0700469 else if (strstr(entry->d_name, IPMI_PLUGIN_EXTN))
vishwabmcba0bd5f2015-09-30 16:50:23 +0530470 {
471 // It is possible that .so could be anywhere in the string but unlikely
Chris Austen120f7322015-10-14 23:27:31 -0500472 // But being careful here. Get the base address of the string, move
vishwabmcba0bd5f2015-09-30 16:50:23 +0530473 // until end and come back 3 steps and that gets what we need.
Patrick Venture0b02be92018-08-31 11:55:55 -0700474 strcpy(dname_copy, (entry->d_name + strlen(entry->d_name) -
475 strlen(IPMI_PLUGIN_EXTN)));
476 if (strcmp(dname_copy, IPMI_PLUGIN_EXTN) == 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530477 {
478 return 1;
479 }
480 }
481 return 0;
482}
483
Patrick Venture0b02be92018-08-31 11:55:55 -0700484// This will do a dlopen of every .so in ipmi_lib_path and will dlopen
485// everything so that they will register a callback handler
vishwabmcba0bd5f2015-09-30 16:50:23 +0530486void ipmi_register_callback_handlers(const char* ipmi_lib_path)
487{
488 // For walking the ipmi_lib_path
Patrick Venture0b02be92018-08-31 11:55:55 -0700489 struct dirent** handler_list;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530490 int num_handlers = 0;
491
492 // This is used to check and abort if someone tries to register a bad one.
Patrick Venture0b02be92018-08-31 11:55:55 -0700493 void* lib_handler = NULL;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530494
Patrick Venture0b02be92018-08-31 11:55:55 -0700495 if (ipmi_lib_path == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530496 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530497 log<level::ERR>("No handlers to be registered for ipmi.. Aborting");
vishwabmcba0bd5f2015-09-30 16:50:23 +0530498 assert(0);
499 }
500 else
501 {
502 // 1: Open ipmi_lib_path. Its usually "/usr/lib/phosphor-host-ipmid"
503 // 2: Scan the directory for the files that end with .so
Chris Austen120f7322015-10-14 23:27:31 -0500504 // 3: For each one of them, just do a 'dlopen' so that they register
vishwabmcba0bd5f2015-09-30 16:50:23 +0530505 // the handlers for callback routines.
506
507 std::string handler_fqdn = ipmi_lib_path;
Chris Austen120f7322015-10-14 23:27:31 -0500508
vishwabmcba0bd5f2015-09-30 16:50:23 +0530509 // Append a "/" since we need to add the name of the .so. If there is
510 // already a .so, adding one more is not any harm.
511 handler_fqdn += "/";
512
Patrick Venture0b02be92018-08-31 11:55:55 -0700513 num_handlers =
514 scandir(ipmi_lib_path, &handler_list, handler_select, alphasort);
Nan Li36c0cb62016-03-31 11:16:08 +0800515 if (num_handlers < 0)
516 return;
Jeremy Kerr5e8f85e2015-10-27 13:43:54 +0800517
Patrick Venture0b02be92018-08-31 11:55:55 -0700518 while (num_handlers--)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530519 {
Chris Austen54030262015-10-13 12:30:46 -0500520 handler_fqdn = ipmi_lib_path;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530521 handler_fqdn += handler_list[num_handlers]->d_name;
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530522#ifdef __IPMI_DEBUG__
523 log<level::DEBUG>("Registering handler",
524 entry("HANDLER=%s", handler_fqdn.c_str()));
525#endif
Chris Austen54030262015-10-13 12:30:46 -0500526
vishwabmcba0bd5f2015-09-30 16:50:23 +0530527 lib_handler = dlopen(handler_fqdn.c_str(), RTLD_NOW);
Nan Li36c0cb62016-03-31 11:16:08 +0800528
Patrick Venture0b02be92018-08-31 11:55:55 -0700529 if (lib_handler == NULL)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530530 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530531 log<level::ERR>("ERROR opening",
532 entry("HANDLER=%s", handler_fqdn.c_str()),
533 entry("ERROR=%s", dlerror()));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530534 }
535 // Wipe the memory allocated for this particular entry.
536 free(handler_list[num_handlers]);
537 }
Nan Li36c0cb62016-03-31 11:16:08 +0800538
vishwabmcba0bd5f2015-09-30 16:50:23 +0530539 // Done with all registration.
540 free(handler_list);
541 }
542
543 // TODO : What to be done on the memory that is given by dlopen ?.
544 return;
545}
546
Patrick Venture0b02be92018-08-31 11:55:55 -0700547sd_bus* ipmid_get_sd_bus_connection(void)
548{
Chris Austen30195fa2015-11-13 14:39:19 -0600549 return bus;
550}
551
Patrick Venture0b02be92018-08-31 11:55:55 -0700552sd_event* ipmid_get_sd_event_connection(void)
553{
Andrew Geissler93c679b2017-04-02 10:06:43 -0500554 return events;
555}
556
Patrick Venture0b02be92018-08-31 11:55:55 -0700557sd_bus_slot* ipmid_get_sd_bus_slot(void)
558{
vishwab9f559a2016-01-13 01:53:08 -0600559 return ipmid_slot;
560}
561
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530562// Calls host command manager to do the right thing for the command
Patrick Venture0b02be92018-08-31 11:55:55 -0700563void ipmid_send_cmd_to_host(CommandHandler&& cmd)
564{
565 return cmdManager->execute(std::move(cmd));
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530566}
567
Patrick Venture0b02be92018-08-31 11:55:55 -0700568cmdManagerPtr& ipmid_get_host_cmd_manager()
569{
570 return cmdManager;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530571}
572
Patrick Venture0b02be92018-08-31 11:55:55 -0700573sdbusPtr& ipmid_get_sdbus_plus_handler()
574{
575 return sdbusp;
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530576}
577
Patrick Venture0b02be92018-08-31 11:55:55 -0700578int main(int argc, char* argv[])
vishwabmcba0bd5f2015-09-30 16:50:23 +0530579{
Chris Austen0ba649e2015-10-13 12:28:13 -0500580 int r;
Chris Austen99497312015-10-22 13:00:16 -0500581 unsigned long tvalue;
582 int c;
583
Chris Austen99497312015-10-22 13:00:16 -0500584 // This file and subsequient switch is for turning on levels
585 // of trace
Patrick Venture0b02be92018-08-31 11:55:55 -0700586 ipmicmddetails = ipmiio = ipmidbus = fopen("/dev/null", "w");
Chris Austen99497312015-10-22 13:00:16 -0500587
Patrick Venture0b02be92018-08-31 11:55:55 -0700588 while ((c = getopt(argc, argv, "h:d:")) != -1)
589 switch (c)
590 {
Chris Austen99497312015-10-22 13:00:16 -0500591 case 'd':
Patrick Venture0b02be92018-08-31 11:55:55 -0700592 tvalue = strtoul(optarg, NULL, 16);
593 if (1 & tvalue)
594 {
Chris Austen99497312015-10-22 13:00:16 -0500595 ipmiio = stdout;
596 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700597 if (2 & tvalue)
598 {
Chris Austen99497312015-10-22 13:00:16 -0500599 ipmidbus = stdout;
600 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700601 if (4 & tvalue)
602 {
Chris Austen99497312015-10-22 13:00:16 -0500603 ipmicmddetails = stdout;
604 }
605 break;
Patrick Venture0b02be92018-08-31 11:55:55 -0700606 case 'h':
607 case '?':
Chris Austen99497312015-10-22 13:00:16 -0500608 print_usage();
609 return 1;
610 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500611
Chris Austen0ba649e2015-10-13 12:28:13 -0500612 /* Connect to system bus */
613 r = sd_bus_open_system(&bus);
Patrick Venture0b02be92018-08-31 11:55:55 -0700614 if (r < 0)
615 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530616 log<level::ERR>("Failed to connect to system bus",
617 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500618 goto finish;
619 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530620
Andrew Geissler93c679b2017-04-02 10:06:43 -0500621 /* Get an sd event handler */
622 r = sd_event_default(&events);
623 if (r < 0)
624 {
625 log<level::ERR>("Failure to create sd_event handler",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530626 entry("ERRNO=0x%X", -r));
Andrew Geissler93c679b2017-04-02 10:06:43 -0500627 goto finish;
628 }
629
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530630 // Now create the Host Bound Command manager. Need sdbusplus
631 // to use the generated bindings
632 sdbusp = std::make_unique<sdbusplus::bus::bus>(bus);
Patrick Venture0b02be92018-08-31 11:55:55 -0700633 cmdManager =
634 std::make_unique<phosphor::host::command::Manager>(*sdbusp, events);
Andrew Geissler93c679b2017-04-02 10:06:43 -0500635
Peter Hanson4a589852017-06-07 17:40:45 -0700636 // Activate OemRouter.
637 oem::mutableRouter()->activate();
638
Chris Austen30195fa2015-11-13 14:39:19 -0600639 // Register all the handlers that provider implementation to IPMI commands.
640 ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
641
Patrick Venture0b02be92018-08-31 11:55:55 -0700642 // Watch for BT messages
vishwab9f559a2016-01-13 01:53:08 -0600643 r = sd_bus_add_match(bus, &ipmid_slot, FILTER, handle_ipmi_command, NULL);
Patrick Venture0b02be92018-08-31 11:55:55 -0700644 if (r < 0)
645 {
646 log<level::ERR>("Failed: sd_bus_add_match", entry("FILTER=%s", FILTER),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530647 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500648 goto finish;
649 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530650
Andrew Geissler93c679b2017-04-02 10:06:43 -0500651 // Attach the bus to sd_event to service user requests
652 sd_bus_attach_event(bus, events, SD_EVENT_PRIORITY_NORMAL);
653
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500654 {
655 using namespace internal;
656 using namespace internal::cache;
657 sdbusplus::bus::bus dbus{bus};
658 objects = std::make_unique<settings::Objects>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700659 dbus, std::vector<settings::Interface>({restrictionModeIntf}));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500660 // Initialize restricted mode
661 cache_restricted_mode();
662 // Wait for changes on Restricted mode
663 sdbusplus::bus::match_t restrictedModeMatch(
664 dbus,
665 sdbusRule::propertiesChanged(
Deepak Kodihallie6027092017-08-27 08:13:37 -0500666 objects->map.at(restrictionModeIntf).front(),
667 restrictionModeIntf),
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500668 handle_restricted_mode_change);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530669
Patrick Venture0b02be92018-08-31 11:55:55 -0700670 for (;;)
671 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500672 /* Process requests */
673 r = sd_event_run(events, (uint64_t)-1);
674 if (r < 0)
675 {
676 log<level::ERR>("Failure in processing request",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530677 entry("ERRNO=0x%X", -r));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500678 goto finish;
679 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500680 }
681 }
682
683finish:
Andrew Geissler93c679b2017-04-02 10:06:43 -0500684 sd_event_unref(events);
685 sd_bus_detach_event(bus);
vishwab9f559a2016-01-13 01:53:08 -0600686 sd_bus_slot_unref(ipmid_slot);
Chris Austen0ba649e2015-10-13 12:28:13 -0500687 sd_bus_unref(bus);
688 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530689}