blob: 7583bb8146f12533051e73bd0ff2af93d30a4769 [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>
Patrick Williams53a360e2016-08-12 22:01:02 -050013#include "ipmid.hpp"
Chris Austen0ba649e2015-10-13 12:28:13 -050014#include <sys/time.h>
15#include <errno.h>
Brad Bishop35518682016-07-22 08:35:41 -040016#include <mapper.h>
Chris Austen0012e9b2015-10-22 01:37:46 -050017#include "sensorhandler.h"
Tom Joseph9a61b4f2016-07-11 06:56:11 -050018#include <vector>
19#include <algorithm>
20#include <iterator>
Patrick Williams4b9efaa2016-08-12 21:59:51 -050021#include <ipmiwhitelist.hpp>
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050022#include <sdbusplus/bus.hpp>
23#include <sdbusplus/bus/match.hpp>
24#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
25#include "sensorhandler.h"
26#include "ipmid.hpp"
27#include "settings.hpp"
Chris Austen0ba649e2015-10-13 12:28:13 -050028
Andrew Geissler93c679b2017-04-02 10:06:43 -050029using namespace phosphor::logging;
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050030namespace sdbusRule = sdbusplus::bus::match::rules;
Andrew Geissler93c679b2017-04-02 10:06:43 -050031
Chris Austen0ba649e2015-10-13 12:28:13 -050032sd_bus *bus = NULL;
vishwab9f559a2016-01-13 01:53:08 -060033sd_bus_slot *ipmid_slot = NULL;
Andrew Geissler93c679b2017-04-02 10:06:43 -050034sd_event *events = nullptr;
Chris Austen30195fa2015-11-13 14:39:19 -060035
Tom Joseph9a61b4f2016-07-11 06:56:11 -050036// Initialise restricted mode to true
37bool restricted_mode = true;
38
Chris Austen41a4b312015-10-25 03:45:42 -050039FILE *ipmiio, *ipmidbus, *ipmicmddetails;
vishwabmcba0bd5f2015-09-30 16:50:23 +053040
Chris Austen99497312015-10-22 13:00:16 -050041void print_usage(void) {
42 fprintf(stderr, "Options: [-d mask]\n");
43 fprintf(stderr, " mask : 0x01 - Print ipmi packets\n");
44 fprintf(stderr, " mask : 0x02 - Print DBUS operations\n");
45 fprintf(stderr, " mask : 0x04 - Print ipmi command details\n");
46 fprintf(stderr, " mask : 0xFF - Print all trace\n");
47}
48
Jeremy Kerre41081f2015-10-27 12:11:36 +080049const char * DBUS_INTF = "org.openbmc.HostIpmi";
vishwabmcba0bd5f2015-09-30 16:50:23 +053050
Jeremy Kerre41081f2015-10-27 12:11:36 +080051const char * FILTER = "type='signal',interface='org.openbmc.HostIpmi',member='ReceivedMessage'";
Chris Austen0ba649e2015-10-13 12:28:13 -050052
vishwabmcba0bd5f2015-09-30 16:50:23 +053053typedef std::pair<ipmi_netfn_t, ipmi_cmd_t> ipmi_fn_cmd_t;
54typedef std::pair<ipmid_callback_t, ipmi_context_t> ipmi_fn_context_t;
55
56// Global data structure that contains the IPMI command handler's registrations.
57std::map<ipmi_fn_cmd_t, ipmi_fn_context_t> g_ipmid_router_map;
58
Nan Li36c0cb62016-03-31 11:16:08 +080059// IPMI Spec, shared Reservation ID.
60unsigned short g_sel_reserve = 0xFFFF;
61
62unsigned short get_sel_reserve_id(void)
63{
64 return g_sel_reserve;
65}
Chris Austen0ba649e2015-10-13 12:28:13 -050066
Deepak Kodihalli84b3a082017-07-21 23:44:44 -050067namespace internal
68{
69
70constexpr auto restrictionModeIntf =
71 "xyz.openbmc_project.Control.Security.RestrictionMode";
72
73namespace cache
74{
75
76std::unique_ptr<settings::Objects> objects = nullptr;
77
78} // namespace cache
79} // namespace internal
80
Chris Austen0ba649e2015-10-13 12:28:13 -050081#ifndef HEXDUMP_COLS
82#define HEXDUMP_COLS 16
83#endif
84
Chris Austen99497312015-10-22 13:00:16 -050085void hexdump(FILE *s, void *mem, size_t len)
Chris Austen0ba649e2015-10-13 12:28:13 -050086{
87 unsigned int i, j;
Chris Austen120f7322015-10-14 23:27:31 -050088
Chris Austen0ba649e2015-10-13 12:28:13 -050089 for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++)
90 {
91 /* print offset */
92 if(i % HEXDUMP_COLS == 0)
93 {
Chris Austen99497312015-10-22 13:00:16 -050094 fprintf(s,"0x%06x: ", i);
Chris Austen0ba649e2015-10-13 12:28:13 -050095 }
Chris Austen120f7322015-10-14 23:27:31 -050096
Chris Austen0ba649e2015-10-13 12:28:13 -050097 /* print hex data */
98 if(i < len)
99 {
Chris Austen99497312015-10-22 13:00:16 -0500100 fprintf(s,"%02x ", 0xFF & ((char*)mem)[i]);
Chris Austen0ba649e2015-10-13 12:28:13 -0500101 }
102 else /* end of block, just aligning for ASCII dump */
103 {
Chris Austen99497312015-10-22 13:00:16 -0500104 fprintf(s," ");
Chris Austen0ba649e2015-10-13 12:28:13 -0500105 }
Chris Austen120f7322015-10-14 23:27:31 -0500106
Chris Austen0ba649e2015-10-13 12:28:13 -0500107 /* print ASCII dump */
108 if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
109 {
110 for(j = i - (HEXDUMP_COLS - 1); j <= i; j++)
111 {
112 if(j >= len) /* end of block, not really printing */
113 {
Chris Austen99497312015-10-22 13:00:16 -0500114 fputc(' ', s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500115 }
116 else if(isprint(((char*)mem)[j])) /* printable char */
117 {
Chris Austen99497312015-10-22 13:00:16 -0500118 fputc(0xFF & ((char*)mem)[j], s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500119 }
120 else /* other char */
121 {
Chris Austen99497312015-10-22 13:00:16 -0500122 fputc('.',s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500123 }
124 }
Chris Austen99497312015-10-22 13:00:16 -0500125 fputc('\n',s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500126 }
127 }
128}
129
130
vishwabmcba0bd5f2015-09-30 16:50:23 +0530131// Method that gets called by shared libraries to get their command handlers registered
Tom05732372016-09-06 17:21:23 +0530132void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_context_t context,
133 ipmid_callback_t handler, ipmi_cmd_privilege_t priv)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530134{
135 // Pack NetFn and Command in one.
136 auto netfn_and_cmd = std::make_pair(netfn, cmd);
137
138 // Pack Function handler and Data in another.
139 auto handler_and_context = std::make_pair(handler, context);
140
141 // Check if the registration has already been made..
142 auto iter = g_ipmid_router_map.find(netfn_and_cmd);
143 if(iter != g_ipmid_router_map.end())
144 {
145 fprintf(stderr,"ERROR : Duplicate registration for NetFn [0x%X], Cmd:[0x%X]\n",netfn, cmd);
146 }
147 else
148 {
149 // This is a fresh registration.. Add it to the map.
150 g_ipmid_router_map.emplace(netfn_and_cmd, handler_and_context);
151 }
152
153 return;
154}
155
156// Looks at the map and calls corresponding handler functions.
157ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
158 ipmi_response_t response, ipmi_data_len_t data_len)
159{
160 // return from the Command handlers.
161 ipmi_ret_t rc = IPMI_CC_INVALID;
162
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500163 // If restricted mode is true and command is not whitelisted, don't
164 // execute the command
165 if(restricted_mode)
166 {
167 if (!std::binary_search(whitelist.cbegin(), whitelist.cend(),
168 std::make_pair(netfn, cmd)))
169 {
170 printf("Net function:[0x%X], Command:[0x%X] is not whitelisted\n",
171 netfn, cmd);
172 rc = IPMI_CC_INSUFFICIENT_PRIVILEGE;
173 memcpy(response, &rc, IPMI_CC_LEN);
174 *data_len = IPMI_CC_LEN;
175 return rc;
176 }
177 }
178
vishwabmcba0bd5f2015-09-30 16:50:23 +0530179 // Walk the map that has the registered handlers and invoke the approprite
180 // handlers for matching commands.
181 auto iter = g_ipmid_router_map.find(std::make_pair(netfn, cmd));
182 if(iter == g_ipmid_router_map.end())
183 {
Chris Austen99497312015-10-22 13:00:16 -0500184 fprintf(stderr, "No registered handlers for NetFn:[0x%X], Cmd:[0x%X]"
vishwabmcba0bd5f2015-09-30 16:50:23 +0530185 " trying Wilcard implementation \n",netfn, cmd);
186
187 // Now that we did not find any specific [NetFn,Cmd], tuple, check for
188 // NetFn, WildCard command present.
189 iter = g_ipmid_router_map.find(std::make_pair(netfn, IPMI_CMD_WILDCARD));
190 if(iter == g_ipmid_router_map.end())
191 {
Chris Austen99497312015-10-22 13:00:16 -0500192 fprintf(stderr, "No Registered handlers for NetFn:[0x%X],Cmd:[0x%X]\n",netfn, IPMI_CMD_WILDCARD);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530193
194 // Respond with a 0xC1
195 memcpy(response, &rc, IPMI_CC_LEN);
196 *data_len = IPMI_CC_LEN;
197 return rc;
198 }
199 }
200
201#ifdef __IPMI_DEBUG__
202 // We have either a perfect match -OR- a wild card atleast,
203 printf("Calling Net function:[0x%X], Command:[0x%X]\n", netfn, cmd);
204#endif
205
206 // Extract the map data onto appropriate containers
207 auto handler_and_context = iter->second;
208
209 // Creating a pointer type casted to char* to make sure we advance 1 byte
210 // when we advance pointer to next's address. advancing void * would not
211 // make sense.
212 char *respo = &((char *)response)[IPMI_CC_LEN];
213
214 // Response message from the plugin goes into a byte post the base response
215 rc = (handler_and_context.first) (netfn, cmd, request, respo,
216 data_len, handler_and_context.second);
Chris Austen120f7322015-10-14 23:27:31 -0500217
vishwabmcba0bd5f2015-09-30 16:50:23 +0530218 // Now copy the return code that we got from handler and pack it in first
219 // byte.
220 memcpy(response, &rc, IPMI_CC_LEN);
Chris Austen120f7322015-10-14 23:27:31 -0500221
vishwabmcba0bd5f2015-09-30 16:50:23 +0530222 // Data length is now actual data + completion code.
223 *data_len = *data_len + IPMI_CC_LEN;
224
225 return rc;
226}
227
vishwabmcba0bd5f2015-09-30 16:50:23 +0530228
vishwabmcba0bd5f2015-09-30 16:50:23 +0530229
vishwabmcba0bd5f2015-09-30 16:50:23 +0530230
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800231static 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 +0530232
Chris Austen0ba649e2015-10-13 12:28:13 -0500233 sd_bus_error error = SD_BUS_ERROR_NULL;
234 sd_bus_message *reply = NULL, *m=NULL;
Jeremy Kerre41081f2015-10-27 12:11:36 +0800235 const char *dest, *path;
Chris Austen0ba649e2015-10-13 12:28:13 -0500236 int r, pty;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530237
Jeremy Kerre41081f2015-10-27 12:11:36 +0800238 dest = sd_bus_message_get_sender(req);
239 path = sd_bus_message_get_path(req);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530240
Jeremy Kerre41081f2015-10-27 12:11:36 +0800241 r = sd_bus_message_new_method_call(bus,&m,dest,path,DBUS_INTF,"sendMessage");
Chris Austen0ba649e2015-10-13 12:28:13 -0500242 if (r < 0) {
243 fprintf(stderr, "Failed to add the method object: %s\n", strerror(-r));
244 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530245 }
246
vishwabmcba0bd5f2015-09-30 16:50:23 +0530247
Chris Austenabfb5e82015-10-13 12:29:24 -0500248 // Responses in IPMI require a bit set. So there ya go...
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800249 netfn |= 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530250
Chris Austen0ba649e2015-10-13 12:28:13 -0500251
252 // Add the bytes needed for the methods to be called
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800253 r = sd_bus_message_append(m, "yyyyy", seq, netfn, lun, cmd, cc);
Chris Austen0ba649e2015-10-13 12:28:13 -0500254 if (r < 0) {
255 fprintf(stderr, "Failed add the netfn and others : %s\n", strerror(-r));
Chris Austen169395e2015-12-02 20:56:15 -0600256 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500257 }
Chris Austen120f7322015-10-14 23:27:31 -0500258
Chris Austen0ba649e2015-10-13 12:28:13 -0500259 r = sd_bus_message_append_array(m, 'y', buf, len);
260 if (r < 0) {
261 fprintf(stderr, "Failed to add the string of response bytes: %s\n", strerror(-r));
Chris Austen169395e2015-12-02 20:56:15 -0600262 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500263 }
264
265
266
267 // Call the IPMI responder on the bus so the message can be sent to the CEC
268 r = sd_bus_call(bus, m, 0, &error, &reply);
269 if (r < 0) {
Chris Austen169395e2015-12-02 20:56:15 -0600270 fprintf(stderr, "Failed to call the method: %s\n", strerror(-r));
Chris Austen6bd23962015-12-07 21:31:48 -0600271 fprintf(stderr, "Dest: %s, Path: %s\n", dest, path);
Chris Austen169395e2015-12-02 20:56:15 -0600272 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500273 }
274
275 r = sd_bus_message_read(reply, "x", &pty);
Chris Austen0ba649e2015-10-13 12:28:13 -0500276 if (r < 0) {
277 fprintf(stderr, "Failed to get a rc from the method: %s\n", strerror(-r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500278 }
279
Chris Austen169395e2015-12-02 20:56:15 -0600280final:
Chris Austen0ba649e2015-10-13 12:28:13 -0500281 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600282 m = sd_bus_message_unref(m);
283 reply = sd_bus_message_unref(reply);
Chris Austen0ba649e2015-10-13 12:28:13 -0500284
Chris Austen0ba649e2015-10-13 12:28:13 -0500285 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Chris Austen0ba649e2015-10-13 12:28:13 -0500286}
287
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500288void cache_restricted_mode()
289{
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500290 restricted_mode = false;
291 using namespace sdbusplus::xyz::openbmc_project::Control::Security::server;
292 using namespace internal;
293 using namespace internal::cache;
294 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
295 const auto& restrictionModeSetting =
296 objects->map.at(restrictionModeIntf);
297 auto method = dbus.new_method_call(
298 objects->service(restrictionModeSetting,
299 restrictionModeIntf).c_str(),
300 restrictionModeSetting.c_str(),
301 "org.freedesktop.DBus.Properties",
302 "Get");
303 method.append(restrictionModeIntf, "RestrictionMode");
304 auto resp = dbus.call(method);
305 if (resp.is_method_error())
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500306 {
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500307 log<level::ERR>("Error in RestrictionMode Get");
308 // Fail-safe to true.
309 restricted_mode = true;
310 return;
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500311 }
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500312 sdbusplus::message::variant<std::string> result;
313 resp.read(result);
314 auto restrictionMode =
315 RestrictionMode::convertModesFromString(result.get<std::string>());
316 if(RestrictionMode::Modes::Whitelist == restrictionMode)
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500317 {
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500318 restricted_mode = true;
319 }
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500320}
321
322static int handle_restricted_mode_change(sd_bus_message *m, void *user_data,
323 sd_bus_error *ret_error)
324{
325 cache_restricted_mode();
326 return 0;
327}
328
Chris Austen0ba649e2015-10-13 12:28:13 -0500329static int handle_ipmi_command(sd_bus_message *m, void *user_data, sd_bus_error
330 *ret_error) {
331 int r = 0;
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800332 unsigned char sequence, netfn, lun, cmd;
Chris Austen0ba649e2015-10-13 12:28:13 -0500333 const void *request;
334 size_t sz;
335 size_t resplen =MAX_IPMI_BUFFER;
336 unsigned char response[MAX_IPMI_BUFFER];
337
Chris Austen0ba649e2015-10-13 12:28:13 -0500338 memset(response, 0, MAX_IPMI_BUFFER);
339
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800340 r = sd_bus_message_read(m, "yyyy", &sequence, &netfn, &lun, &cmd);
Chris Austen0ba649e2015-10-13 12:28:13 -0500341 if (r < 0) {
342 fprintf(stderr, "Failed to parse signal message: %s\n", strerror(-r));
343 return -1;
344 }
345
346 r = sd_bus_message_read_array(m, 'y', &request, &sz );
347 if (r < 0) {
348 fprintf(stderr, "Failed to parse signal message: %s\n", strerror(-r));
349 return -1;
350 }
351
Chris Austen99497312015-10-22 13:00:16 -0500352 fprintf(ipmiio, "IPMI Incoming: Seq 0x%02x, NetFn 0x%02x, CMD: 0x%02x \n", sequence, netfn, cmd);
353 hexdump(ipmiio, (void*)request, sz);
Chris Austen0ba649e2015-10-13 12:28:13 -0500354
Chris Austen120f7322015-10-14 23:27:31 -0500355 // Allow the length field to be used for both input and output of the
Chris Austen0ba649e2015-10-13 12:28:13 -0500356 // ipmi call
357 resplen = sz;
358
Chris Austen120f7322015-10-14 23:27:31 -0500359 // Now that we have parsed the entire byte array from the caller
vishwabmcba0bd5f2015-09-30 16:50:23 +0530360 // we can call the ipmi router to do the work...
Chris Austen0ba649e2015-10-13 12:28:13 -0500361 r = ipmi_netfn_router(netfn, cmd, (void *)request, (void *)response, &resplen);
362 if(r != 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530363 {
Chris Austen0ba649e2015-10-13 12:28:13 -0500364 fprintf(stderr,"ERROR:[0x%X] handling NetFn:[0x%X], Cmd:[0x%X]\n",r, netfn, cmd);
Nan Li80be4b92016-05-23 19:30:49 +0800365
tomjose7ec0add2016-06-27 07:59:28 -0500366 if(r < 0) {
Nan Li80be4b92016-05-23 19:30:49 +0800367 response[0] = IPMI_CC_UNSPECIFIED_ERROR;
368 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530369 }
370
Chris Austen99497312015-10-22 13:00:16 -0500371 fprintf(ipmiio, "IPMI Response:\n");
372 hexdump(ipmiio, (void*)response, resplen);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530373
Chris Austen0ba649e2015-10-13 12:28:13 -0500374 // Send the response buffer from the ipmi command
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800375 r = send_ipmi_message(m, sequence, netfn, lun, cmd, response[0],
376 ((unsigned char *)response) + 1, resplen - 1);
Chris Austen0ba649e2015-10-13 12:28:13 -0500377 if (r < 0) {
378 fprintf(stderr, "Failed to send the response message\n");
379 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530380 }
381
vishwabmcba0bd5f2015-09-30 16:50:23 +0530382
Chris Austen0ba649e2015-10-13 12:28:13 -0500383 return 0;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530384}
385
Chris Austen0ba649e2015-10-13 12:28:13 -0500386
vishwabmcba0bd5f2015-09-30 16:50:23 +0530387//----------------------------------------------------------------------
388// handler_select
389// Select all the files ending with with .so. in the given diretcory
390// @d: dirent structure containing the file name
391//----------------------------------------------------------------------
392int handler_select(const struct dirent *entry)
393{
394 // To hold ".so" from entry->d_name;
395 char dname_copy[4] = {0};
396
397 // We want to avoid checking for everything and isolate to the ones having
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500398 // .so.* or .so in them.
399 // Check for versioned libraries .so.*
400 if(strstr(entry->d_name, IPMI_PLUGIN_SONAME_EXTN))
401 {
402 return 1;
403 }
404 // Check for non versioned libraries .so
405 else if(strstr(entry->d_name, IPMI_PLUGIN_EXTN))
vishwabmcba0bd5f2015-09-30 16:50:23 +0530406 {
407 // It is possible that .so could be anywhere in the string but unlikely
Chris Austen120f7322015-10-14 23:27:31 -0500408 // But being careful here. Get the base address of the string, move
vishwabmcba0bd5f2015-09-30 16:50:23 +0530409 // until end and come back 3 steps and that gets what we need.
410 strcpy(dname_copy, (entry->d_name + strlen(entry->d_name)-strlen(IPMI_PLUGIN_EXTN)));
411 if(strcmp(dname_copy, IPMI_PLUGIN_EXTN) == 0)
412 {
413 return 1;
414 }
415 }
416 return 0;
417}
418
419// 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 -0500420// register a callback handler
vishwabmcba0bd5f2015-09-30 16:50:23 +0530421void ipmi_register_callback_handlers(const char* ipmi_lib_path)
422{
423 // For walking the ipmi_lib_path
424 struct dirent **handler_list;
425 int num_handlers = 0;
426
427 // This is used to check and abort if someone tries to register a bad one.
428 void *lib_handler = NULL;
429
430 if(ipmi_lib_path == NULL)
431 {
432 fprintf(stderr,"ERROR; No handlers to be registered for ipmi.. Aborting\n");
433 assert(0);
434 }
435 else
436 {
437 // 1: Open ipmi_lib_path. Its usually "/usr/lib/phosphor-host-ipmid"
438 // 2: Scan the directory for the files that end with .so
Chris Austen120f7322015-10-14 23:27:31 -0500439 // 3: For each one of them, just do a 'dlopen' so that they register
vishwabmcba0bd5f2015-09-30 16:50:23 +0530440 // the handlers for callback routines.
441
442 std::string handler_fqdn = ipmi_lib_path;
Chris Austen120f7322015-10-14 23:27:31 -0500443
vishwabmcba0bd5f2015-09-30 16:50:23 +0530444 // Append a "/" since we need to add the name of the .so. If there is
445 // already a .so, adding one more is not any harm.
446 handler_fqdn += "/";
447
448 num_handlers = scandir(ipmi_lib_path, &handler_list, handler_select, alphasort);
Nan Li36c0cb62016-03-31 11:16:08 +0800449 if (num_handlers < 0)
450 return;
Jeremy Kerr5e8f85e2015-10-27 13:43:54 +0800451
vishwabmcba0bd5f2015-09-30 16:50:23 +0530452 while(num_handlers--)
453 {
Chris Austen54030262015-10-13 12:30:46 -0500454 handler_fqdn = ipmi_lib_path;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530455 handler_fqdn += handler_list[num_handlers]->d_name;
Chris Austen54030262015-10-13 12:30:46 -0500456 printf("Registering handler:[%s]\n",handler_fqdn.c_str());
457
vishwabmcba0bd5f2015-09-30 16:50:23 +0530458 lib_handler = dlopen(handler_fqdn.c_str(), RTLD_NOW);
Nan Li36c0cb62016-03-31 11:16:08 +0800459
vishwabmcba0bd5f2015-09-30 16:50:23 +0530460 if(lib_handler == NULL)
461 {
Chris Austen120f7322015-10-14 23:27:31 -0500462 fprintf(stderr,"ERROR opening [%s]: %s\n",
463 handler_fqdn.c_str(), dlerror());
vishwabmcba0bd5f2015-09-30 16:50:23 +0530464 }
465 // Wipe the memory allocated for this particular entry.
466 free(handler_list[num_handlers]);
467 }
Nan Li36c0cb62016-03-31 11:16:08 +0800468
vishwabmcba0bd5f2015-09-30 16:50:23 +0530469 // Done with all registration.
470 free(handler_list);
471 }
472
473 // TODO : What to be done on the memory that is given by dlopen ?.
474 return;
475}
476
Chris Austen30195fa2015-11-13 14:39:19 -0600477sd_bus *ipmid_get_sd_bus_connection(void) {
478 return bus;
479}
480
Andrew Geissler93c679b2017-04-02 10:06:43 -0500481sd_event *ipmid_get_sd_event_connection(void) {
482 return events;
483}
484
vishwab9f559a2016-01-13 01:53:08 -0600485sd_bus_slot *ipmid_get_sd_bus_slot(void) {
486 return ipmid_slot;
487}
488
vishwabmcba0bd5f2015-09-30 16:50:23 +0530489int main(int argc, char *argv[])
490{
Chris Austen0ba649e2015-10-13 12:28:13 -0500491 int r;
Chris Austen99497312015-10-22 13:00:16 -0500492 unsigned long tvalue;
493 int c;
494
495
496
497 // This file and subsequient switch is for turning on levels
498 // of trace
499 ipmicmddetails = ipmiio = ipmidbus = fopen("/dev/null", "w");
500
501 while ((c = getopt (argc, argv, "h:d:")) != -1)
502 switch (c) {
503 case 'd':
504 tvalue = strtoul(optarg, NULL, 16);
505 if (1&tvalue) {
506 ipmiio = stdout;
507 }
508 if (2&tvalue) {
509 ipmidbus = stdout;
510 }
511 if (4&tvalue) {
512 ipmicmddetails = stdout;
513 }
514 break;
515 case 'h':
516 case '?':
517 print_usage();
518 return 1;
519 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500520
521
Chris Austen0ba649e2015-10-13 12:28:13 -0500522 /* Connect to system bus */
523 r = sd_bus_open_system(&bus);
524 if (r < 0) {
525 fprintf(stderr, "Failed to connect to system bus: %s\n",
526 strerror(-r));
527 goto finish;
528 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530529
Andrew Geissler93c679b2017-04-02 10:06:43 -0500530 /* Get an sd event handler */
531 r = sd_event_default(&events);
532 if (r < 0)
533 {
534 log<level::ERR>("Failure to create sd_event handler",
535 entry("ERROR=%s", strerror(-r)));
536 goto finish;
537 }
538
539
Chris Austen30195fa2015-11-13 14:39:19 -0600540 // Register all the handlers that provider implementation to IPMI commands.
541 ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
542
vishwa36993272015-11-20 12:43:49 -0600543 // Watch for BT messages
vishwab9f559a2016-01-13 01:53:08 -0600544 r = sd_bus_add_match(bus, &ipmid_slot, FILTER, handle_ipmi_command, NULL);
Chris Austen0ba649e2015-10-13 12:28:13 -0500545 if (r < 0) {
546 fprintf(stderr, "Failed: sd_bus_add_match: %s : %s\n", strerror(-r), FILTER);
547 goto finish;
548 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530549
Andrew Geissler93c679b2017-04-02 10:06:43 -0500550 // Attach the bus to sd_event to service user requests
551 sd_bus_attach_event(bus, events, SD_EVENT_PRIORITY_NORMAL);
552
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500553 {
554 using namespace internal;
555 using namespace internal::cache;
556 sdbusplus::bus::bus dbus{bus};
557 objects = std::make_unique<settings::Objects>(
558 dbus,
559 std::vector<settings::Interface>({restrictionModeIntf}));
560 // Initialize restricted mode
561 cache_restricted_mode();
562 // Wait for changes on Restricted mode
563 sdbusplus::bus::match_t restrictedModeMatch(
564 dbus,
565 sdbusRule::propertiesChanged(
566 objects->map.at(restrictionModeIntf), restrictionModeIntf),
567 handle_restricted_mode_change);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530568
Deepak Kodihalli84b3a082017-07-21 23:44:44 -0500569 for (;;) {
570 /* Process requests */
571 r = sd_event_run(events, (uint64_t)-1);
572 if (r < 0)
573 {
574 log<level::ERR>("Failure in processing request",
575 entry("ERROR=%s", strerror(-r)));
576 goto finish;
577 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500578 }
579 }
580
581finish:
Andrew Geissler93c679b2017-04-02 10:06:43 -0500582 sd_event_unref(events);
583 sd_bus_detach_event(bus);
vishwab9f559a2016-01-13 01:53:08 -0600584 sd_bus_slot_unref(ipmid_slot);
Chris Austen0ba649e2015-10-13 12:28:13 -0500585 sd_bus_unref(bus);
586 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
587
vishwabmcba0bd5f2015-09-30 16:50:23 +0530588}