blob: 7848afefa1df39b2b91ec60454dd132e54802b6e [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>
11#include "ipmid.H"
Chris Austen0ba649e2015-10-13 12:28:13 -050012#include <sys/time.h>
13#include <errno.h>
Brad Bishop35518682016-07-22 08:35:41 -040014#include <mapper.h>
Chris Austen0012e9b2015-10-22 01:37:46 -050015#include "sensorhandler.h"
Tom Joseph9a61b4f2016-07-11 06:56:11 -050016#include <vector>
17#include <algorithm>
18#include <iterator>
19#include <ipmiwhitelist.H>
Chris Austen0ba649e2015-10-13 12:28:13 -050020
Chris Austen0ba649e2015-10-13 12:28:13 -050021sd_bus *bus = NULL;
vishwab9f559a2016-01-13 01:53:08 -060022sd_bus_slot *ipmid_slot = NULL;
Chris Austen30195fa2015-11-13 14:39:19 -060023
Tom Joseph9a61b4f2016-07-11 06:56:11 -050024// Initialise restricted mode to true
25bool restricted_mode = true;
26
Chris Austen41a4b312015-10-25 03:45:42 -050027FILE *ipmiio, *ipmidbus, *ipmicmddetails;
vishwabmcba0bd5f2015-09-30 16:50:23 +053028
Chris Austen99497312015-10-22 13:00:16 -050029void print_usage(void) {
30 fprintf(stderr, "Options: [-d mask]\n");
31 fprintf(stderr, " mask : 0x01 - Print ipmi packets\n");
32 fprintf(stderr, " mask : 0x02 - Print DBUS operations\n");
33 fprintf(stderr, " mask : 0x04 - Print ipmi command details\n");
34 fprintf(stderr, " mask : 0xFF - Print all trace\n");
35}
36
Tom Joseph9a61b4f2016-07-11 06:56:11 -050037// Host settings in DBUS
38constexpr char settings_host_bus[] = "org.openbmc.settings.Host";
39constexpr char settings_host_object[] = "/org/openbmc/settings/host0";
40constexpr char settings_host_intf[] = "org.freedesktop.DBus.Properties";
41
Jeremy Kerre41081f2015-10-27 12:11:36 +080042const char * DBUS_INTF = "org.openbmc.HostIpmi";
vishwabmcba0bd5f2015-09-30 16:50:23 +053043
Jeremy Kerre41081f2015-10-27 12:11:36 +080044const char * FILTER = "type='signal',interface='org.openbmc.HostIpmi',member='ReceivedMessage'";
Tom Joseph9a61b4f2016-07-11 06:56:11 -050045constexpr char RESTRICTED_MODE_FILTER[] = "type='signal',interface='org.freedesktop.DBus.Properties',path='/org/openbmc/settings/host0'";
Chris Austen0ba649e2015-10-13 12:28:13 -050046
vishwabmcba0bd5f2015-09-30 16:50:23 +053047typedef std::pair<ipmi_netfn_t, ipmi_cmd_t> ipmi_fn_cmd_t;
48typedef std::pair<ipmid_callback_t, ipmi_context_t> ipmi_fn_context_t;
49
50// Global data structure that contains the IPMI command handler's registrations.
51std::map<ipmi_fn_cmd_t, ipmi_fn_context_t> g_ipmid_router_map;
52
Nan Li36c0cb62016-03-31 11:16:08 +080053// IPMI Spec, shared Reservation ID.
54unsigned short g_sel_reserve = 0xFFFF;
55
56unsigned short get_sel_reserve_id(void)
57{
58 return g_sel_reserve;
59}
Chris Austen0ba649e2015-10-13 12:28:13 -050060
Chris Austen0ba649e2015-10-13 12:28:13 -050061#ifndef HEXDUMP_COLS
62#define HEXDUMP_COLS 16
63#endif
64
Chris Austen99497312015-10-22 13:00:16 -050065void hexdump(FILE *s, void *mem, size_t len)
Chris Austen0ba649e2015-10-13 12:28:13 -050066{
67 unsigned int i, j;
Chris Austen120f7322015-10-14 23:27:31 -050068
Chris Austen0ba649e2015-10-13 12:28:13 -050069 for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++)
70 {
71 /* print offset */
72 if(i % HEXDUMP_COLS == 0)
73 {
Chris Austen99497312015-10-22 13:00:16 -050074 fprintf(s,"0x%06x: ", i);
Chris Austen0ba649e2015-10-13 12:28:13 -050075 }
Chris Austen120f7322015-10-14 23:27:31 -050076
Chris Austen0ba649e2015-10-13 12:28:13 -050077 /* print hex data */
78 if(i < len)
79 {
Chris Austen99497312015-10-22 13:00:16 -050080 fprintf(s,"%02x ", 0xFF & ((char*)mem)[i]);
Chris Austen0ba649e2015-10-13 12:28:13 -050081 }
82 else /* end of block, just aligning for ASCII dump */
83 {
Chris Austen99497312015-10-22 13:00:16 -050084 fprintf(s," ");
Chris Austen0ba649e2015-10-13 12:28:13 -050085 }
Chris Austen120f7322015-10-14 23:27:31 -050086
Chris Austen0ba649e2015-10-13 12:28:13 -050087 /* print ASCII dump */
88 if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
89 {
90 for(j = i - (HEXDUMP_COLS - 1); j <= i; j++)
91 {
92 if(j >= len) /* end of block, not really printing */
93 {
Chris Austen99497312015-10-22 13:00:16 -050094 fputc(' ', s);
Chris Austen0ba649e2015-10-13 12:28:13 -050095 }
96 else if(isprint(((char*)mem)[j])) /* printable char */
97 {
Chris Austen99497312015-10-22 13:00:16 -050098 fputc(0xFF & ((char*)mem)[j], s);
Chris Austen0ba649e2015-10-13 12:28:13 -050099 }
100 else /* other char */
101 {
Chris Austen99497312015-10-22 13:00:16 -0500102 fputc('.',s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500103 }
104 }
Chris Austen99497312015-10-22 13:00:16 -0500105 fputc('\n',s);
Chris Austen0ba649e2015-10-13 12:28:13 -0500106 }
107 }
108}
109
110
vishwabmcba0bd5f2015-09-30 16:50:23 +0530111// Method that gets called by shared libraries to get their command handlers registered
112void ipmi_register_callback(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
113 ipmi_context_t context, ipmid_callback_t handler)
114{
115 // Pack NetFn and Command in one.
116 auto netfn_and_cmd = std::make_pair(netfn, cmd);
117
118 // Pack Function handler and Data in another.
119 auto handler_and_context = std::make_pair(handler, context);
120
121 // Check if the registration has already been made..
122 auto iter = g_ipmid_router_map.find(netfn_and_cmd);
123 if(iter != g_ipmid_router_map.end())
124 {
125 fprintf(stderr,"ERROR : Duplicate registration for NetFn [0x%X], Cmd:[0x%X]\n",netfn, cmd);
126 }
127 else
128 {
129 // This is a fresh registration.. Add it to the map.
130 g_ipmid_router_map.emplace(netfn_and_cmd, handler_and_context);
131 }
132
133 return;
134}
135
136// Looks at the map and calls corresponding handler functions.
137ipmi_ret_t ipmi_netfn_router(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
138 ipmi_response_t response, ipmi_data_len_t data_len)
139{
140 // return from the Command handlers.
141 ipmi_ret_t rc = IPMI_CC_INVALID;
142
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500143 // If restricted mode is true and command is not whitelisted, don't
144 // execute the command
145 if(restricted_mode)
146 {
147 if (!std::binary_search(whitelist.cbegin(), whitelist.cend(),
148 std::make_pair(netfn, cmd)))
149 {
150 printf("Net function:[0x%X], Command:[0x%X] is not whitelisted\n",
151 netfn, cmd);
152 rc = IPMI_CC_INSUFFICIENT_PRIVILEGE;
153 memcpy(response, &rc, IPMI_CC_LEN);
154 *data_len = IPMI_CC_LEN;
155 return rc;
156 }
157 }
158
vishwabmcba0bd5f2015-09-30 16:50:23 +0530159 // Walk the map that has the registered handlers and invoke the approprite
160 // handlers for matching commands.
161 auto iter = g_ipmid_router_map.find(std::make_pair(netfn, cmd));
162 if(iter == g_ipmid_router_map.end())
163 {
Chris Austen99497312015-10-22 13:00:16 -0500164 fprintf(stderr, "No registered handlers for NetFn:[0x%X], Cmd:[0x%X]"
vishwabmcba0bd5f2015-09-30 16:50:23 +0530165 " trying Wilcard implementation \n",netfn, cmd);
166
167 // Now that we did not find any specific [NetFn,Cmd], tuple, check for
168 // NetFn, WildCard command present.
169 iter = g_ipmid_router_map.find(std::make_pair(netfn, IPMI_CMD_WILDCARD));
170 if(iter == g_ipmid_router_map.end())
171 {
Chris Austen99497312015-10-22 13:00:16 -0500172 fprintf(stderr, "No Registered handlers for NetFn:[0x%X],Cmd:[0x%X]\n",netfn, IPMI_CMD_WILDCARD);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530173
174 // Respond with a 0xC1
175 memcpy(response, &rc, IPMI_CC_LEN);
176 *data_len = IPMI_CC_LEN;
177 return rc;
178 }
179 }
180
181#ifdef __IPMI_DEBUG__
182 // We have either a perfect match -OR- a wild card atleast,
183 printf("Calling Net function:[0x%X], Command:[0x%X]\n", netfn, cmd);
184#endif
185
186 // Extract the map data onto appropriate containers
187 auto handler_and_context = iter->second;
188
189 // Creating a pointer type casted to char* to make sure we advance 1 byte
190 // when we advance pointer to next's address. advancing void * would not
191 // make sense.
192 char *respo = &((char *)response)[IPMI_CC_LEN];
193
194 // Response message from the plugin goes into a byte post the base response
195 rc = (handler_and_context.first) (netfn, cmd, request, respo,
196 data_len, handler_and_context.second);
Chris Austen120f7322015-10-14 23:27:31 -0500197
vishwabmcba0bd5f2015-09-30 16:50:23 +0530198 // Now copy the return code that we got from handler and pack it in first
199 // byte.
200 memcpy(response, &rc, IPMI_CC_LEN);
Chris Austen120f7322015-10-14 23:27:31 -0500201
vishwabmcba0bd5f2015-09-30 16:50:23 +0530202 // Data length is now actual data + completion code.
203 *data_len = *data_len + IPMI_CC_LEN;
204
205 return rc;
206}
207
vishwabmcba0bd5f2015-09-30 16:50:23 +0530208
vishwabmcba0bd5f2015-09-30 16:50:23 +0530209
vishwabmcba0bd5f2015-09-30 16:50:23 +0530210
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800211static 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 +0530212
Chris Austen0ba649e2015-10-13 12:28:13 -0500213 sd_bus_error error = SD_BUS_ERROR_NULL;
214 sd_bus_message *reply = NULL, *m=NULL;
Jeremy Kerre41081f2015-10-27 12:11:36 +0800215 const char *dest, *path;
Chris Austen0ba649e2015-10-13 12:28:13 -0500216 int r, pty;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530217
Jeremy Kerre41081f2015-10-27 12:11:36 +0800218 dest = sd_bus_message_get_sender(req);
219 path = sd_bus_message_get_path(req);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530220
Jeremy Kerre41081f2015-10-27 12:11:36 +0800221 r = sd_bus_message_new_method_call(bus,&m,dest,path,DBUS_INTF,"sendMessage");
Chris Austen0ba649e2015-10-13 12:28:13 -0500222 if (r < 0) {
223 fprintf(stderr, "Failed to add the method object: %s\n", strerror(-r));
224 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530225 }
226
vishwabmcba0bd5f2015-09-30 16:50:23 +0530227
Chris Austenabfb5e82015-10-13 12:29:24 -0500228 // Responses in IPMI require a bit set. So there ya go...
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800229 netfn |= 0x01;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530230
Chris Austen0ba649e2015-10-13 12:28:13 -0500231
232 // Add the bytes needed for the methods to be called
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800233 r = sd_bus_message_append(m, "yyyyy", seq, netfn, lun, cmd, cc);
Chris Austen0ba649e2015-10-13 12:28:13 -0500234 if (r < 0) {
235 fprintf(stderr, "Failed add the netfn and others : %s\n", strerror(-r));
Chris Austen169395e2015-12-02 20:56:15 -0600236 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500237 }
Chris Austen120f7322015-10-14 23:27:31 -0500238
Chris Austen0ba649e2015-10-13 12:28:13 -0500239 r = sd_bus_message_append_array(m, 'y', buf, len);
240 if (r < 0) {
241 fprintf(stderr, "Failed to add the string of response bytes: %s\n", strerror(-r));
Chris Austen169395e2015-12-02 20:56:15 -0600242 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500243 }
244
245
246
247 // Call the IPMI responder on the bus so the message can be sent to the CEC
248 r = sd_bus_call(bus, m, 0, &error, &reply);
249 if (r < 0) {
Chris Austen169395e2015-12-02 20:56:15 -0600250 fprintf(stderr, "Failed to call the method: %s\n", strerror(-r));
Chris Austen6bd23962015-12-07 21:31:48 -0600251 fprintf(stderr, "Dest: %s, Path: %s\n", dest, path);
Chris Austen169395e2015-12-02 20:56:15 -0600252 goto final;
Chris Austen0ba649e2015-10-13 12:28:13 -0500253 }
254
255 r = sd_bus_message_read(reply, "x", &pty);
Chris Austen0ba649e2015-10-13 12:28:13 -0500256 if (r < 0) {
257 fprintf(stderr, "Failed to get a rc from the method: %s\n", strerror(-r));
Chris Austen0ba649e2015-10-13 12:28:13 -0500258 }
259
Chris Austen169395e2015-12-02 20:56:15 -0600260final:
Chris Austen0ba649e2015-10-13 12:28:13 -0500261 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600262 m = sd_bus_message_unref(m);
263 reply = sd_bus_message_unref(reply);
Chris Austen0ba649e2015-10-13 12:28:13 -0500264
Chris Austen0ba649e2015-10-13 12:28:13 -0500265 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Chris Austen0ba649e2015-10-13 12:28:13 -0500266}
267
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500268void cache_restricted_mode()
269{
270 sd_bus *bus = ipmid_get_sd_bus_connection();
271 sd_bus_message *reply = NULL;
272 sd_bus_error error = SD_BUS_ERROR_NULL;
273 int rc = 0;
274
275 rc = sd_bus_call_method(bus,
276 settings_host_bus,
277 settings_host_object,
278 settings_host_intf,
279 "Get",
280 &error,
281 &reply,
282 "ss",
283 settings_host_bus,
284 "restricted_mode");
285 if(rc < 0)
286 {
287 fprintf(stderr, "Failed sd_bus_call_method method for restricted mode: %s\n",
288 strerror(-rc));
289 goto cleanup;
290 }
291
292 rc = sd_bus_message_read(reply, "v", "b", &restricted_mode);
293 if(rc < 0)
294 {
295 fprintf(stderr, "Failed to parse response message for restricted mode: %s\n",
296 strerror(-rc));
297 // Fail-safe to restricted mode
298 restricted_mode = true;
299 }
300
301 printf("Restricted mode = %d\n", restricted_mode);
302
303cleanup:
304 sd_bus_error_free(&error);
305 reply = sd_bus_message_unref(reply);
306}
307
308static int handle_restricted_mode_change(sd_bus_message *m, void *user_data,
309 sd_bus_error *ret_error)
310{
311 cache_restricted_mode();
312 return 0;
313}
314
Chris Austen0ba649e2015-10-13 12:28:13 -0500315static int handle_ipmi_command(sd_bus_message *m, void *user_data, sd_bus_error
316 *ret_error) {
317 int r = 0;
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800318 unsigned char sequence, netfn, lun, cmd;
Chris Austen0ba649e2015-10-13 12:28:13 -0500319 const void *request;
320 size_t sz;
321 size_t resplen =MAX_IPMI_BUFFER;
322 unsigned char response[MAX_IPMI_BUFFER];
323
Chris Austen0ba649e2015-10-13 12:28:13 -0500324 memset(response, 0, MAX_IPMI_BUFFER);
325
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800326 r = sd_bus_message_read(m, "yyyy", &sequence, &netfn, &lun, &cmd);
Chris Austen0ba649e2015-10-13 12:28:13 -0500327 if (r < 0) {
328 fprintf(stderr, "Failed to parse signal message: %s\n", strerror(-r));
329 return -1;
330 }
331
332 r = sd_bus_message_read_array(m, 'y', &request, &sz );
333 if (r < 0) {
334 fprintf(stderr, "Failed to parse signal message: %s\n", strerror(-r));
335 return -1;
336 }
337
Chris Austen99497312015-10-22 13:00:16 -0500338 fprintf(ipmiio, "IPMI Incoming: Seq 0x%02x, NetFn 0x%02x, CMD: 0x%02x \n", sequence, netfn, cmd);
339 hexdump(ipmiio, (void*)request, sz);
Chris Austen0ba649e2015-10-13 12:28:13 -0500340
Chris Austen120f7322015-10-14 23:27:31 -0500341 // Allow the length field to be used for both input and output of the
Chris Austen0ba649e2015-10-13 12:28:13 -0500342 // ipmi call
343 resplen = sz;
344
Chris Austen120f7322015-10-14 23:27:31 -0500345 // Now that we have parsed the entire byte array from the caller
vishwabmcba0bd5f2015-09-30 16:50:23 +0530346 // we can call the ipmi router to do the work...
Chris Austen0ba649e2015-10-13 12:28:13 -0500347 r = ipmi_netfn_router(netfn, cmd, (void *)request, (void *)response, &resplen);
348 if(r != 0)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530349 {
Chris Austen0ba649e2015-10-13 12:28:13 -0500350 fprintf(stderr,"ERROR:[0x%X] handling NetFn:[0x%X], Cmd:[0x%X]\n",r, netfn, cmd);
Nan Li80be4b92016-05-23 19:30:49 +0800351
tomjose7ec0add2016-06-27 07:59:28 -0500352 if(r < 0) {
Nan Li80be4b92016-05-23 19:30:49 +0800353 response[0] = IPMI_CC_UNSPECIFIED_ERROR;
354 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530355 }
356
Chris Austen99497312015-10-22 13:00:16 -0500357 fprintf(ipmiio, "IPMI Response:\n");
358 hexdump(ipmiio, (void*)response, resplen);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530359
Chris Austen0ba649e2015-10-13 12:28:13 -0500360 // Send the response buffer from the ipmi command
Jeremy Kerr2564b1a2015-10-27 13:37:17 +0800361 r = send_ipmi_message(m, sequence, netfn, lun, cmd, response[0],
362 ((unsigned char *)response) + 1, resplen - 1);
Chris Austen0ba649e2015-10-13 12:28:13 -0500363 if (r < 0) {
364 fprintf(stderr, "Failed to send the response message\n");
365 return -1;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530366 }
367
vishwabmcba0bd5f2015-09-30 16:50:23 +0530368
Chris Austen0ba649e2015-10-13 12:28:13 -0500369 return 0;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530370}
371
Chris Austen0ba649e2015-10-13 12:28:13 -0500372
vishwabmcba0bd5f2015-09-30 16:50:23 +0530373//----------------------------------------------------------------------
374// handler_select
375// Select all the files ending with with .so. in the given diretcory
376// @d: dirent structure containing the file name
377//----------------------------------------------------------------------
378int handler_select(const struct dirent *entry)
379{
380 // To hold ".so" from entry->d_name;
381 char dname_copy[4] = {0};
382
383 // We want to avoid checking for everything and isolate to the ones having
Adriana Kobylak87e080b2016-07-10 13:16:53 -0500384 // .so.* or .so in them.
385 // Check for versioned libraries .so.*
386 if(strstr(entry->d_name, IPMI_PLUGIN_SONAME_EXTN))
387 {
388 return 1;
389 }
390 // Check for non versioned libraries .so
391 else if(strstr(entry->d_name, IPMI_PLUGIN_EXTN))
vishwabmcba0bd5f2015-09-30 16:50:23 +0530392 {
393 // It is possible that .so could be anywhere in the string but unlikely
Chris Austen120f7322015-10-14 23:27:31 -0500394 // But being careful here. Get the base address of the string, move
vishwabmcba0bd5f2015-09-30 16:50:23 +0530395 // until end and come back 3 steps and that gets what we need.
396 strcpy(dname_copy, (entry->d_name + strlen(entry->d_name)-strlen(IPMI_PLUGIN_EXTN)));
397 if(strcmp(dname_copy, IPMI_PLUGIN_EXTN) == 0)
398 {
399 return 1;
400 }
401 }
402 return 0;
403}
404
405// 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 -0500406// register a callback handler
vishwabmcba0bd5f2015-09-30 16:50:23 +0530407void ipmi_register_callback_handlers(const char* ipmi_lib_path)
408{
409 // For walking the ipmi_lib_path
410 struct dirent **handler_list;
411 int num_handlers = 0;
412
413 // This is used to check and abort if someone tries to register a bad one.
414 void *lib_handler = NULL;
415
416 if(ipmi_lib_path == NULL)
417 {
418 fprintf(stderr,"ERROR; No handlers to be registered for ipmi.. Aborting\n");
419 assert(0);
420 }
421 else
422 {
423 // 1: Open ipmi_lib_path. Its usually "/usr/lib/phosphor-host-ipmid"
424 // 2: Scan the directory for the files that end with .so
Chris Austen120f7322015-10-14 23:27:31 -0500425 // 3: For each one of them, just do a 'dlopen' so that they register
vishwabmcba0bd5f2015-09-30 16:50:23 +0530426 // the handlers for callback routines.
427
428 std::string handler_fqdn = ipmi_lib_path;
Chris Austen120f7322015-10-14 23:27:31 -0500429
vishwabmcba0bd5f2015-09-30 16:50:23 +0530430 // Append a "/" since we need to add the name of the .so. If there is
431 // already a .so, adding one more is not any harm.
432 handler_fqdn += "/";
433
434 num_handlers = scandir(ipmi_lib_path, &handler_list, handler_select, alphasort);
Nan Li36c0cb62016-03-31 11:16:08 +0800435 if (num_handlers < 0)
436 return;
Jeremy Kerr5e8f85e2015-10-27 13:43:54 +0800437
vishwabmcba0bd5f2015-09-30 16:50:23 +0530438 while(num_handlers--)
439 {
Chris Austen54030262015-10-13 12:30:46 -0500440 handler_fqdn = ipmi_lib_path;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530441 handler_fqdn += handler_list[num_handlers]->d_name;
Chris Austen54030262015-10-13 12:30:46 -0500442 printf("Registering handler:[%s]\n",handler_fqdn.c_str());
443
vishwabmcba0bd5f2015-09-30 16:50:23 +0530444 lib_handler = dlopen(handler_fqdn.c_str(), RTLD_NOW);
Nan Li36c0cb62016-03-31 11:16:08 +0800445
vishwabmcba0bd5f2015-09-30 16:50:23 +0530446 if(lib_handler == NULL)
447 {
Chris Austen120f7322015-10-14 23:27:31 -0500448 fprintf(stderr,"ERROR opening [%s]: %s\n",
449 handler_fqdn.c_str(), dlerror());
vishwabmcba0bd5f2015-09-30 16:50:23 +0530450 }
451 // Wipe the memory allocated for this particular entry.
452 free(handler_list[num_handlers]);
453 }
Nan Li36c0cb62016-03-31 11:16:08 +0800454
vishwabmcba0bd5f2015-09-30 16:50:23 +0530455 // Done with all registration.
456 free(handler_list);
457 }
458
459 // TODO : What to be done on the memory that is given by dlopen ?.
460 return;
461}
462
Chris Austen30195fa2015-11-13 14:39:19 -0600463sd_bus *ipmid_get_sd_bus_connection(void) {
464 return bus;
465}
466
vishwab9f559a2016-01-13 01:53:08 -0600467sd_bus_slot *ipmid_get_sd_bus_slot(void) {
468 return ipmid_slot;
469}
470
vishwabmcba0bd5f2015-09-30 16:50:23 +0530471int main(int argc, char *argv[])
472{
Chris Austen0ba649e2015-10-13 12:28:13 -0500473 int r;
Chris Austen99497312015-10-22 13:00:16 -0500474 unsigned long tvalue;
475 int c;
476
477
478
479 // This file and subsequient switch is for turning on levels
480 // of trace
481 ipmicmddetails = ipmiio = ipmidbus = fopen("/dev/null", "w");
482
483 while ((c = getopt (argc, argv, "h:d:")) != -1)
484 switch (c) {
485 case 'd':
486 tvalue = strtoul(optarg, NULL, 16);
487 if (1&tvalue) {
488 ipmiio = stdout;
489 }
490 if (2&tvalue) {
491 ipmidbus = stdout;
492 }
493 if (4&tvalue) {
494 ipmicmddetails = stdout;
495 }
496 break;
497 case 'h':
498 case '?':
499 print_usage();
500 return 1;
501 }
Chris Austen0ba649e2015-10-13 12:28:13 -0500502
503
Chris Austen0ba649e2015-10-13 12:28:13 -0500504 /* Connect to system bus */
505 r = sd_bus_open_system(&bus);
506 if (r < 0) {
507 fprintf(stderr, "Failed to connect to system bus: %s\n",
508 strerror(-r));
509 goto finish;
510 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530511
Chris Austen30195fa2015-11-13 14:39:19 -0600512 // Register all the handlers that provider implementation to IPMI commands.
513 ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
514
vishwa36993272015-11-20 12:43:49 -0600515 // Watch for BT messages
vishwab9f559a2016-01-13 01:53:08 -0600516 r = sd_bus_add_match(bus, &ipmid_slot, FILTER, handle_ipmi_command, NULL);
Chris Austen0ba649e2015-10-13 12:28:13 -0500517 if (r < 0) {
518 fprintf(stderr, "Failed: sd_bus_add_match: %s : %s\n", strerror(-r), FILTER);
519 goto finish;
520 }
vishwabmcba0bd5f2015-09-30 16:50:23 +0530521
Tom Joseph9a61b4f2016-07-11 06:56:11 -0500522 // Wait for changes on Restricted mode
523 r = sd_bus_add_match(bus, &ipmid_slot, RESTRICTED_MODE_FILTER, handle_restricted_mode_change, NULL);
524 if (r < 0) {
525 fprintf(stderr, "Failed: sd_bus_add_match: %s : %s\n", strerror(-r), RESTRICTED_MODE_FILTER);
526 goto finish;
527 }
528
529 // Initialise restricted mode
530 cache_restricted_mode();
vishwabmcba0bd5f2015-09-30 16:50:23 +0530531
Chris Austen0ba649e2015-10-13 12:28:13 -0500532 for (;;) {
533 /* Process requests */
Chris Austen0ba649e2015-10-13 12:28:13 -0500534 r = sd_bus_process(bus, NULL);
535 if (r < 0) {
536 fprintf(stderr, "Failed to process bus: %s\n", strerror(-r));
537 goto finish;
538 }
539 if (r > 0) {
540 continue;
541 }
542
543 r = sd_bus_wait(bus, (uint64_t) - 1);
544 if (r < 0) {
545 fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-r));
546 goto finish;
547 }
548 }
549
550finish:
vishwab9f559a2016-01-13 01:53:08 -0600551 sd_bus_slot_unref(ipmid_slot);
Chris Austen0ba649e2015-10-13 12:28:13 -0500552 sd_bus_unref(bus);
553 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
554
vishwabmcba0bd5f2015-09-30 16:50:23 +0530555}
Chris Austenb071c702015-10-15 00:00:09 -0500556
Chris Austen0012e9b2015-10-22 01:37:46 -0500557// Use a lookup table to find the interface name of a specific sensor
558// This will be used until an alternative is found. this is the first
559// step for mapping IPMI
560int find_interface_property_fru_type(dbus_interface_t *interface, const char *property_name, char *property_value) {
Chris Austenb071c702015-10-15 00:00:09 -0500561
Joel Stanleyf19539e2015-11-25 17:24:05 +1030562 char *str1;
Chris Austen0012e9b2015-10-22 01:37:46 -0500563 sd_bus_error error = SD_BUS_ERROR_NULL;
564 sd_bus_message *reply = NULL, *m=NULL;
Chris Austenb071c702015-10-15 00:00:09 -0500565
566
Chris Austen0012e9b2015-10-22 01:37:46 -0500567 int r;
568
Chris Austen0012e9b2015-10-22 01:37:46 -0500569 r = sd_bus_message_new_method_call(bus,&m,interface->bus,interface->path,"org.freedesktop.DBus.Properties","Get");
570 if (r < 0) {
571 fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
572 fprintf(stderr,"Bus: %s Path: %s Interface: %s \n",
573 interface->bus, interface->path, interface->interface);
vishwa1eaea4f2016-02-26 11:57:40 -0600574 goto final;
Chris Austen0012e9b2015-10-22 01:37:46 -0500575 }
576
577 r = sd_bus_message_append(m, "ss", "org.openbmc.InventoryItem", property_name);
578 if (r < 0) {
579 fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
580 fprintf(stderr,"Bus: %s Path: %s Interface: %s \n",
581 interface->bus, interface->path, interface->interface);
vishwa1eaea4f2016-02-26 11:57:40 -0600582 goto final;
Chris Austen0012e9b2015-10-22 01:37:46 -0500583 }
584
585 r = sd_bus_call(bus, m, 0, &error, &reply);
586 if (r < 0) {
587 fprintf(stderr, "Failed to call the method: %s", strerror(-r));
588 goto final;
589 }
590
591 r = sd_bus_message_read(reply, "v", "s", &str1) ;
592 if (r < 0) {
593 fprintf(stderr, "Failed to get a response: %s", strerror(-r));
594 goto final;
595 }
596
597 strcpy(property_value, str1);
598
599final:
600
601 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600602 m = sd_bus_message_unref(m);
603 reply = sd_bus_message_unref(reply);
Chris Austen0012e9b2015-10-22 01:37:46 -0500604
605 return r;
606}
Chris Austenb071c702015-10-15 00:00:09 -0500607
Chris Austen41a4b312015-10-25 03:45:42 -0500608
Chris Austenb071c702015-10-15 00:00:09 -0500609// Use a lookup table to find the interface name of a specific sensor
610// This will be used until an alternative is found. this is the first
611// step for mapping IPMI
612int find_openbmc_path(const char *type, const uint8_t num, dbus_interface_t *interface) {
Brad Bishop35518682016-07-22 08:35:41 -0400613 char *busname = NULL;
614 const char *iface = "org.openbmc.managers.System";
Chris Austenb071c702015-10-15 00:00:09 -0500615 const char *objname = "/org/openbmc/managers/System";
Brad Bishop35518682016-07-22 08:35:41 -0400616 char *str1 = NULL, *str2, *str3;
Chris Austenb071c702015-10-15 00:00:09 -0500617 sd_bus_error error = SD_BUS_ERROR_NULL;
vishwa1eaea4f2016-02-26 11:57:40 -0600618 sd_bus_message *reply = NULL;
Chris Austenb071c702015-10-15 00:00:09 -0500619
620
621 int r;
Brad Bishop35518682016-07-22 08:35:41 -0400622 r = mapper_get_service(bus, objname, &busname);
623 if (r < 0) {
624 fprintf(stderr, "Failed to get system manager busname: %s\n", strerror(-r));
625 goto final;
626 }
Chris Austenb071c702015-10-15 00:00:09 -0500627
Brad Bishop35518682016-07-22 08:35:41 -0400628 r = sd_bus_call_method(bus,busname,objname,iface, "getObjectFromByteId",
vishwa1eaea4f2016-02-26 11:57:40 -0600629 &error, &reply, "sy", type, num);
Chris Austenb071c702015-10-15 00:00:09 -0500630 if (r < 0) {
631 fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
Chris Austenb071c702015-10-15 00:00:09 -0500632 goto final;
633 }
634
Brad Bishop35518682016-07-22 08:35:41 -0400635 r = sd_bus_message_read(reply, "(ss)", &str2, &str3);
Chris Austenb071c702015-10-15 00:00:09 -0500636 if (r < 0) {
637 fprintf(stderr, "Failed to get a response: %s", strerror(-r));
638 goto final;
639 }
640
Brad Bishop35518682016-07-22 08:35:41 -0400641 r = mapper_get_service(bus, str2, &str1);
642 if (r < 0) {
643 fprintf(stderr, "Failed to get item busname: %s\n", strerror(-r));
644 goto final;
645 }
646
Chris Austenb071c702015-10-15 00:00:09 -0500647 strncpy(interface->bus, str1, MAX_DBUS_PATH);
648 strncpy(interface->path, str2, MAX_DBUS_PATH);
649 strncpy(interface->interface, str3, MAX_DBUS_PATH);
650
651 interface->sensornumber = num;
652
Chris Austenb071c702015-10-15 00:00:09 -0500653final:
654
655 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600656 reply = sd_bus_message_unref(reply);
Brad Bishop35518682016-07-22 08:35:41 -0400657 free(busname);
658 free(str1);
Chris Austenb071c702015-10-15 00:00:09 -0500659
660 return r;
661}
662
663
664/////////////////////////////////////////////////////////////////////
665//
666// Routines used by ipmi commands wanting to interact on the dbus
667//
668/////////////////////////////////////////////////////////////////////
Chris Austen10ccc0f2015-12-10 18:27:04 -0600669int set_sensor_dbus_state_s(uint8_t number, const char *method, const char *value) {
Chris Austen0130d6e2015-10-15 22:32:36 -0500670
671
672 dbus_interface_t a;
673 int r;
674 sd_bus_error error = SD_BUS_ERROR_NULL;
Joel Stanleyf19539e2015-11-25 17:24:05 +1030675 sd_bus_message *m=NULL;
Chris Austen0130d6e2015-10-15 22:32:36 -0500676
Chris Austen99497312015-10-22 13:00:16 -0500677 fprintf(ipmidbus, "Attempting to set a dbus Variant Sensor 0x%02x via %s with a value of %s\n",
Chris Austen0130d6e2015-10-15 22:32:36 -0500678 number, method, value);
679
680 r = find_openbmc_path("SENSOR", number, &a);
681
Nan Li36deb762016-05-12 10:23:41 +0800682 if (r < 0) {
683 fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
684 return 0;
685 }
686
Chris Austen0130d6e2015-10-15 22:32:36 -0500687 r = sd_bus_message_new_method_call(bus,&m,a.bus,a.path,a.interface,method);
688 if (r < 0) {
689 fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
vishwa1eaea4f2016-02-26 11:57:40 -0600690 goto final;
Chris Austen0130d6e2015-10-15 22:32:36 -0500691 }
692
693 r = sd_bus_message_append(m, "v", "s", value);
694 if (r < 0) {
695 fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
vishwa1eaea4f2016-02-26 11:57:40 -0600696 goto final;
Chris Austen0130d6e2015-10-15 22:32:36 -0500697 }
698
699
Chris Austen0130d6e2015-10-15 22:32:36 -0500700 r = sd_bus_call(bus, m, 0, &error, NULL);
701 if (r < 0) {
Chris Austen10ccc0f2015-12-10 18:27:04 -0600702 fprintf(stderr, "Failed to call the method: %s", strerror(-r));
Chris Austen0130d6e2015-10-15 22:32:36 -0500703 }
704
vishwa1eaea4f2016-02-26 11:57:40 -0600705final:
Chris Austen0130d6e2015-10-15 22:32:36 -0500706 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600707 m = sd_bus_message_unref(m);
Chris Austen0130d6e2015-10-15 22:32:36 -0500708
709 return 0;
710}
Chris Austen10ccc0f2015-12-10 18:27:04 -0600711int set_sensor_dbus_state_y(uint8_t number, const char *method, const uint8_t value) {
712
713
714 dbus_interface_t a;
715 int r;
716 sd_bus_error error = SD_BUS_ERROR_NULL;
717 sd_bus_message *m=NULL;
718
719 fprintf(ipmidbus, "Attempting to set a dbus Variant Sensor 0x%02x via %s with a value of 0x%02x\n",
720 number, method, value);
721
722 r = find_openbmc_path("SENSOR", number, &a);
723
Nan Li36deb762016-05-12 10:23:41 +0800724 if (r < 0) {
725 fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
726 return 0;
727 }
728
Chris Austen10ccc0f2015-12-10 18:27:04 -0600729 r = sd_bus_message_new_method_call(bus,&m,a.bus,a.path,a.interface,method);
730 if (r < 0) {
731 fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
vishwa1eaea4f2016-02-26 11:57:40 -0600732 goto final;
Chris Austen10ccc0f2015-12-10 18:27:04 -0600733 }
734
Adriana Kobylak93125982016-03-01 12:48:10 -0600735 r = sd_bus_message_append(m, "v", "i", value);
Chris Austen10ccc0f2015-12-10 18:27:04 -0600736 if (r < 0) {
737 fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
vishwa1eaea4f2016-02-26 11:57:40 -0600738 goto final;
Chris Austen10ccc0f2015-12-10 18:27:04 -0600739 }
740
741
742 r = sd_bus_call(bus, m, 0, &error, NULL);
743 if (r < 0) {
744 fprintf(stderr, "12 Failed to call the method: %s", strerror(-r));
745 }
746
vishwa1eaea4f2016-02-26 11:57:40 -0600747final:
Chris Austen10ccc0f2015-12-10 18:27:04 -0600748 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600749 m = sd_bus_message_unref(m);
Chris Austen10ccc0f2015-12-10 18:27:04 -0600750
751 return 0;
vishwa1eaea4f2016-02-26 11:57:40 -0600752}