blob: f664488570a6c4226ec8cfb401481e187a84c95d [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>
Peter Hanson4a589852017-06-07 17:40:45 -070030#include "host-ipmid/oemrouter.hpp"
Chris Austen0ba649e2015-10-13 12:28:13 -050031
Andrew Geissler93c679b2017-04-02 10:06:43 -050032using namespace phosphor::logging;
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050033namespace sdbusRule = sdbusplus::bus::match::rules;
Andrew Geissler93c679b2017-04-02 10:06:43 -050034
Chris Austen0ba649e2015-10-13 12:28:13 -050035sd_bus *bus = NULL;
vishwab9f559a2016-01-13 01:53:08 -060036sd_bus_slot *ipmid_slot = NULL;
Andrew Geissler93c679b2017-04-02 10:06:43 -050037sd_event *events = nullptr;
Chris Austen30195fa2015-11-13 14:39:19 -060038
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053039// Need this to use new sdbusplus compatible interfaces
40sdbusPtr sdbusp;
41
42// Global Host Bound Command manager
43using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>;
44cmdManagerPtr cmdManager;
45
Ratan Gupta7a7f0122018-03-07 12:31:05 +053046// Global timer for network changes
47std::unique_ptr<phosphor::ipmi::Timer> networkTimer = nullptr;
48
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053049// Command and handler tuple. Used when clients ask the command to be put
50// into host message queue
51using CommandHandler = phosphor::host::command::CommandHandler;
52
Tom Joseph9a61b4f2016-07-11 06:56:11 -050053// Initialise restricted mode to true
54bool restricted_mode = true;
55
Chris Austen41a4b312015-10-25 03:45:42 -050056FILE *ipmiio, *ipmidbus, *ipmicmddetails;
vishwabmcba0bd5f2015-09-30 16:50:23 +053057
Chris Austen99497312015-10-22 13:00:16 -050058void print_usage(void) {
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");
64}
65
Jeremy Kerre41081f2015-10-27 12:11:36 +080066const char * DBUS_INTF = "org.openbmc.HostIpmi";
vishwabmcba0bd5f2015-09-30 16:50:23 +053067
Jeremy Kerre41081f2015-10-27 12:11:36 +080068const char * FILTER = "type='signal',interface='org.openbmc.HostIpmi',member='ReceivedMessage'";
Chris Austen0ba649e2015-10-13 12:28:13 -050069
vishwabmcba0bd5f2015-09-30 16:50:23 +053070typedef std::pair<ipmi_netfn_t, ipmi_cmd_t> ipmi_fn_cmd_t;
71typedef std::pair<ipmid_callback_t, ipmi_context_t> ipmi_fn_context_t;
72
73// Global data structure that contains the IPMI command handler's registrations.
74std::map<ipmi_fn_cmd_t, ipmi_fn_context_t> g_ipmid_router_map;
75
Nan Li36c0cb62016-03-31 11:16:08 +080076// IPMI Spec, shared Reservation ID.
77unsigned short g_sel_reserve = 0xFFFF;
78
79unsigned short get_sel_reserve_id(void)
80{
81 return g_sel_reserve;
82}
Chris Austen0ba649e2015-10-13 12:28:13 -050083
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050084namespace internal
85{
86
87constexpr auto restrictionModeIntf =
88 "xyz.openbmc_project.Control.Security.RestrictionMode";
89
90namespace cache
91{
92
93std::unique_ptr<settings::Objects> objects = nullptr;
94
95} // namespace cache
96} // namespace internal
97
Chris Austen0ba649e2015-10-13 12:28:13 -050098#ifndef HEXDUMP_COLS
99#define HEXDUMP_COLS 16
100#endif
101
Chris Austen99497312015-10-22 13:00:16 -0500102void hexdump(FILE *s, void *mem, size_t len)
Chris Austen0ba649e2015-10-13 12:28:13 -0500103{
104 unsigned int i, j;
Chris Austen120f7322015-10-14 23:27:31 -0500105
Chris Austen0ba649e2015-10-13 12:28:13 -0500106 for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++)
107 {
108 /* print offset */
109 if(i % HEXDUMP_COLS == 0)
110 {
Chris Austen99497312015-10-22 13:00:16 -0500111 fprintf(s,"0x%06x: ", i);
Chris Austen0ba649e2015-10-13 12:28:13 -0500112 }
Chris Austen120f7322015-10-14 23:27:31 -0500113
Chris Austen0ba649e2015-10-13 12:28:13 -0500114 /* print hex data */
115 if(i < len)
116 {
Chris Austen99497312015-10-22 13:00:16 -0500117 fprintf(s,"%02x ", 0xFF & ((char*)mem)[i]);
Chris Austen0ba649e2015-10-13 12:28:13 -0500118 }
119 else /* end of block, just aligning for ASCII dump */
120 {
Chris Austen99497312015-10-22 13:00:16 -0500121 fprintf(s," ");
Chris Austen0ba649e2015-10-13 12:28:13 -0500122 }
Chris Austen120f7322015-10-14 23:27:31 -0500123
Chris Austen0ba649e2015-10-13 12:28:13 -0500124 /* print ASCII dump */
125 if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
126 {
127 for(j = i - (HEXDUMP_COLS - 1); j <= i; j++)
128 {
129 if(j >= len) /* end of block, not really printing */
130 {
Chris Austen99497312015-10-22 13:00:16 -0500131 fputc(' ', s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500132 }
133 else if(isprint(((char*)mem)[j])) /* printable char */
134 {
Chris Austen99497312015-10-22 13:00:16 -0500135 fputc(0xFF & ((char*)mem)[j], s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500136 }
137 else /* other char */
138 {
Chris Austen99497312015-10-22 13:00:16 -0500139 fputc('.',s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500140 }
141 }
Chris Austen99497312015-10-22 13:00:16 -0500142 fputc('\n',s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500143 }
144 }
145}
146
147
vishwabmcba0bd5f2015-09-30 16:50:23 +0530148// Method that gets called by shared libraries to get their command handlers registered
Tom05732372016-09-06 17:21:23 +0530149void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_context_t context,
150 ipmid_callback_t handler, ipmi_cmd_privilege_t priv)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530151{
152 // Pack NetFn and Command in one.
153 auto netfn_and_cmd = std::make_pair(netfn, cmd);
154
155 // Pack Function handler and Data in another.
156 auto handler_and_context = std::make_pair(handler, context);
157
158 // Check if the registration has already been made..
159 auto iter = g_ipmid_router_map.find(netfn_and_cmd);
160 if(iter != g_ipmid_router_map.end())
161 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530162 log<level::ERR>("Duplicate registration",
163 entry("NETFN=0x%X", netfn),
164 entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530165 }
166 else
167 {
168 // This is a fresh registration.. Add it to the map.
169 g_ipmid_router_map.emplace(netfn_and_cmd, handler_and_context);
170 }
171
172 return;
173}
174
175// Looks at the map and calls corresponding handler functions.
176ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
177 ipmi_response_t response, ipmi_data_len_t data_len)
178{
179 // return from the Command handlers.
180 ipmi_ret_t rc = IPMI_CC_INVALID;
181
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500182 // If restricted mode is true and command is not whitelisted, don't
183 // execute the command
184 if(restricted_mode)
185 {
186 if (!std::binary_search(whitelist.cbegin(), whitelist.cend(),
187 std::make_pair(netfn, cmd)))
188 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530189 log<level::ERR>("Net function not whitelisted",
190 entry("NETFN=0x%X", netfn),
191 entry("CMD=0x%X", cmd));
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500192 rc = IPMI_CC_INSUFFICIENT_PRIVILEGE;
193 memcpy(response, &rc, IPMI_CC_LEN);
194 *data_len = IPMI_CC_LEN;
195 return rc;
196 }
197 }
198
vishwabmcba0bd5f2015-09-30 16:50:23 +0530199 // Walk the map that has the registered handlers and invoke the approprite
200 // handlers for matching commands.
201 auto iter = g_ipmid_router_map.find(std::make_pair(netfn, cmd));
202 if(iter == g_ipmid_router_map.end())
203 {
Patrick Venture03f84ba2017-09-20 09:15:33 -0700204 /* By default should only print on failure to find wildcard command. */
205#ifdef __IPMI_DEBUG__
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530206 log<level::ERR>(
207 "No registered handlers for NetFn, trying Wilcard implementation",
208 entry("NET_FUN=0x%X", netfn)
209 entry("CMD=0x%X", IPMI_CMD_WILDCARD));
Patrick Venture03f84ba2017-09-20 09:15:33 -0700210#endif
vishwabmcba0bd5f2015-09-30 16:50:23 +0530211
212 // Now that we did not find any specific [NetFn,Cmd], tuple, check for
213 // NetFn, WildCard command present.
214 iter = g_ipmid_router_map.find(std::make_pair(netfn, IPMI_CMD_WILDCARD));
215 if(iter == g_ipmid_router_map.end())
216 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530217 log<level::ERR>("No Registered handlers for NetFn",
218 entry("NET_FUN=0x%X", netfn),
219 entry("CMD=0x%X", IPMI_CMD_WILDCARD));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530220
221 // Respond with a 0xC1
222 memcpy(response, &rc, IPMI_CC_LEN);
223 *data_len = IPMI_CC_LEN;
224 return rc;
225 }
226 }
227
228#ifdef __IPMI_DEBUG__
229 // We have either a perfect match -OR- a wild card atleast,
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530230 log<level::ERR>("Calling Net function",
231 entry("NET_FUN=0x%X", netfn)
232 entry("CMD=0x%X", cmd));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530233#endif
234
235 // Extract the map data onto appropriate containers
236 auto handler_and_context = iter->second;
237
238 // Creating a pointer type casted to char* to make sure we advance 1 byte
239 // when we advance pointer to next's address. advancing void * would not
240 // make sense.
241 char *respo = &((char *)response)[IPMI_CC_LEN];
242
Richard Marian Thomaiyarebc886f2018-06-06 14:33:59 +0530243 try
244 {
245 // Response message from the plugin goes into a byte post the base
246 // response
247 rc = (handler_and_context.first) (netfn, cmd, request, respo,
248 data_len, handler_and_context.second);
249 }
250 // IPMI command handlers can throw unhandled exceptions, catch those
251 // and return sane error code.
252 catch (const std::exception &e)
253 {
254 log<level::ERR>(e.what(), entry("NET_FUN=0x%X", netfn),
255 entry("CMD=0x%X", cmd));
256 rc = IPMI_CC_UNSPECIFIED_ERROR;
257 *data_len = 0;
258 // fall through
259 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530260 // Now copy the return code that we got from handler and pack it in first
261 // byte.
262 memcpy(response, &rc, IPMI_CC_LEN);
Chris Austen120f7322015-10-14 23:27:31 -0500263
vishwabmcba0bd5f2015-09-30 16:50:23 +0530264 // Data length is now actual data + completion code.
265 *data_len = *data_len + IPMI_CC_LEN;
266
267 return rc;
268}
269
vishwabmcba0bd5f2015-09-30 16:50:23 +0530270
vishwabmcba0bd5f2015-09-30 16:50:23 +0530271
vishwabmcba0bd5f2015-09-30 16:50:23 +0530272
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800273static 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 +0530274
Chris Austen0ba649e2015-10-13 12:28:13 -0500275 sd_bus_error error = SD_BUS_ERROR_NULL;
276 sd_bus_message *reply = NULL, *m=NULL;
Jeremy Kerre41081f2015-10-27 12:11:36 +0800277 const char *dest, *path;
Chris Austen0ba649e2015-10-13 12:28:13 -0500278 int r, pty;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530279
Jeremy Kerre41081f2015-10-27 12:11:36 +0800280 dest = sd_bus_message_get_sender(req);
281 path = sd_bus_message_get_path(req);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530282
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530283 r = sd_bus_message_new_method_call(bus,&m,dest,path,
284 DBUS_INTF,
285 "sendMessage");
Chris Austen0ba649e2015-10-13 12:28:13 -0500286 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530287 log<level::ERR>("Failed to add the method object",
288 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500289 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530290 }
291
vishwabmcba0bd5f2015-09-30 16:50:23 +0530292
Chris Austenabfb5e82015-10-13 12:29:24 -0500293 // Responses in IPMI require a bit set. So there ya go...
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800294 netfn |= 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530295
Chris Austen0ba649e2015-10-13 12:28:13 -0500296
297 // Add the bytes needed for the methods to be called
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800298 r = sd_bus_message_append(m, "yyyyy", seq, netfn, lun, cmd, cc);
Chris Austen0ba649e2015-10-13 12:28:13 -0500299 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530300 log<level::ERR>("Failed add the netfn and others",
301 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600302 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500303 }
Chris Austen120f7322015-10-14 23:27:31 -0500304
Chris Austen0ba649e2015-10-13 12:28:13 -0500305 r = sd_bus_message_append_array(m, 'y', buf, len);
306 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530307 log<level::ERR>("Failed to add the string of response bytes",
308 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600309 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500310 }
311
312
313
314 // Call the IPMI responder on the bus so the message can be sent to the CEC
315 r = sd_bus_call(bus, m, 0, &error, &reply);
316 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530317 log<level::ERR>("Failed to call the method",
318 entry("DEST=%s", dest),
319 entry("PATH=%s", path),
320 entry("ERRNO=0x%X", -r));
Chris Austen169395e2015-12-02 20:56:15 -0600321 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500322 }
323
324 r = sd_bus_message_read(reply, "x", &pty);
Chris Austen0ba649e2015-10-13 12:28:13 -0500325 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530326 log<level::ERR>("Failed to get a reply from the method",
327 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500328 }
329
Chris Austen169395e2015-12-02 20:56:15 -0600330final:
Chris Austen0ba649e2015-10-13 12:28:13 -0500331 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600332 m = sd_bus_message_unref(m);
333 reply = sd_bus_message_unref(reply);
Chris Austen0ba649e2015-10-13 12:28:13 -0500334
Chris Austen0ba649e2015-10-13 12:28:13 -0500335 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Chris Austen0ba649e2015-10-13 12:28:13 -0500336}
337
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500338void cache_restricted_mode()
339{
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500340 restricted_mode = false;
341 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
342 using namespace internal;
343 using namespace internal::cache;
344 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
345 const auto& restrictionModeSetting =
Deepak Kodihallie6027092017-08-27 08:13:37 -0500346 objects->map.at(restrictionModeIntf).front();
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500347 auto method = dbus.new_method_call(
348 objects->service(restrictionModeSetting,
349 restrictionModeIntf).c_str(),
350 restrictionModeSetting.c_str(),
351 "org.freedesktop.DBus.Properties",
352 "Get");
353 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>());
366 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
372static int handle_restricted_mode_change(sd_bus_message *m, void *user_data,
373 sd_bus_error *ret_error)
374{
375 cache_restricted_mode();
376 return 0;
377}
378
Chris Austen0ba649e2015-10-13 12:28:13 -0500379static int handle_ipmi_command(sd_bus_message *m, void *user_data, sd_bus_error
380 *ret_error) {
381 int r = 0;
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800382 unsigned char sequence, netfn, lun, cmd;
Chris Austen0ba649e2015-10-13 12:28:13 -0500383 const void *request;
384 size_t sz;
385 size_t resplen =MAX_IPMI_BUFFER;
386 unsigned char response[MAX_IPMI_BUFFER];
387
Chris Austen0ba649e2015-10-13 12:28:13 -0500388 memset(response, 0, MAX_IPMI_BUFFER);
389
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800390 r = sd_bus_message_read(m, "yyyy", &sequence, &netfn, &lun, &cmd);
Chris Austen0ba649e2015-10-13 12:28:13 -0500391 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530392 log<level::ERR>("Failed to parse signal message",
393 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500394 return -1;
395 }
396
397 r = sd_bus_message_read_array(m, 'y', &request, &sz );
398 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530399 log<level::ERR>("Failed to parse signal message",
400 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500401 return -1;
402 }
403
Chris Austen99497312015-10-22 13:00:16 -0500404 fprintf(ipmiio, "IPMI Incoming: Seq 0x%02x, NetFn 0x%02x, CMD: 0x%02x \n", sequence, netfn, cmd);
405 hexdump(ipmiio, (void*)request, sz);
Chris Austen0ba649e2015-10-13 12:28:13 -0500406
Chris Austen120f7322015-10-14 23:27:31 -0500407 // Allow the length field to be used for both input and output of the
Chris Austen0ba649e2015-10-13 12:28:13 -0500408 // ipmi call
409 resplen = sz;
410
Chris Austen120f7322015-10-14 23:27:31 -0500411 // Now that we have parsed the entire byte array from the caller
vishwabmcba0bd5f2015-09-30 16:50:23 +0530412 // we can call the ipmi router to do the work...
Chris Austen0ba649e2015-10-13 12:28:13 -0500413 r = ipmi_netfn_router(netfn, cmd, (void *)request, (void *)response, &resplen);
414 if(r != 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530415 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530416#ifdef __IPMI_DEBUG__
417 log<level::ERR>("ERROR in handling NetFn",
418 entry("ERRNO=0x%X", -r),
419 entry("NET_FUN=0x%X", netfn),
420 entry("CMD=0x%X", cmd));
421#endif
Ratan Guptae0cc8552018-01-22 14:23:04 +0530422 resplen = 0;
423 }
424 else
425 {
426 resplen = resplen - 1; // first byte is for return code.
vishwabmcba0bd5f2015-09-30 16:50:23 +0530427 }
428
Chris Austen99497312015-10-22 13:00:16 -0500429 fprintf(ipmiio, "IPMI Response:\n");
430 hexdump(ipmiio, (void*)response, resplen);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530431
Chris Austen0ba649e2015-10-13 12:28:13 -0500432 // Send the response buffer from the ipmi command
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800433 r = send_ipmi_message(m, sequence, netfn, lun, cmd, response[0],
Ratan Guptae0cc8552018-01-22 14:23:04 +0530434 ((unsigned char *)response) + 1, resplen);
Chris Austen0ba649e2015-10-13 12:28:13 -0500435 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530436 log<level::ERR>("Failed to send the response message");
Chris Austen0ba649e2015-10-13 12:28:13 -0500437 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530438 }
439
vishwabmcba0bd5f2015-09-30 16:50:23 +0530440
Chris Austen0ba649e2015-10-13 12:28:13 -0500441 return 0;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530442}
443
Chris Austen0ba649e2015-10-13 12:28:13 -0500444
vishwabmcba0bd5f2015-09-30 16:50:23 +0530445//----------------------------------------------------------------------
446// handler_select
447// Select all the files ending with with .so. in the given diretcory
448// @d: dirent structure containing the file name
449//----------------------------------------------------------------------
450int handler_select(const struct dirent *entry)
451{
452 // To hold ".so" from entry->d_name;
453 char dname_copy[4] = {0};
454
455 // We want to avoid checking for everything and isolate to the ones having
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500456 // .so.* or .so in them.
457 // Check for versioned libraries .so.*
458 if(strstr(entry->d_name, IPMI_PLUGIN_SONAME_EXTN))
459 {
460 return 1;
461 }
462 // Check for non versioned libraries .so
463 else if(strstr(entry->d_name, IPMI_PLUGIN_EXTN))
vishwabmcba0bd5f2015-09-30 16:50:23 +0530464 {
465 // It is possible that .so could be anywhere in the string but unlikely
Chris Austen120f7322015-10-14 23:27:31 -0500466 // But being careful here. Get the base address of the string, move
vishwabmcba0bd5f2015-09-30 16:50:23 +0530467 // until end and come back 3 steps and that gets what we need.
468 strcpy(dname_copy, (entry->d_name + strlen(entry->d_name)-strlen(IPMI_PLUGIN_EXTN)));
469 if(strcmp(dname_copy, IPMI_PLUGIN_EXTN) == 0)
470 {
471 return 1;
472 }
473 }
474 return 0;
475}
476
477// 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 -0500478// register a callback handler
vishwabmcba0bd5f2015-09-30 16:50:23 +0530479void ipmi_register_callback_handlers(const char* ipmi_lib_path)
480{
481 // For walking the ipmi_lib_path
482 struct dirent **handler_list;
483 int num_handlers = 0;
484
485 // This is used to check and abort if someone tries to register a bad one.
486 void *lib_handler = NULL;
487
488 if(ipmi_lib_path == NULL)
489 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530490 log<level::ERR>("No handlers to be registered for ipmi.. Aborting");
vishwabmcba0bd5f2015-09-30 16:50:23 +0530491 assert(0);
492 }
493 else
494 {
495 // 1: Open ipmi_lib_path. Its usually "/usr/lib/phosphor-host-ipmid"
496 // 2: Scan the directory for the files that end with .so
Chris Austen120f7322015-10-14 23:27:31 -0500497 // 3: For each one of them, just do a 'dlopen' so that they register
vishwabmcba0bd5f2015-09-30 16:50:23 +0530498 // the handlers for callback routines.
499
500 std::string handler_fqdn = ipmi_lib_path;
Chris Austen120f7322015-10-14 23:27:31 -0500501
vishwabmcba0bd5f2015-09-30 16:50:23 +0530502 // Append a "/" since we need to add the name of the .so. If there is
503 // already a .so, adding one more is not any harm.
504 handler_fqdn += "/";
505
506 num_handlers = scandir(ipmi_lib_path, &handler_list, handler_select, alphasort);
Nan Li36c0cb62016-03-31 11:16:08 +0800507 if (num_handlers < 0)
508 return;
Jeremy Kerr5e8f85e2015-10-27 13:43:54 +0800509
vishwabmcba0bd5f2015-09-30 16:50:23 +0530510 while(num_handlers--)
511 {
Chris Austen54030262015-10-13 12:30:46 -0500512 handler_fqdn = ipmi_lib_path;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530513 handler_fqdn += handler_list[num_handlers]->d_name;
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530514#ifdef __IPMI_DEBUG__
515 log<level::DEBUG>("Registering handler",
516 entry("HANDLER=%s", handler_fqdn.c_str()));
517#endif
Chris Austen54030262015-10-13 12:30:46 -0500518
vishwabmcba0bd5f2015-09-30 16:50:23 +0530519 lib_handler = dlopen(handler_fqdn.c_str(), RTLD_NOW);
Nan Li36c0cb62016-03-31 11:16:08 +0800520
vishwabmcba0bd5f2015-09-30 16:50:23 +0530521 if(lib_handler == NULL)
522 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530523 log<level::ERR>("ERROR opening",
524 entry("HANDLER=%s", handler_fqdn.c_str()),
525 entry("ERROR=%s", dlerror()));
vishwabmcba0bd5f2015-09-30 16:50:23 +0530526 }
527 // Wipe the memory allocated for this particular entry.
528 free(handler_list[num_handlers]);
529 }
Nan Li36c0cb62016-03-31 11:16:08 +0800530
vishwabmcba0bd5f2015-09-30 16:50:23 +0530531 // Done with all registration.
532 free(handler_list);
533 }
534
535 // TODO : What to be done on the memory that is given by dlopen ?.
536 return;
537}
538
Chris Austen30195fa2015-11-13 14:39:19 -0600539sd_bus *ipmid_get_sd_bus_connection(void) {
540 return bus;
541}
542
Andrew Geissler93c679b2017-04-02 10:06:43 -0500543sd_event *ipmid_get_sd_event_connection(void) {
544 return events;
545}
546
vishwab9f559a2016-01-13 01:53:08 -0600547sd_bus_slot *ipmid_get_sd_bus_slot(void) {
548 return ipmid_slot;
549}
550
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530551// Calls host command manager to do the right thing for the command
552void ipmid_send_cmd_to_host(CommandHandler&& cmd) {
553 return cmdManager->execute(std::move(cmd));
554}
555
556cmdManagerPtr& ipmid_get_host_cmd_manager() {
557 return cmdManager;
558}
559
560sdbusPtr& ipmid_get_sdbus_plus_handler() {
561 return sdbusp;
562}
563
vishwabmcba0bd5f2015-09-30 16:50:23 +0530564int main(int argc, char *argv[])
565{
Chris Austen0ba649e2015-10-13 12:28:13 -0500566 int r;
Chris Austen99497312015-10-22 13:00:16 -0500567 unsigned long tvalue;
568 int c;
569
570
571
572 // This file and subsequient switch is for turning on levels
573 // of trace
574 ipmicmddetails = ipmiio = ipmidbus = fopen("/dev/null", "w");
575
576 while ((c = getopt (argc, argv, "h:d:")) != -1)
577 switch (c) {
578 case 'd':
579 tvalue = strtoul(optarg, NULL, 16);
580 if (1&tvalue) {
581 ipmiio = stdout;
582 }
583 if (2&tvalue) {
584 ipmidbus = stdout;
585 }
586 if (4&tvalue) {
587 ipmicmddetails = stdout;
588 }
589 break;
590 case 'h':
591 case '?':
592 print_usage();
593 return 1;
594 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500595
596
Chris Austen0ba649e2015-10-13 12:28:13 -0500597 /* Connect to system bus */
598 r = sd_bus_open_system(&bus);
599 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530600 log<level::ERR>("Failed to connect to system bus",
601 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500602 goto finish;
603 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530604
Andrew Geissler93c679b2017-04-02 10:06:43 -0500605 /* Get an sd event handler */
606 r = sd_event_default(&events);
607 if (r < 0)
608 {
609 log<level::ERR>("Failure to create sd_event handler",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530610 entry("ERRNO=0x%X", -r));
Andrew Geissler93c679b2017-04-02 10:06:43 -0500611 goto finish;
612 }
613
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530614 // Now create the Host Bound Command manager. Need sdbusplus
615 // to use the generated bindings
616 sdbusp = std::make_unique<sdbusplus::bus::bus>(bus);
617 cmdManager = std::make_unique<phosphor::host::command::Manager>(
618 *sdbusp, events);
Andrew Geissler93c679b2017-04-02 10:06:43 -0500619
Peter Hanson4a589852017-06-07 17:40:45 -0700620 // Activate OemRouter.
621 oem::mutableRouter()->activate();
622
Chris Austen30195fa2015-11-13 14:39:19 -0600623 // Register all the handlers that provider implementation to IPMI commands.
624 ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
625
vishwa36993272015-11-20 12:43:49 -0600626 // Watch for BT messages
vishwab9f559a2016-01-13 01:53:08 -0600627 r = sd_bus_add_match(bus, &ipmid_slot, FILTER, handle_ipmi_command, NULL);
Chris Austen0ba649e2015-10-13 12:28:13 -0500628 if (r < 0) {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530629 log<level::ERR>("Failed: sd_bus_add_match",
630 entry("FILTER=%s", FILTER),
631 entry("ERRNO=0x%X", -r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500632 goto finish;
633 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530634
Andrew Geissler93c679b2017-04-02 10:06:43 -0500635 // Attach the bus to sd_event to service user requests
636 sd_bus_attach_event(bus, events, SD_EVENT_PRIORITY_NORMAL);
637
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500638 {
639 using namespace internal;
640 using namespace internal::cache;
641 sdbusplus::bus::bus dbus{bus};
642 objects = std::make_unique<settings::Objects>(
643 dbus,
644 std::vector<settings::Interface>({restrictionModeIntf}));
645 // Initialize restricted mode
646 cache_restricted_mode();
647 // Wait for changes on Restricted mode
648 sdbusplus::bus::match_t restrictedModeMatch(
649 dbus,
650 sdbusRule::propertiesChanged(
Deepak Kodihallie6027092017-08-27 08:13:37 -0500651 objects->map.at(restrictionModeIntf).front(),
652 restrictionModeIntf),
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500653 handle_restricted_mode_change);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530654
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500655 for (;;) {
656 /* Process requests */
657 r = sd_event_run(events, (uint64_t)-1);
658 if (r < 0)
659 {
660 log<level::ERR>("Failure in processing request",
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530661 entry("ERRNO=0x%X", -r));
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500662 goto finish;
663 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500664 }
665 }
666
667finish:
Andrew Geissler93c679b2017-04-02 10:06:43 -0500668 sd_event_unref(events);
669 sd_bus_detach_event(bus);
vishwab9f559a2016-01-13 01:53:08 -0600670 sd_bus_slot_unref(ipmid_slot);
Chris Austen0ba649e2015-10-13 12:28:13 -0500671 sd_bus_unref(bus);
672 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
673
vishwabmcba0bd5f2015-09-30 16:50:23 +0530674}