blob: 3d7c663eb3c90f83904948d9bc7e8e63555c9293 [file] [log] [blame]
vishwabmcba0bd5f2015-09-30 16:50:23 +05301#include <stdio.h>
2#include <dlfcn.h>
3#include <iostream>
4#include <unistd.h>
5#include <assert.h>
6#include <dirent.h>
Chris Austen0ba649e2015-10-13 12:28:13 -05007#include <systemd/sd-bus.h>
vishwabmcba0bd5f2015-09-30 16:50:23 +05308#include <string.h>
9#include <stdlib.h>
10#include <map>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050011#include <memory>
Andrew Geissler93c679b2017-04-02 10:06:43 -050012#include <phosphor-logging/log.hpp>
Chris Austen0ba649e2015-10-13 12:28:13 -050013#include <sys/time.h>
14#include <errno.h>
Brad Bishop35518682016-07-22 08:35:41 -040015#include <mapper.h>
Chris Austen0012e9b2015-10-22 01:37:46 -050016#include "sensorhandler.h"
Tom Joseph9a61b4f2016-07-11 06:56:11 -050017#include <vector>
18#include <algorithm>
19#include <iterator>
Patrick Williams4b9efaa2016-08-12 21:59:51 -050020#include <ipmiwhitelist.hpp>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050021#include <sdbusplus/bus.hpp>
22#include <sdbusplus/bus/match.hpp>
23#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
24#include "sensorhandler.h"
25#include "ipmid.hpp"
26#include "settings.hpp"
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053027#include <host-cmd-manager.hpp>
Vishwanatha Subbanna6e8979d2017-07-13 16:48:20 +053028#include <host-ipmid/ipmid-host-cmd.hpp>
29#include <timer.hpp>
Chris Austen0ba649e2015-10-13 12:28:13 -050030
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
Chris Austen0ba649e2015-10-13 12:28:13 -050034sd_bus *bus = NULL;
vishwab9f559a2016-01-13 01:53:08 -060035sd_bus_slot *ipmid_slot = NULL;
Andrew Geissler93c679b2017-04-02 10:06:43 -050036sd_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
Chris Austen99497312015-10-22 13:00:16 -050057void print_usage(void) {
58 fprintf(stderr, "Options: [-d mask]\n");
59 fprintf(stderr, " mask : 0x01 - Print ipmi packets\n");
60 fprintf(stderr, " mask : 0x02 - Print DBUS operations\n");
61 fprintf(stderr, " mask : 0x04 - Print ipmi command details\n");
62 fprintf(stderr, " mask : 0xFF - Print all trace\n");
63}
64
Jeremy Kerre41081f2015-10-27 12:11:36 +080065const char * DBUS_INTF = "org.openbmc.HostIpmi";
vishwabmcba0bd5f2015-09-30 16:50:23 +053066
Jeremy Kerre41081f2015-10-27 12:11:36 +080067const char * FILTER = "type='signal',interface='org.openbmc.HostIpmi',member='ReceivedMessage'";
Chris Austen0ba649e2015-10-13 12:28:13 -050068
vishwabmcba0bd5f2015-09-30 16:50:23 +053069typedef std::pair<ipmi_netfn_t, ipmi_cmd_t> ipmi_fn_cmd_t;
70typedef std::pair<ipmid_callback_t, ipmi_context_t> ipmi_fn_context_t;
71
72// Global data structure that contains the IPMI command handler's registrations.
73std::map<ipmi_fn_cmd_t, ipmi_fn_context_t> g_ipmid_router_map;
74
Nan Li36c0cb62016-03-31 11:16:08 +080075// IPMI Spec, shared Reservation ID.
76unsigned short g_sel_reserve = 0xFFFF;
77
78unsigned short get_sel_reserve_id(void)
79{
80 return g_sel_reserve;
81}
Chris Austen0ba649e2015-10-13 12:28:13 -050082
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050083namespace internal
84{
85
86constexpr auto restrictionModeIntf =
87 "xyz.openbmc_project.Control.Security.RestrictionMode";
88
89namespace cache
90{
91
92std::unique_ptr<settings::Objects> objects = nullptr;
93
94} // namespace cache
95} // namespace internal
96
Chris Austen0ba649e2015-10-13 12:28:13 -050097#ifndef HEXDUMP_COLS
98#define HEXDUMP_COLS 16
99#endif
100
Chris Austen99497312015-10-22 13:00:16 -0500101void hexdump(FILE *s, void *mem, size_t len)
Chris Austen0ba649e2015-10-13 12:28:13 -0500102{
103 unsigned int i, j;
Chris Austen120f7322015-10-14 23:27:31 -0500104
Chris Austen0ba649e2015-10-13 12:28:13 -0500105 for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++)
106 {
107 /* print offset */
108 if(i % HEXDUMP_COLS == 0)
109 {
Chris Austen99497312015-10-22 13:00:16 -0500110 fprintf(s,"0x%06x: ", i);
Chris Austen0ba649e2015-10-13 12:28:13 -0500111 }
Chris Austen120f7322015-10-14 23:27:31 -0500112
Chris Austen0ba649e2015-10-13 12:28:13 -0500113 /* print hex data */
114 if(i < len)
115 {
Chris Austen99497312015-10-22 13:00:16 -0500116 fprintf(s,"%02x ", 0xFF & ((char*)mem)[i]);
Chris Austen0ba649e2015-10-13 12:28:13 -0500117 }
118 else /* end of block, just aligning for ASCII dump */
119 {
Chris Austen99497312015-10-22 13:00:16 -0500120 fprintf(s," ");
Chris Austen0ba649e2015-10-13 12:28:13 -0500121 }
Chris Austen120f7322015-10-14 23:27:31 -0500122
Chris Austen0ba649e2015-10-13 12:28:13 -0500123 /* print ASCII dump */
124 if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
125 {
126 for(j = i - (HEXDUMP_COLS - 1); j <= i; j++)
127 {
128 if(j >= len) /* end of block, not really printing */
129 {
Chris Austen99497312015-10-22 13:00:16 -0500130 fputc(' ', s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500131 }
132 else if(isprint(((char*)mem)[j])) /* printable char */
133 {
Chris Austen99497312015-10-22 13:00:16 -0500134 fputc(0xFF & ((char*)mem)[j], s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500135 }
136 else /* other char */
137 {
Chris Austen99497312015-10-22 13:00:16 -0500138 fputc('.',s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500139 }
140 }
Chris Austen99497312015-10-22 13:00:16 -0500141 fputc('\n',s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500142 }
143 }
144}
145
146
vishwabmcba0bd5f2015-09-30 16:50:23 +0530147// Method that gets called by shared libraries to get their command handlers registered
Tom05732372016-09-06 17:21:23 +0530148void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_context_t context,
149 ipmid_callback_t handler, ipmi_cmd_privilege_t priv)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530150{
151 // Pack NetFn and Command in one.
152 auto netfn_and_cmd = std::make_pair(netfn, cmd);
153
154 // Pack Function handler and Data in another.
155 auto handler_and_context = std::make_pair(handler, context);
156
157 // Check if the registration has already been made..
158 auto iter = g_ipmid_router_map.find(netfn_and_cmd);
159 if(iter != g_ipmid_router_map.end())
160 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530161 log<level::ERR>("Duplicate registration",
162 entry("NETFN=0x%X", netfn),
163 entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530164 }
165 else
166 {
167 // This is a fresh registration.. Add it to the map.
168 g_ipmid_router_map.emplace(netfn_and_cmd, handler_and_context);
169 }
170
171 return;
172}
173
174// Looks at the map and calls corresponding handler functions.
175ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
176 ipmi_response_t response, ipmi_data_len_t data_len)
177{
178 // return from the Command handlers.
179 ipmi_ret_t rc = IPMI_CC_INVALID;
180
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500181 // If restricted mode is true and command is not whitelisted, don't
182 // execute the command
183 if(restricted_mode)
184 {
185 if (!std::binary_search(whitelist.cbegin(), whitelist.cend(),
186 std::make_pair(netfn, cmd)))
187 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530188 log<level::ERR>("Net function not whitelisted",
189 entry("NETFN=0x%X", netfn),
190 entry("CMD=0x%X", cmd));
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500191 rc = IPMI_CC_INSUFFICIENT_PRIVILEGE;
192 memcpy(response, &rc, IPMI_CC_LEN);
193 *data_len = IPMI_CC_LEN;
194 return rc;
195 }
196 }
197
vishwabmcba0bd5f2015-09-30 16:50:23 +0530198 // Walk the map that has the registered handlers and invoke the approprite
199 // handlers for matching commands.
200 auto iter = g_ipmid_router_map.find(std::make_pair(netfn, cmd));
201 if(iter == g_ipmid_router_map.end())
202 {
Patrick Venture03f84ba2017-09-20 09:15:33 -0700203 /* By default should only print on failure to find wildcard command. */
204#ifdef __IPMI_DEBUG__
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530205 log<level::ERR>(
206 "No registered handlers for NetFn, trying Wilcard implementation",
207 entry("NET_FUN=0x%X", netfn)
208 entry("CMD=0x%X", IPMI_CMD_WILDCARD));
Patrick Venture03f84ba2017-09-20 09:15:33 -0700209#endif
vishwabmcba0bd5f2015-09-30 16:50:23 +0530210
211 // Now that we did not find any specific [NetFn,Cmd], tuple, check for
212 // NetFn, WildCard command present.
213 iter = g_ipmid_router_map.find(std::make_pair(netfn, IPMI_CMD_WILDCARD));
214 if(iter == g_ipmid_router_map.end())
215 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530216 log<level::ERR>("No Registered handlers for NetFn",
217 entry("NET_FUN=0x%X", netfn),
218 entry("CMD=0x%X", IPMI_CMD_WILDCARD));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530219
220 // Respond with a 0xC1
221 memcpy(response, &rc, IPMI_CC_LEN);
222 *data_len = IPMI_CC_LEN;
223 return rc;
224 }
225 }
226
227#ifdef __IPMI_DEBUG__
228 // We have either a perfect match -OR- a wild card atleast,
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530229 log<level::ERR>("Calling Net function",
230 entry("NET_FUN=0x%X", netfn)
231 entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530232#endif
233
234 // Extract the map data onto appropriate containers
235 auto handler_and_context = iter->second;
236
237 // Creating a pointer type casted to char* to make sure we advance 1 byte
238 // when we advance pointer to next's address. advancing void * would not
239 // make sense.
240 char *respo = &((char *)response)[IPMI_CC_LEN];
241
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530242 try
243 {
244 // Response message from the plugin goes into a byte post the base
245 // response
246 rc = (handler_and_context.first) (netfn, cmd, request, respo,
247 data_len, handler_and_context.second);
248 }
249 // IPMI command handlers can throw unhandled exceptions, catch those
250 // and return sane error code.
251 catch (const std::exception &e)
252 {
253 log<level::ERR>(e.what(), entry("NET_FUN=0x%X", netfn),
254 entry("CMD=0x%X", cmd));
255 rc = IPMI_CC_UNSPECIFIED_ERROR;
256 *data_len = 0;
257 // fall through
258 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530259 // Now copy the return code that we got from handler and pack it in first
260 // byte.
261 memcpy(response, &rc, IPMI_CC_LEN);
Chris Austen120f7322015-10-14 23:27:31 -0500262
vishwabmcba0bd5f2015-09-30 16:50:23 +0530263 // Data length is now actual data + completion code.
264 *data_len = *data_len + IPMI_CC_LEN;
265
266 return rc;
267}
268
vishwabmcba0bd5f2015-09-30 16:50:23 +0530269
vishwabmcba0bd5f2015-09-30 16:50:23 +0530270
vishwabmcba0bd5f2015-09-30 16:50:23 +0530271
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800272static int send_ipmi_message(sd_bus_message *req, unsigned char seq, unsigned char netfn, unsigned char lun, unsigned char cmd, unsigned char cc, unsigned char *buf, unsigned char len) {
vishwabmcba0bd5f2015-09-30 16:50:23 +0530273
Chris Austen0ba649e2015-10-13 12:28:13 -0500274 sd_bus_error error = SD_BUS_ERROR_NULL;
275 sd_bus_message *reply = NULL, *m=NULL;
Jeremy Kerre41081f2015-10-27 12:11:36 +0800276 const char *dest, *path;
Chris Austen0ba649e2015-10-13 12:28:13 -0500277 int r, pty;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530278
Jeremy Kerre41081f2015-10-27 12:11:36 +0800279 dest = sd_bus_message_get_sender(req);
280 path = sd_bus_message_get_path(req);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530281
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530282 r = sd_bus_message_new_method_call(bus,&m,dest,path,
283 DBUS_INTF,
284 "sendMessage");
Chris Austen0ba649e2015-10-13 12:28:13 -0500285 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530286 log<level::ERR>("Failed to add the method object",
287 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500288 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530289 }
290
vishwabmcba0bd5f2015-09-30 16:50:23 +0530291
Chris Austenabfb5e82015-10-13 12:29:24 -0500292 // Responses in IPMI require a bit set. So there ya go...
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800293 netfn |= 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530294
Chris Austen0ba649e2015-10-13 12:28:13 -0500295
296 // Add the bytes needed for the methods to be called
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800297 r = sd_bus_message_append(m, "yyyyy", seq, netfn, lun, cmd, cc);
Chris Austen0ba649e2015-10-13 12:28:13 -0500298 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530299 log<level::ERR>("Failed add the netfn and others",
300 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600301 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500302 }
Chris Austen120f7322015-10-14 23:27:31 -0500303
Chris Austen0ba649e2015-10-13 12:28:13 -0500304 r = sd_bus_message_append_array(m, 'y', buf, len);
305 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530306 log<level::ERR>("Failed to add the string of response bytes",
307 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600308 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500309 }
310
311
312
313 // Call the IPMI responder on the bus so the message can be sent to the CEC
314 r = sd_bus_call(bus, m, 0, &error, &reply);
315 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530316 log<level::ERR>("Failed to call the method",
317 entry("DEST=%s", dest),
318 entry("PATH=%s", path),
319 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600320 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500321 }
322
323 r = sd_bus_message_read(reply, "x", &pty);
Chris Austen0ba649e2015-10-13 12:28:13 -0500324 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530325 log<level::ERR>("Failed to get a reply from the method",
326 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500327 }
328
Chris Austen169395e2015-12-02 20:56:15 -0600329final:
Chris Austen0ba649e2015-10-13 12:28:13 -0500330 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600331 m = sd_bus_message_unref(m);
332 reply = sd_bus_message_unref(reply);
Chris Austen0ba649e2015-10-13 12:28:13 -0500333
Chris Austen0ba649e2015-10-13 12:28:13 -0500334 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Chris Austen0ba649e2015-10-13 12:28:13 -0500335}
336
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500337void cache_restricted_mode()
338{
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500339 restricted_mode = false;
340 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
341 using namespace internal;
342 using namespace internal::cache;
343 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
344 const auto& restrictionModeSetting =
Deepak Kodihallie6027092017-08-27 08:13:37 -0500345 objects->map.at(restrictionModeIntf).front();
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500346 auto method = dbus.new_method_call(
347 objects->service(restrictionModeSetting,
348 restrictionModeIntf).c_str(),
349 restrictionModeSetting.c_str(),
350 "org.freedesktop.DBus.Properties",
351 "Get");
352 method.append(restrictionModeIntf, "RestrictionMode");
353 auto resp = dbus.call(method);
354 if (resp.is_method_error())
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500355 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500356 log<level::ERR>("Error in RestrictionMode Get");
357 // Fail-safe to true.
358 restricted_mode = true;
359 return;
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500360 }
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500361 sdbusplus::message::variant<std::string> result;
362 resp.read(result);
363 auto restrictionMode =
364 RestrictionMode::convertModesFromString(result.get<std::string>());
365 if(RestrictionMode::Modes::Whitelist == restrictionMode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500366 {
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500367 restricted_mode = true;
368 }
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500369}
370
371static int handle_restricted_mode_change(sd_bus_message *m, void *user_data,
372 sd_bus_error *ret_error)
373{
374 cache_restricted_mode();
375 return 0;
376}
377
Chris Austen0ba649e2015-10-13 12:28:13 -0500378static int handle_ipmi_command(sd_bus_message *m, void *user_data, sd_bus_error
379 *ret_error) {
380 int r = 0;
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800381 unsigned char sequence, netfn, lun, cmd;
Chris Austen0ba649e2015-10-13 12:28:13 -0500382 const void *request;
383 size_t sz;
384 size_t resplen =MAX_IPMI_BUFFER;
385 unsigned char response[MAX_IPMI_BUFFER];
386
Chris Austen0ba649e2015-10-13 12:28:13 -0500387 memset(response, 0, MAX_IPMI_BUFFER);
388
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800389 r = sd_bus_message_read(m, "yyyy", &sequence, &netfn, &lun, &cmd);
Chris Austen0ba649e2015-10-13 12:28:13 -0500390 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530391 log<level::ERR>("Failed to parse signal message",
392 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500393 return -1;
394 }
395
396 r = sd_bus_message_read_array(m, 'y', &request, &sz );
397 if (r < 0) {
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
Chris Austen99497312015-10-22 13:00:16 -0500403 fprintf(ipmiio, "IPMI Incoming: Seq 0x%02x, NetFn 0x%02x, CMD: 0x%02x \n", sequence, netfn, cmd);
404 hexdump(ipmiio, (void*)request, sz);
Chris Austen0ba649e2015-10-13 12:28:13 -0500405
Chris Austen120f7322015-10-14 23:27:31 -0500406 // Allow the length field to be used for both input and output of the
Chris Austen0ba649e2015-10-13 12:28:13 -0500407 // ipmi call
408 resplen = sz;
409
Chris Austen120f7322015-10-14 23:27:31 -0500410 // Now that we have parsed the entire byte array from the caller
vishwabmcba0bd5f2015-09-30 16:50:23 +0530411 // we can call the ipmi router to do the work...
Chris Austen0ba649e2015-10-13 12:28:13 -0500412 r = ipmi_netfn_router(netfn, cmd, (void *)request, (void *)response, &resplen);
413 if(r != 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530414 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530415#ifdef __IPMI_DEBUG__
416 log<level::ERR>("ERROR in handling NetFn",
417 entry("ERRNO=0x%X", -r),
418 entry("NET_FUN=0x%X", netfn),
419 entry("CMD=0x%X", cmd));
420#endif
Ratan Guptae0cc8552018-01-22 14:23:04 +0530421 resplen = 0;
422 }
423 else
424 {
425 resplen = resplen - 1; // first byte is for return code.
vishwabmcba0bd5f2015-09-30 16:50:23 +0530426 }
427
Chris Austen99497312015-10-22 13:00:16 -0500428 fprintf(ipmiio, "IPMI Response:\n");
429 hexdump(ipmiio, (void*)response, resplen);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530430
Chris Austen0ba649e2015-10-13 12:28:13 -0500431 // Send the response buffer from the ipmi command
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800432 r = send_ipmi_message(m, sequence, netfn, lun, cmd, response[0],
Ratan Guptae0cc8552018-01-22 14:23:04 +0530433 ((unsigned char *)response) + 1, resplen);
Chris Austen0ba649e2015-10-13 12:28:13 -0500434 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530435 log<level::ERR>("Failed to send the response message");
Chris Austen0ba649e2015-10-13 12:28:13 -0500436 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530437 }
438
vishwabmcba0bd5f2015-09-30 16:50:23 +0530439
Chris Austen0ba649e2015-10-13 12:28:13 -0500440 return 0;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530441}
442
Chris Austen0ba649e2015-10-13 12:28:13 -0500443
vishwabmcba0bd5f2015-09-30 16:50:23 +0530444//----------------------------------------------------------------------
445// handler_select
446// Select all the files ending with with .so. in the given diretcory
447// @d: dirent structure containing the file name
448//----------------------------------------------------------------------
449int handler_select(const struct dirent *entry)
450{
451 // To hold ".so" from entry->d_name;
452 char dname_copy[4] = {0};
453
454 // We want to avoid checking for everything and isolate to the ones having
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500455 // .so.* or .so in them.
456 // Check for versioned libraries .so.*
457 if(strstr(entry->d_name, IPMI_PLUGIN_SONAME_EXTN))
458 {
459 return 1;
460 }
461 // Check for non versioned libraries .so
462 else if(strstr(entry->d_name, IPMI_PLUGIN_EXTN))
vishwabmcba0bd5f2015-09-30 16:50:23 +0530463 {
464 // It is possible that .so could be anywhere in the string but unlikely
Chris Austen120f7322015-10-14 23:27:31 -0500465 // But being careful here. Get the base address of the string, move
vishwabmcba0bd5f2015-09-30 16:50:23 +0530466 // until end and come back 3 steps and that gets what we need.
467 strcpy(dname_copy, (entry->d_name + strlen(entry->d_name)-strlen(IPMI_PLUGIN_EXTN)));
468 if(strcmp(dname_copy, IPMI_PLUGIN_EXTN) == 0)
469 {
470 return 1;
471 }
472 }
473 return 0;
474}
475
476// This will do a dlopen of every .so in ipmi_lib_path and will dlopen everything so that they will
Chris Austen120f7322015-10-14 23:27:31 -0500477// register a callback handler
vishwabmcba0bd5f2015-09-30 16:50:23 +0530478void ipmi_register_callback_handlers(const char* ipmi_lib_path)
479{
480 // For walking the ipmi_lib_path
481 struct dirent **handler_list;
482 int num_handlers = 0;
483
484 // This is used to check and abort if someone tries to register a bad one.
485 void *lib_handler = NULL;
486
487 if(ipmi_lib_path == NULL)
488 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530489 log<level::ERR>("No handlers to be registered for ipmi.. Aborting");
vishwabmcba0bd5f2015-09-30 16:50:23 +0530490 assert(0);
491 }
492 else
493 {
494 // 1: Open ipmi_lib_path. Its usually "/usr/lib/phosphor-host-ipmid"
495 // 2: Scan the directory for the files that end with .so
Chris Austen120f7322015-10-14 23:27:31 -0500496 // 3: For each one of them, just do a 'dlopen' so that they register
vishwabmcba0bd5f2015-09-30 16:50:23 +0530497 // the handlers for callback routines.
498
499 std::string handler_fqdn = ipmi_lib_path;
Chris Austen120f7322015-10-14 23:27:31 -0500500
vishwabmcba0bd5f2015-09-30 16:50:23 +0530501 // Append a "/" since we need to add the name of the .so. If there is
502 // already a .so, adding one more is not any harm.
503 handler_fqdn += "/";
504
505 num_handlers = scandir(ipmi_lib_path, &handler_list, handler_select, alphasort);
Nan Li36c0cb62016-03-31 11:16:08 +0800506 if (num_handlers < 0)
507 return;
Jeremy Kerr5e8f85e2015-10-27 13:43:54 +0800508
vishwabmcba0bd5f2015-09-30 16:50:23 +0530509 while(num_handlers--)
510 {
Chris Austen54030262015-10-13 12:30:46 -0500511 handler_fqdn = ipmi_lib_path;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530512 handler_fqdn += handler_list[num_handlers]->d_name;
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530513#ifdef __IPMI_DEBUG__
514 log<level::DEBUG>("Registering handler",
515 entry("HANDLER=%s", handler_fqdn.c_str()));
516#endif
Chris Austen54030262015-10-13 12:30:46 -0500517
vishwabmcba0bd5f2015-09-30 16:50:23 +0530518 lib_handler = dlopen(handler_fqdn.c_str(), RTLD_NOW);
Nan Li36c0cb62016-03-31 11:16:08 +0800519
vishwabmcba0bd5f2015-09-30 16:50:23 +0530520 if(lib_handler == NULL)
521 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530522 log<level::ERR>("ERROR opening",
523 entry("HANDLER=%s", handler_fqdn.c_str()),
524 entry("ERROR=%s", dlerror()));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530525 }
526 // Wipe the memory allocated for this particular entry.
527 free(handler_list[num_handlers]);
528 }
Nan Li36c0cb62016-03-31 11:16:08 +0800529
vishwabmcba0bd5f2015-09-30 16:50:23 +0530530 // Done with all registration.
531 free(handler_list);
532 }
533
534 // TODO : What to be done on the memory that is given by dlopen ?.
535 return;
536}
537
Chris Austen30195fa2015-11-13 14:39:19 -0600538sd_bus *ipmid_get_sd_bus_connection(void) {
539 return bus;
540}
541
Andrew Geissler93c679b2017-04-02 10:06:43 -0500542sd_event *ipmid_get_sd_event_connection(void) {
543 return events;
544}
545
vishwab9f559a2016-01-13 01:53:08 -0600546sd_bus_slot *ipmid_get_sd_bus_slot(void) {
547 return ipmid_slot;
548}
549
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530550// Calls host command manager to do the right thing for the command
551void ipmid_send_cmd_to_host(CommandHandler&& cmd) {
552 return cmdManager->execute(std::move(cmd));
553}
554
555cmdManagerPtr& ipmid_get_host_cmd_manager() {
556 return cmdManager;
557}
558
559sdbusPtr& ipmid_get_sdbus_plus_handler() {
560 return sdbusp;
561}
562
vishwabmcba0bd5f2015-09-30 16:50:23 +0530563int main(int argc, char *argv[])
564{
Chris Austen0ba649e2015-10-13 12:28:13 -0500565 int r;
Chris Austen99497312015-10-22 13:00:16 -0500566 unsigned long tvalue;
567 int c;
568
569
570
571 // This file and subsequient switch is for turning on levels
572 // of trace
573 ipmicmddetails = ipmiio = ipmidbus = fopen("/dev/null", "w");
574
575 while ((c = getopt (argc, argv, "h:d:")) != -1)
576 switch (c) {
577 case 'd':
578 tvalue = strtoul(optarg, NULL, 16);
579 if (1&tvalue) {
580 ipmiio = stdout;
581 }
582 if (2&tvalue) {
583 ipmidbus = stdout;
584 }
585 if (4&tvalue) {
586 ipmicmddetails = stdout;
587 }
588 break;
589 case 'h':
590 case '?':
591 print_usage();
592 return 1;
593 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500594
595
Chris Austen0ba649e2015-10-13 12:28:13 -0500596 /* Connect to system bus */
597 r = sd_bus_open_system(&bus);
598 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530599 log<level::ERR>("Failed to connect to system bus",
600 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500601 goto finish;
602 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530603
Andrew Geissler93c679b2017-04-02 10:06:43 -0500604 /* Get an sd event handler */
605 r = sd_event_default(&events);
606 if (r < 0)
607 {
608 log<level::ERR>("Failure to create sd_event handler",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530609 entry("ERRNO=0x%X", -r));
Andrew Geissler93c679b2017-04-02 10:06:43 -0500610 goto finish;
611 }
612
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530613 // Now create the Host Bound Command manager. Need sdbusplus
614 // to use the generated bindings
615 sdbusp = std::make_unique<sdbusplus::bus::bus>(bus);
616 cmdManager = std::make_unique<phosphor::host::command::Manager>(
617 *sdbusp, events);
Andrew Geissler93c679b2017-04-02 10:06:43 -0500618
Chris Austen30195fa2015-11-13 14:39:19 -0600619 // Register all the handlers that provider implementation to IPMI commands.
620 ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
621
vishwa36993272015-11-20 12:43:49 -0600622 // Watch for BT messages
vishwab9f559a2016-01-13 01:53:08 -0600623 r = sd_bus_add_match(bus, &ipmid_slot, FILTER, handle_ipmi_command, NULL);
Chris Austen0ba649e2015-10-13 12:28:13 -0500624 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530625 log<level::ERR>("Failed: sd_bus_add_match",
626 entry("FILTER=%s", FILTER),
627 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500628 goto finish;
629 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530630
Andrew Geissler93c679b2017-04-02 10:06:43 -0500631 // Attach the bus to sd_event to service user requests
632 sd_bus_attach_event(bus, events, SD_EVENT_PRIORITY_NORMAL);
633
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500634 {
635 using namespace internal;
636 using namespace internal::cache;
637 sdbusplus::bus::bus dbus{bus};
638 objects = std::make_unique<settings::Objects>(
639 dbus,
640 std::vector<settings::Interface>({restrictionModeIntf}));
641 // Initialize restricted mode
642 cache_restricted_mode();
643 // Wait for changes on Restricted mode
644 sdbusplus::bus::match_t restrictedModeMatch(
645 dbus,
646 sdbusRule::propertiesChanged(
Deepak Kodihallie6027092017-08-27 08:13:37 -0500647 objects->map.at(restrictionModeIntf).front(),
648 restrictionModeIntf),
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500649 handle_restricted_mode_change);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530650
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500651 for (;;) {
652 /* Process requests */
653 r = sd_event_run(events, (uint64_t)-1);
654 if (r < 0)
655 {
656 log<level::ERR>("Failure in processing request",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530657 entry("ERRNO=0x%X", -r));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500658 goto finish;
659 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500660 }
661 }
662
663finish:
Andrew Geissler93c679b2017-04-02 10:06:43 -0500664 sd_event_unref(events);
665 sd_bus_detach_event(bus);
vishwab9f559a2016-01-13 01:53:08 -0600666 sd_bus_slot_unref(ipmid_slot);
Chris Austen0ba649e2015-10-13 12:28:13 -0500667 sd_bus_unref(bus);
668 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
669
vishwabmcba0bd5f2015-09-30 16:50:23 +0530670}