summaryrefslogtreecommitdiff
path: root/lib/ipmi_mc.c
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2022-10-30 18:12:02 +0100
committerJörg Frings-Fürst <debian@jff-webhosting.net>2022-10-30 18:12:02 +0100
commit1f3c9b4ae26ce1d46d954d509b83b8684ada5625 (patch)
tree260b922ec4d5d153cc6db745e27931cfd464472f /lib/ipmi_mc.c
parent8fcf0ba6f182918bd584bb80bf0b8998acad26a8 (diff)
parent8b758ee941f4c1ffea0532caa74b1fcd8101d1d8 (diff)
Merge branch 'release/debian/1.8.19-1'debian/1.8.19-1
Diffstat (limited to 'lib/ipmi_mc.c')
-rw-r--r--lib/ipmi_mc.c774
1 files changed, 640 insertions, 134 deletions
diff --git a/lib/ipmi_mc.c b/lib/ipmi_mc.c
index 4580bfb..a594347 100644
--- a/lib/ipmi_mc.c
+++ b/lib/ipmi_mc.c
@@ -34,6 +34,10 @@
#include <string.h>
#include <stdio.h>
#include <time.h>
+#include <limits.h>
+#include <stdbool.h>
+
+#include <arpa/inet.h>
#include <ipmitool/helper.h>
#include <ipmitool/log.h>
@@ -42,6 +46,7 @@
#include <ipmitool/ipmi_intf.h>
#include <ipmitool/ipmi_mc.h>
#include <ipmitool/ipmi_strings.h>
+#include <ipmitool/ipmi_time.h>
extern int verbose;
@@ -81,14 +86,14 @@ ipmi_mc_reset(struct ipmi_intf * intf, int cmd)
if (cmd == BMC_COLD_RESET)
intf->abort = 1;
- if (cmd == BMC_COLD_RESET && rsp == NULL) {
+ if (cmd == BMC_COLD_RESET && !rsp) {
/* This is expected. See 20.2 Cold Reset Command, p.243, IPMIv2.0 rev1.0 */
- } else if (rsp == NULL) {
+ } else if (!rsp) {
lprintf(LOG_ERR, "MC reset command failed.");
return (-1);
- } else if (rsp->ccode > 0) {
+ } else if (rsp->ccode) {
lprintf(LOG_ERR, "MC reset command failed: %s",
- val2str(rsp->ccode, completion_code_vals));
+ CC_STRING(rsp->ccode));
return (-1);
}
@@ -181,13 +186,13 @@ printf_mc_usage(void)
struct bitfield_data * bf;
lprintf(LOG_NOTICE, "MC Commands:");
lprintf(LOG_NOTICE, " reset <warm|cold>");
- lprintf(LOG_NOTICE, " guid");
+ lprintf(LOG_NOTICE, " guid [auto|smbios|ipmi|rfc4122|dump]");
lprintf(LOG_NOTICE, " info");
lprintf(LOG_NOTICE, " watchdog <get|reset|off>");
lprintf(LOG_NOTICE, " selftest");
lprintf(LOG_NOTICE, " getenables");
lprintf(LOG_NOTICE, " setenables <option=on|off> ...");
- for (bf = mc_enables_bf; bf->name != NULL; bf++) {
+ for (bf = mc_enables_bf; bf->name; bf++) {
lprintf(LOG_NOTICE, " %-20s %s", bf->name, bf->desc);
}
printf_sysinfo_usage(0);
@@ -230,15 +235,38 @@ printf_sysinfo_usage(int full_help)
static void
print_watchdog_usage(void)
{
- lprintf(LOG_NOTICE, "usage: watchdog <command>:");
- lprintf(LOG_NOTICE, " get : Get Current Watchdog settings");
- lprintf(LOG_NOTICE, " reset : Restart Watchdog timer based on most recent settings");
- lprintf(LOG_NOTICE, " off : Shut off a running Watchdog timer");
+ lprintf(LOG_NOTICE,
+"usage: watchdog <command>:\n"
+"\n"
+" set <option[=value]> [<option[=value]> ...]\n"
+" Set Watchdog settings\n"
+" Options: (* = mandatory)\n"
+" timeout=<1-6553> - [0] Initial countdown value, sec\n"
+" pretimeout=<1-255> - [0] Pre-timeout interval, sec\n"
+" int=<smi|nmi|msg> - [-] Pre-timeout interrupt type\n"
+" use=<frb2|post|osload|sms|oem> - [-] Timer use\n"
+" clear=<frb2|post|osload|sms|oem> - [-] Clear timer use expiration\n"
+" flag, can be specified\n"
+" multiple times\n"
+" action=<reset|poweroff|cycle|none> - [none] Timer action\n"
+" nolog - [-] Don't log the timer use\n"
+" dontstop - [-] Don't stop the timer\n"
+" while applying settings\n"
+"\n"
+" get\n"
+" Get Current settings\n"
+"\n"
+" reset\n"
+" Restart Watchdog timer based on the most recent settings\n"
+"\n"
+" off\n"
+" Shut off a running Watchdog timer"
+ );
}
/* ipmi_mc_get_enables - print out MC enables
*
- * @intf: ipmi inteface
+ * @intf: ipmi interface
*
* returns 0 on success
* returns -1 on error
@@ -255,17 +283,17 @@ ipmi_mc_get_enables(struct ipmi_intf * intf)
req.msg.cmd = BMC_GET_GLOBAL_ENABLES;
rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
+ if (!rsp) {
lprintf(LOG_ERR, "Get Global Enables command failed");
return -1;
}
- if (rsp->ccode > 0) {
+ if (rsp->ccode) {
lprintf(LOG_ERR, "Get Global Enables command failed: %s",
- val2str(rsp->ccode, completion_code_vals));
+ CC_STRING(rsp->ccode));
return -1;
}
- for (bf = mc_enables_bf; bf->name != NULL; bf++) {
+ for (bf = mc_enables_bf; bf->name; bf++) {
printf("%-40s : %sabled\n", bf->desc,
rsp->data[0] & bf->mask ? "en" : "dis");
}
@@ -275,7 +303,7 @@ ipmi_mc_get_enables(struct ipmi_intf * intf)
/* ipmi_mc_set_enables - set MC enable flags
*
- * @intf: ipmi inteface
+ * @intf: ipmi interface
* @argc: argument count
* @argv: argument list
*
@@ -295,7 +323,7 @@ ipmi_mc_set_enables(struct ipmi_intf * intf, int argc, char ** argv)
printf_mc_usage();
return (-1);
}
- else if (strncmp(argv[0], "help", 4) == 0) {
+ else if (!strcmp(argv[0], "help")) {
printf_mc_usage();
return 0;
}
@@ -305,28 +333,28 @@ ipmi_mc_set_enables(struct ipmi_intf * intf, int argc, char ** argv)
req.msg.cmd = BMC_GET_GLOBAL_ENABLES;
rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
+ if (!rsp) {
lprintf(LOG_ERR, "Get Global Enables command failed");
return -1;
}
- if (rsp->ccode > 0) {
+ if (rsp->ccode) {
lprintf(LOG_ERR, "Get Global Enables command failed: %s",
- val2str(rsp->ccode, completion_code_vals));
+ CC_STRING(rsp->ccode));
return -1;
}
en = rsp->data[0];
for (i = 0; i < argc; i++) {
- for (bf = mc_enables_bf; bf->name != NULL; bf++) {
+ for (bf = mc_enables_bf; bf->name; bf++) {
int nl = strlen(bf->name);
- if (strncmp(argv[i], bf->name, nl) != 0)
+ if (strcmp(argv[i], bf->name))
continue;
- if (strncmp(argv[i]+nl+1, "off", 3) == 0) {
+ if (!strcmp(argv[i]+nl+1, "off")) {
printf("Disabling %s\n", bf->desc);
en &= ~bf->mask;
}
- else if (strncmp(argv[i]+nl+1, "on", 2) == 0) {
+ else if (!strcmp(argv[i]+nl+1, "on")) {
printf("Enabling %s\n", bf->desc);
en |= bf->mask;
}
@@ -347,13 +375,13 @@ ipmi_mc_set_enables(struct ipmi_intf * intf, int argc, char ** argv)
req.msg.data_len = 1;
rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
+ if (!rsp) {
lprintf(LOG_ERR, "Set Global Enables command failed");
return -1;
}
- else if (rsp->ccode > 0) {
+ else if (rsp->ccode) {
lprintf(LOG_ERR, "Set Global Enables command failed: %s",
- val2str(rsp->ccode, completion_code_vals));
+ CC_STRING(rsp->ccode));
return -1;
}
@@ -397,13 +425,13 @@ ipmi_mc_get_deviceid(struct ipmi_intf * intf)
req.msg.data_len = 0;
rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
+ if (!rsp) {
lprintf(LOG_ERR, "Get Device ID command failed");
return -1;
}
- if (rsp->ccode > 0) {
+ if (rsp->ccode) {
lprintf(LOG_ERR, "Get Device ID command failed: %s",
- val2str(rsp->ccode, completion_code_vals));
+ CC_STRING(rsp->ccode));
return -1;
}
@@ -421,18 +449,15 @@ ipmi_mc_get_deviceid(struct ipmi_intf * intf)
printf("Manufacturer ID : %lu\n",
(long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id));
printf("Manufacturer Name : %s\n",
- val2str( (long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id),
- ipmi_oem_info) );
+ OEM_MFG_STRING(devid->manufacturer_id));
printf("Product ID : %u (0x%02x%02x)\n",
buf2short((uint8_t *)(devid->product_id)),
devid->product_id[1], devid->product_id[0]);
- product=oemval2str(IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id),
- (devid->product_id[1]<<8)+devid->product_id[0],
- ipmi_oem_product_info);
+ product = OEM_PROD_STRING(devid->manufacturer_id, devid->product_id);
- if (product!=NULL) {
+ if (product) {
printf("Product Name : %s\n", product);
}
@@ -470,69 +495,292 @@ ipmi_mc_get_deviceid(struct ipmi_intf * intf)
* returns - negative number means error, positive is a ccode.
*/
int
-_ipmi_mc_get_guid(struct ipmi_intf *intf, struct ipmi_guid_t *guid)
+_ipmi_mc_get_guid(struct ipmi_intf *intf, ipmi_guid_t *guid)
{
struct ipmi_rs *rsp;
struct ipmi_rq req;
- if (guid == NULL) {
+ if (!guid) {
return (-3);
}
- memset(guid, 0, sizeof(struct ipmi_guid_t));
+ memset(guid, 0, sizeof(ipmi_guid_t));
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_GET_GUID;
rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
+ if (!rsp) {
return (-1);
- } else if (rsp->ccode > 0) {
+ } else if (rsp->ccode) {
return rsp->ccode;
} else if (rsp->data_len != 16
- || rsp->data_len != sizeof(struct ipmi_guid_t)) {
+ || rsp->data_len != sizeof(ipmi_guid_t)) {
return (-2);
}
- memcpy(guid, &rsp->data[0], sizeof(struct ipmi_guid_t));
+ memcpy(guid, &rsp->data[0], sizeof(ipmi_guid_t));
return 0;
}
-/* ipmi_mc_print_guid - print-out given BMC GUID
+/* A helper function to convert GUID time to time_t */
+static time_t _guid_time(uint64_t t_low, uint64_t t_mid, uint64_t t_hi)
+{
+ /* GUID time-stamp is a 60-bit value representing the
+ * count of 100ns intervals since 00:00:00.00, 15 Oct 1582 */
+
+ const uint64_t t100ns_in_sec = 10000000LL;
+
+ /* Seconds from 15 Oct 1582 to 1 Jan 1970 00:00:00 */
+ uint64_t epoch_since_gregorian = 12219292800;
+
+ /* 100ns intervals since 15 Oct 1582 00:00:00 */
+ uint64_t gregorian = (GUID_TIME_HI(t_hi) << 48)
+ | (t_mid << 32)
+ | t_low;
+ time_t unixtime; /* We need timestamp in seconds since UNIX epoch */
+
+ gregorian /= t100ns_in_sec; /* Convert to seconds */
+ unixtime = gregorian - epoch_since_gregorian;
+
+ return unixtime;
+}
+
+#define TM_YEAR_BASE 1900
+#define EPOCH_YEAR 1970
+static bool _is_time_valid(time_t t)
+{
+ time_t t_now = time(NULL);
+ struct tm tm;
+ struct tm now;
+
+ gmtime_r(&t, &tm);
+ gmtime_r(&t_now, &now);
+
+ /* It's enought to check that the year fits in [Epoch .. now] interval */
+
+ if (tm.tm_year + TM_YEAR_BASE < EPOCH_YEAR)
+ return false;
+
+ if (tm.tm_year > now.tm_year) {
+ /* GUID timestamp can't be in future */
+ return false;
+ }
+
+ return true;
+}
+
+/** ipmi_mc_parse_guid - print-out given BMC GUID
+ *
+ * The function parses the raw guid data according to the requested encoding
+ * mode. If GUID_AUTO mode is requested, then automatic detection of encoding
+ * is attempted using the version nibble of the time_hi_and_version field of
+ * each of the supported encodings.
*
- * @guid - struct with GUID.
+ * Considering the rather random nature of GUIDs, it may happen that the
+ * version nibble is valid for multiple encodings at the same time. That's why
+ * if the version is 1 (time-based), the function will also check validity of
+ * the time stamp. If a valid time stamp is found for a given mode, the mode is
+ * considered detected and no further checks are performed. Otherwise other
+ * encodings are probed the same way. If in neither encoding the valid version
+ * nibble happened to indicate time-based version or no valid time-stamp has
+ * been found, then the last probed encoding with valid version nibble is
+ * considered detected. If none of the probed encodings indicated a valid
+ * version nibble, then fall back to GUID_DUMP
*
- * returns 0
+ * @param[in] guid - The original GUID data as received from BMC
+ * @param[in] mode - The requested mode/encoding
+ *
+ * @returns parsed GUID
*/
-static int
-ipmi_mc_print_guid(struct ipmi_guid_t guid)
+parsed_guid_t ipmi_parse_guid(void *guid, ipmi_guid_mode_t guid_mode)
{
- char tbuf[40];
- time_t s;
- memset(tbuf, 0, 40);
- /* Kipp - changed order of last field (node) to follow specification */
- printf("System GUID : %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n",
- guid.time_low, guid.time_mid, guid.time_hi_and_version,
- guid.clock_seq_hi_variant << 8 | guid.clock_seq_low,
- guid.node[0], guid.node[1], guid.node[2],
- guid.node[3], guid.node[4], guid.node[5]);
+ ipmi_guid_mode_t i;
+ ipmi_guid_t *ipmi_guid = guid;
+ rfc_guid_t *rfc_guid = guid;
+ parsed_guid_t parsed_guid = { 0 };
+ uint32_t t_low[GUID_REAL_MODES];
+ uint16_t t_mid[GUID_REAL_MODES];
+ uint16_t t_hi[GUID_REAL_MODES];
+ uint16_t clk[GUID_REAL_MODES];
+ time_t seconds[GUID_REAL_MODES];
+ bool detect = false;
+
+ /* Unless another mode is detected, default to dumping */
+ if (GUID_AUTO == guid_mode) {
+ detect = true;
+ guid_mode = GUID_DUMP;
+ }
- s = (time_t)guid.time_low; /* Kipp - removed the BSWAP_32, it was not needed here */
- strftime(tbuf, sizeof(tbuf), "%m/%d/%Y %H:%M:%S", localtime(&s));
- printf("Timestamp : %s\n", tbuf);
- return 0;
+ /* Try to convert time using all possible methods to use
+ * the result later if GUID_AUTO is requested */
+
+ /* For IPMI all fields are little-endian (LSB first) */
+ t_hi[GUID_IPMI] = ipmi16toh(&ipmi_guid->time_hi_and_version);
+ t_mid[GUID_IPMI] = ipmi16toh(&ipmi_guid->time_mid);
+ t_low[GUID_IPMI] = ipmi32toh(&ipmi_guid->time_low);
+ clk[GUID_IPMI] = ipmi16toh(&ipmi_guid->clock_seq_and_rsvd);
+
+ /* For RFC4122 all fields are in network byte order (MSB first) */
+ t_hi[GUID_RFC4122] = ntohs(rfc_guid->time_hi_and_version);
+ t_mid[GUID_RFC4122] = ntohs(rfc_guid->time_mid);
+ t_low[GUID_RFC4122] = ntohl(rfc_guid->time_low);
+ clk[GUID_RFC4122] = ntohs(rfc_guid->clock_seq_and_rsvd);
+
+ /* For SMBIOS time fields are little-endian (as in IPMI), the rest is
+ * in network order (as in RFC4122) */
+ t_hi[GUID_SMBIOS] = ipmi16toh(&rfc_guid->time_hi_and_version);
+ t_mid[GUID_SMBIOS] = ipmi16toh(&rfc_guid->time_mid);
+ t_low[GUID_SMBIOS] = ipmi32toh(&rfc_guid->time_low);
+ clk[GUID_SMBIOS] = ntohs(rfc_guid->clock_seq_and_rsvd);
+
+ /* Using 0 here to allow for reordering of modes in ipmi_guid_mode_t */
+ for (i = 0; i < GUID_REAL_MODES; ++i) {
+ seconds[i] = _guid_time(t_low[i], t_mid[i], t_hi[i]);
+
+ /* If autodetection was initially requested and mode
+ * hasn't been detected yet */
+ if (detect) {
+ guid_version_t ver = GUID_VERSION(t_hi[i]);
+ if (is_guid_version_valid(ver)) {
+ guid_mode = i;
+ if (GUID_VERSION_TIME == ver && _is_time_valid(seconds[i])) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (guid_mode >= GUID_REAL_MODES) {
+ guid_mode = GUID_DUMP;
+ /* The endianness and field order are irrelevant for dump mode */
+ memcpy(&parsed_guid, guid, sizeof(ipmi_guid_t));
+ goto out;
+ }
+
+ /*
+ * Return only a valid version in the parsed version field.
+ * If one needs the raw value, they still may use
+ * GUID_VERSION(parsed_guid.time_hi_and_version)
+ */
+ parsed_guid.ver = GUID_VERSION(t_hi[guid_mode]);
+ if (parsed_guid.ver > GUID_VERSION_MAX) {
+ parsed_guid.ver = GUID_VERSION_UNKNOWN;
+ }
+
+ if (GUID_VERSION_TIME == parsed_guid.ver) {
+ parsed_guid.time = seconds[guid_mode];
+ }
+
+ if (GUID_IPMI == guid_mode) {
+ /*
+ * In IPMI all fields are little-endian (LSB first)
+ * That is, first byte last. Hence, swap before copying.
+ */
+ memcpy(parsed_guid.node,
+ array_byteswap(ipmi_guid->node, GUID_NODE_SZ),
+ GUID_NODE_SZ);
+ } else {
+ /*
+ * For RFC4122 and SMBIOS the node field is in network byte order.
+ * That is first byte first. Hence, copy as is.
+ */
+ memcpy(parsed_guid.node, rfc_guid->node, GUID_NODE_SZ);
+ }
+
+ parsed_guid.time_low = t_low[guid_mode];
+ parsed_guid.time_mid = t_mid[guid_mode];
+ parsed_guid.time_hi_and_version = t_hi[guid_mode];
+ parsed_guid.clock_seq_and_rsvd = clk[guid_mode];
+
+out:
+ parsed_guid.mode = guid_mode;
+ return parsed_guid;
}
-/* ipmi_mc_get_guid - Gets and prints-out System GUID */
-int
-ipmi_mc_get_guid(struct ipmi_intf *intf)
+/* ipmi_mc_print_guid - print-out given BMC GUID
+ *
+ * @param[in] intf - The IPMI interface to request GUID from
+ * @param[in] guid_mode - GUID decoding mode
+ *
+ * @returns status code
+ * @retval 0 - Success
+ * @retval -1 - Error
+ */
+static int
+ipmi_mc_print_guid(struct ipmi_intf *intf, ipmi_guid_mode_t guid_mode)
{
- struct ipmi_guid_t guid;
+ /* Allocate a byte array for ease of use in dump mode */
+ uint8_t guid_data[sizeof(ipmi_guid_t)];
+
+ /* These are host architecture specific */
+ parsed_guid_t guid;
+
+ const char *guid_ver_str[GUID_VERSION_COUNT] = {
+ [GUID_VERSION_UNKNOWN] = "Unknown/unsupported",
+ [GUID_VERSION_TIME] = "Time-based",
+ [GUID_VERSION_DCE] = "DCE Security with POSIX UIDs (not for IPMI)",
+ [GUID_VERSION_MD5] = "Name-based using MD5",
+ [GUID_VERSION_RND] = "Random or pseudo-random",
+ [GUID_VERSION_SHA1] = "Name-based using SHA-1"
+ };
+
+ const char *guid_mode_str[GUID_TOTAL_MODES] = {
+ [GUID_IPMI] = "IPMI",
+ [GUID_RFC4122] = "RFC4122",
+ [GUID_SMBIOS] = "SMBIOS",
+ [GUID_AUTO] = "Automatic (if you see this, report a bug)",
+ [GUID_DUMP] = "Unknown (data dumped)"
+ };
+
int rc;
- rc = _ipmi_mc_get_guid(intf, &guid);
+
+ rc = _ipmi_mc_get_guid(intf, (ipmi_guid_t *)guid_data);
if (eval_ccode(rc) != 0) {
return (-1);
}
- rc = ipmi_mc_print_guid(guid);
- return rc;
+
+ printf("System GUID : ");
+
+ guid = ipmi_parse_guid(guid_data, guid_mode);
+ if (GUID_DUMP == guid.mode) {
+ size_t i;
+ for (i = 0; i < sizeof(guid_data); ++i) {
+ printf("%02X", guid_data[i]);
+ }
+ printf("\n");
+ return 0;
+ }
+
+ printf("%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x\n",
+ (int)guid.time_low,
+ (int)guid.time_mid,
+ (int)guid.time_hi_and_version,
+ guid.clock_seq_and_rsvd,
+ guid.node[0], guid.node[1], guid.node[2],
+ guid.node[3], guid.node[4], guid.node[5]);
+
+ if (GUID_AUTO == guid_mode) {
+ /* ipmi_parse_guid() returns only valid modes in guid.ver */
+ printf("GUID Encoding : %s", guid_mode_str[guid.mode]);
+ if (GUID_IPMI != guid.mode) {
+ printf(" (WARNING: IPMI Specification violation!)");
+ }
+ printf("\n");
+ }
+
+ printf("GUID Version : %s", guid_ver_str[guid.ver]);
+
+ switch (guid.ver) {
+ case GUID_VERSION_UNKNOWN:
+ printf(" (%d)\n", GUID_VERSION((int)guid.time_hi_and_version));
+ break;
+ case GUID_VERSION_TIME:
+ printf("\nTimestamp : %s\n", ipmi_timestamp_numeric(guid.time));
+ break;
+ default:
+ printf("\n");
+ }
+
+ return 0;
}
/* ipmi_mc_get_selftest - returns and print selftest results
@@ -559,7 +807,7 @@ static int ipmi_mc_get_selftest(struct ipmi_intf * intf)
if (rsp->ccode) {
lprintf(LOG_ERR, "Bad response: (%s)",
- val2str(rsp->ccode, completion_code_vals));
+ CC_STRING(rsp->ccode));
return -1;
}
@@ -583,7 +831,7 @@ static int ipmi_mc_get_selftest(struct ipmi_intf * intf)
printf(" -> SEL device not accessible\n");
}
if (sft_res->test & IPM_SELFTEST_SDR_ERROR) {
- printf(" -> SDR repository not accesible\n");
+ printf(" -> SDR repository not accessible\n");
}
if (sft_res->test & IPM_SELFTEST_FRU_ERROR) {
printf("FRU device not accessible\n");
@@ -625,6 +873,63 @@ static int ipmi_mc_get_selftest(struct ipmi_intf * intf)
return rv;
}
+struct wdt_string_s {
+ const char *get; /* The name of 'timer use' for `watchdog get` command */
+ const char *set; /* The name of 'timer use' for `watchdog set` command */
+};
+
+
+#define WDTS(g,s) &(const struct wdt_string_s){ (g), (s) }
+
+const struct wdt_string_s *wdt_use[] = {
+ WDTS("Reserved", "none"),
+ WDTS("BIOS FRB2", "frb2"),
+ WDTS("BIOS/POST", "post"),
+ WDTS("OS Load", "osload"),
+ WDTS("SMS/OS", "sms"),
+ WDTS("OEM", "oem"),
+ WDTS("Reserved", NULL),
+ WDTS("Reserved", NULL),
+ NULL
+};
+
+const struct wdt_string_s *wdt_int[] = {
+ WDTS("None", "none"),
+ WDTS("SMI", "smi"),
+ WDTS("NMI/Diagnostic", "nmi"),
+ WDTS("Messaging", "msg"),
+ WDTS("Reserved", NULL),
+ WDTS("Reserved", NULL),
+ WDTS("Reserved", NULL),
+ WDTS("Reserved", NULL),
+ NULL
+};
+
+const struct wdt_string_s *wdt_action[] = {
+ WDTS("No action", "none"),
+ WDTS("Hard Reset", "reset"),
+ WDTS("Power Down", "poweroff"),
+ WDTS("Power Cycle", "cycle"),
+ WDTS("Reserved", NULL),
+ WDTS("Reserved", NULL),
+ WDTS("Reserved", NULL),
+ WDTS("Reserved", NULL),
+ NULL
+};
+
+int find_set_wdt_string(const struct wdt_string_s *w[], const char *s)
+{
+ int val = 0;
+ while (w[val]) {
+ if (!strcmp(s, w[val]->set)) break;
+ ++val;
+ }
+ if (!w[val]) {
+ return -1;
+ }
+ return val;
+}
+
/* ipmi_mc_get_watchdog
*
* @intf: ipmi interface
@@ -632,35 +937,15 @@ static int ipmi_mc_get_selftest(struct ipmi_intf * intf)
* returns 0 on success
* returns -1 on error
*/
-
-const char *wdt_use_string[8] = {
- "Reserved",
- "BIOS FRB2",
- "BIOS/POST",
- "OS Load",
- "SMS/OS",
- "OEM",
- "Reserved",
- "Reserved"
-};
-
-const char *wdt_action_string[8] = {
- "No action",
- "Hard Reset",
- "Power Down",
- "Power Cycle",
- "Reserved",
- "Reserved",
- "Reserved",
- "Reserved"
-};
-
static int
ipmi_mc_get_watchdog(struct ipmi_intf * intf)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
struct ipm_get_watchdog_rsp * wdt_res;
+ double init_cnt;
+ double pres_cnt;
+ size_t i;
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
@@ -668,35 +953,226 @@ ipmi_mc_get_watchdog(struct ipmi_intf * intf)
req.msg.data_len = 0;
rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
+ if (!rsp) {
lprintf(LOG_ERR, "Get Watchdog Timer command failed");
return -1;
}
if (rsp->ccode) {
lprintf(LOG_ERR, "Get Watchdog Timer command failed: %s",
- val2str(rsp->ccode, completion_code_vals));
+ CC_STRING(rsp->ccode));
return -1;
}
wdt_res = (struct ipm_get_watchdog_rsp *) rsp->data;
+ /* Convert 100ms intervals to seconds */
+ init_cnt = (double)ipmi16toh(&wdt_res->init_cnt_le) / 10.0;
+ pres_cnt = (double)ipmi16toh(&wdt_res->pres_cnt_le) / 10.0;
+
printf("Watchdog Timer Use: %s (0x%02x)\n",
- wdt_use_string[(wdt_res->timer_use & 0x07 )], wdt_res->timer_use);
+ wdt_use[IPMI_WDT_GET(wdt_res->use, USE)]->get, wdt_res->use);
printf("Watchdog Timer Is: %s\n",
- wdt_res->timer_use & 0x40 ? "Started/Running" : "Stopped");
- printf("Watchdog Timer Actions: %s (0x%02x)\n",
- wdt_action_string[(wdt_res->timer_actions&0x07)], wdt_res->timer_actions);
+ IS_WDT_BIT(wdt_res->use, USE_RUNNING)
+ ? "Started/Running"
+ : "Stopped");
+ printf("Watchdog Timer Logging: %s\n",
+ IS_WDT_BIT(wdt_res->use, USE_NOLOG)
+ ? "Off"
+ : "On");
+ printf("Watchdog Timer Action: %s (0x%02x)\n",
+ wdt_action[IPMI_WDT_GET(wdt_res->intr_action, ACTION)]->get,
+ wdt_res->intr_action);
+ printf("Pre-timeout interrupt: %s\n",
+ wdt_int[IPMI_WDT_GET(wdt_res->intr_action, INTR)]->get);
printf("Pre-timeout interval: %d seconds\n", wdt_res->pre_timeout);
- printf("Timer Expiration Flags: 0x%02x\n", wdt_res->timer_use_exp);
- printf("Initial Countdown: %i sec\n",
- ((wdt_res->initial_countdown_msb << 8) | wdt_res->initial_countdown_lsb)/10);
- printf("Present Countdown: %i sec\n",
- (((wdt_res->present_countdown_msb << 8) | wdt_res->present_countdown_lsb)) / 10);
+ printf("Timer Expiration Flags: %s(0x%02x)\n",
+ wdt_res->exp_flags ? "" : "None ",
+ wdt_res->exp_flags);
+ for (i = 0; i < sizeof(wdt_res->exp_flags) * CHAR_BIT; ++i) {
+ if (IS_SET(wdt_res->exp_flags, i)) {
+ printf(" * %s\n", wdt_use[i]->get);
+ }
+ }
+ printf("Initial Countdown: %0.1f sec\n", init_cnt);
+ printf("Present Countdown: %0.1f sec\n", pres_cnt);
return 0;
}
+/* Configuration to set with ipmi_mc_set_watchdog() */
+typedef struct ipmi_mc_set_wdt_conf_s {
+ uint16_t timeout;
+ uint8_t pretimeout;
+ uint8_t intr;
+ uint8_t use;
+ uint8_t clear;
+ uint8_t action;
+ bool nolog;
+ bool dontstop;
+} wdt_conf_t;
+
+/* Options parser for ipmi_mc_set_watchdog() */
+static bool
+parse_set_wdt_options(wdt_conf_t *conf, int argc, char *argv[])
+{
+ const int MAX_TIMEOUT = 6553; /* Seconds, makes almost USHRT_MAX when
+ converted to 100ms intervals */
+ const int MAX_PRETIMEOUT = 255; /* Seconds */
+ bool error = true;
+ int i;
+
+ if (!argc || !strcmp(argv[0], "help")) {
+ goto out;
+ }
+
+ for (i = 0; i < argc; ++i) {
+ long val;
+ char *vstr = strchr(argv[i], '=');
+ if (vstr)
+ vstr++; /* Point to the value */
+
+ switch (argv[i][0]) { /* only check the first letter to allow for
+ shortcuts */
+ case 't': /* timeout */
+ val = strtol(vstr, NULL, 10);
+ if (val < 1 || val > MAX_TIMEOUT) {
+ lprintf(LOG_ERR, "Timeout value %lu is out of range (1-%d)\n",
+ val, MAX_TIMEOUT);
+ goto out;
+ }
+ conf->timeout = val * 10; /* Convert seconds to 100ms intervals */
+ break;
+ case 'p': /* pretimeout */
+ val = strtol(vstr, NULL, 10);
+ if (val < 1 || val > MAX_PRETIMEOUT) {
+ lprintf(LOG_ERR,
+ "Pretimeout value %lu is out of range (1-%d)\n",
+ val, MAX_PRETIMEOUT);
+ goto out;
+ }
+ conf->pretimeout = val; /* Convert seconds to 100ms intervals */
+ break;
+ case 'i': /* int */
+ if (0 > (val = find_set_wdt_string(wdt_int, vstr))) {
+ lprintf(LOG_ERR, "Interrupt type '%s' is not valid\n", vstr);
+ goto out;
+ }
+ conf->intr = val;
+ break;
+ case 'u': /* use */
+ if (0 > (val = find_set_wdt_string(wdt_use, vstr))) {
+ lprintf(LOG_ERR, "Use '%s' is not valid\n", vstr);
+ goto out;
+ }
+ conf->use = val;
+ break;
+ case 'a': /* action */
+ if (0 > (val = find_set_wdt_string(wdt_action, vstr))) {
+ lprintf(LOG_ERR, "Use '%s' is not valid\n", vstr);
+ goto out;
+ }
+ conf->action = val;
+ break;
+ case 'c': /* clear */
+ if (0 > (val = find_set_wdt_string(wdt_use, vstr))) {
+ lprintf(LOG_ERR, "Use '%s' is not valid\n", vstr);
+ goto out;
+ }
+ conf->clear |= 1 << val;
+ break;
+ case 'n': /* nolog */
+ conf->nolog = true;
+ break;
+ case 'd': /* dontstop */
+ conf->dontstop = true;
+ break;
+
+ default:
+ lprintf(LOG_ERR, "Invalid option '%s'", argv[i]);
+ break;
+ }
+ }
+
+ error = false;
+
+out:
+ return error;
+}
+
+/* ipmi_mc_set_watchdog
+ *
+ * @intf: ipmi interface
+ * @argc: argument count
+ * @argv: arguments
+ *
+ * returns 0 on success
+ * returns non-zero (-1 or IPMI completion code) on error
+ */
+static int
+ipmi_mc_set_watchdog(struct ipmi_intf * intf, int argc, char *argv[])
+{
+ struct ipmi_rs * rsp;
+ struct ipmi_rq req = {0};
+ unsigned char msg_data[6] = {0};
+ int rc = -1;
+ wdt_conf_t conf = {0};
+ bool options_error = parse_set_wdt_options(&conf, argc, argv);
+
+ /* Fill data bytes according to IPMI 2.0 Spec section 27.6 */
+ msg_data[0] = conf.nolog << IPMI_WDT_USE_NOLOG_SHIFT;
+ msg_data[0] |= conf.dontstop << IPMI_WDT_USE_DONTSTOP_SHIFT;
+ msg_data[0] |= conf.use & IPMI_WDT_USE_MASK;
+
+ msg_data[1] = (conf.intr & IPMI_WDT_INTR_MASK) << IPMI_WDT_INTR_SHIFT;
+ msg_data[1] |= conf.action & IPMI_WDT_ACTION_MASK;
+
+ msg_data[2] = conf.pretimeout;
+
+ msg_data[3] = conf.clear;
+
+ htoipmi16(conf.timeout, &msg_data[4]);
+
+ req.msg.netfn = IPMI_NETFN_APP;
+ req.msg.cmd = BMC_SET_WATCHDOG_TIMER;
+ req.msg.data_len = 6;
+ req.msg.data = msg_data;
+
+ lprintf(LOG_INFO,
+ "Sending Set Watchdog command [%02X %02X %02X %02X %02X %02X]:"
+ , msg_data[0], msg_data[1], msg_data[2]
+ , msg_data[3], msg_data[4], msg_data[5]
+ );
+ lprintf(LOG_INFO, " - nolog = %d", conf.nolog);
+ lprintf(LOG_INFO, " - dontstop = %d", conf.dontstop);
+ lprintf(LOG_INFO, " - use = 0x%02hhX", conf.use);
+ lprintf(LOG_INFO, " - intr = 0x%02hhX", conf.intr);
+ lprintf(LOG_INFO, " - action = 0x%02hhX", conf.action);
+ lprintf(LOG_INFO, " - pretimeout = %hhu", conf.pretimeout);
+ lprintf(LOG_INFO, " - clear = 0x%02hhX", conf.clear);
+ lprintf(LOG_INFO, " - timeout = %hu", conf.timeout);
+
+ rsp = intf->sendrecv(intf, &req);
+ if (!rsp) {
+ lprintf(LOG_ERR, "Set Watchdog Timer command failed");
+ goto out;
+ }
+
+ rc = rsp->ccode;
+ if (rc) {
+ lprintf(LOG_ERR, "Set Watchdog Timer command failed: %s",
+ CC_STRING(rsp->ccode));
+ goto out;
+ }
+
+ lprintf(LOG_NOTICE, "Watchdog Timer was successfully configured");
+
+out:
+ if (options_error) print_watchdog_usage();
+
+ return rc;
+}
+
/* ipmi_mc_shutoff_watchdog
*
* @intf: ipmi interface
@@ -737,14 +1213,14 @@ ipmi_mc_shutoff_watchdog(struct ipmi_intf * intf)
msg_data[5] = 0x0b; /* countdown msb - 5 mins */
rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
+ if (!rsp) {
lprintf(LOG_ERR, "Watchdog Timer Shutoff command failed!");
return -1;
}
if (rsp->ccode) {
lprintf(LOG_ERR, "Watchdog Timer Shutoff command failed! %s",
- val2str(rsp->ccode, completion_code_vals));
+ CC_STRING(rsp->ccode));
return -1;
}
@@ -772,16 +1248,16 @@ ipmi_mc_rst_watchdog(struct ipmi_intf * intf)
req.msg.data_len = 0;
rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL) {
+ if (!rsp) {
lprintf(LOG_ERR, "Reset Watchdog Timer command failed!");
return -1;
}
if (rsp->ccode) {
lprintf(LOG_ERR, "Reset Watchdog Timer command failed: %s",
- (rsp->ccode == IPM_WATCHDOG_RESET_ERROR) ?
- "Attempt to reset uninitialized watchdog" :
- val2str(rsp->ccode, completion_code_vals));
+ (rsp->ccode == IPM_WATCHDOG_RESET_ERROR)
+ ? "Attempt to reset uninitialized watchdog"
+ : CC_STRING(rsp->ccode));
return -1;
}
@@ -808,24 +1284,24 @@ ipmi_mc_main(struct ipmi_intf * intf, int argc, char ** argv)
printf_mc_usage();
rc = (-1);
}
- else if (strncmp(argv[0], "help", 4) == 0) {
+ else if (!strcmp(argv[0], "help")) {
printf_mc_usage();
rc = 0;
}
- else if (strncmp(argv[0], "reset", 5) == 0) {
+ else if (!strcmp(argv[0], "reset")) {
if (argc < 2) {
lprintf(LOG_ERR, "Not enough parameters given.");
printf_mc_reset_usage();
rc = (-1);
}
- else if (strncmp(argv[1], "help", 4) == 0) {
+ else if (!strcmp(argv[1], "help")) {
printf_mc_reset_usage();
rc = 0;
}
- else if (strncmp(argv[1], "cold", 4) == 0) {
+ else if (!strcmp(argv[1], "cold")) {
rc = ipmi_mc_reset(intf, BMC_COLD_RESET);
}
- else if (strncmp(argv[1], "warm", 4) == 0) {
+ else if (!strcmp(argv[1], "warm")) {
rc = ipmi_mc_reset(intf, BMC_WARM_RESET);
}
else {
@@ -834,38 +1310,68 @@ ipmi_mc_main(struct ipmi_intf * intf, int argc, char ** argv)
rc = (-1);
}
}
- else if (strncmp(argv[0], "info", 4) == 0) {
+ else if (!strcmp(argv[0], "info")) {
rc = ipmi_mc_get_deviceid(intf);
}
- else if (strncmp(argv[0], "guid", 4) == 0) {
- rc = ipmi_mc_get_guid(intf);
+ else if (!strcmp(argv[0], "guid")) {
+ ipmi_guid_mode_t guid_mode = GUID_AUTO;
+
+ /* Allow for 'rfc' and 'rfc4122' */
+ if (argc > 1) {
+ if (!strcmp(argv[1], "rfc")) {
+ guid_mode = GUID_RFC4122;
+ }
+ else if (!strcmp(argv[1], "smbios")) {
+ guid_mode = GUID_SMBIOS;
+ }
+ else if (!strcmp(argv[1], "ipmi")) {
+ guid_mode = GUID_IPMI;
+ }
+ else if (!strcmp(argv[1], "auto")) {
+ guid_mode = GUID_AUTO;
+ }
+ else if (!strcmp(argv[1], "dump")) {
+ guid_mode = GUID_DUMP;
+ }
+ }
+ rc = ipmi_mc_print_guid(intf, guid_mode);
}
- else if (strncmp(argv[0], "getenables", 10) == 0) {
+ else if (!strcmp(argv[0], "getenables")) {
rc = ipmi_mc_get_enables(intf);
}
- else if (strncmp(argv[0], "setenables", 10) == 0) {
+ else if (!strcmp(argv[0], "setenables")) {
rc = ipmi_mc_set_enables(intf, argc-1, &(argv[1]));
}
- else if (!strncmp(argv[0], "selftest", 8)) {
+ else if (!strcmp(argv[0], "selftest")) {
rc = ipmi_mc_get_selftest(intf);
}
- else if (!strncmp(argv[0], "watchdog", 8)) {
+ else if (!strcmp(argv[0], "watchdog")) {
if (argc < 2) {
lprintf(LOG_ERR, "Not enough parameters given.");
print_watchdog_usage();
rc = (-1);
}
- else if (strncmp(argv[1], "help", 4) == 0) {
+ else if (!strcmp(argv[1], "help")) {
print_watchdog_usage();
rc = 0;
}
- else if (strncmp(argv[1], "get", 3) == 0) {
+ else if (!strcmp(argv[1], "set")) {
+ if (argc < 3) { /* Requires options */
+ lprintf(LOG_ERR, "Not enough parameters given.");
+ print_watchdog_usage();
+ rc = (-1);
+ }
+ else {
+ rc = ipmi_mc_set_watchdog(intf, argc - 2, &(argv[2]));
+ }
+ }
+ else if (!strcmp(argv[1], "get")) {
rc = ipmi_mc_get_watchdog(intf);
}
- else if(strncmp(argv[1], "off", 3) == 0) {
+ else if (!strcmp(argv[1], "off")) {
rc = ipmi_mc_shutoff_watchdog(intf);
}
- else if(strncmp(argv[1], "reset", 5) == 0) {
+ else if (!strcmp(argv[1], "reset")) {
rc = ipmi_mc_rst_watchdog(intf);
}
else {
@@ -874,10 +1380,10 @@ ipmi_mc_main(struct ipmi_intf * intf, int argc, char ** argv)
rc = (-1);
}
}
- else if (strncmp(argv[0], "getsysinfo", 10) == 0) {
+ else if (!strcmp(argv[0], "getsysinfo")) {
rc = ipmi_sysinfo_main(intf, argc, argv, 0);
}
- else if (strncmp(argv[0], "setsysinfo", 10) == 0) {
+ else if (!strcmp(argv[0], "setsysinfo")) {
rc = ipmi_sysinfo_main(intf, argc, argv, 1);
}
else {
@@ -969,10 +1475,10 @@ ipmi_mc_getsysinfo(struct ipmi_intf * intf, int param, int block, int set,
* u8 data0[14]
*/
rsp = intf->sendrecv(intf, &req);
- if (rsp == NULL)
+ if (!rsp)
return (-1);
- if (rsp->ccode == 0) {
+ if (!rsp->ccode) {
if (len > rsp->data_len)
len = rsp->data_len;
if (len && buffer)
@@ -1011,7 +1517,7 @@ ipmi_mc_setsysinfo(struct ipmi_intf * intf, int len, void *buffer)
* u8 data1[16]
*/
rsp = intf->sendrecv(intf, &req);
- if (rsp != NULL) {
+ if (rsp) {
return rsp->ccode;
}
return -1;
@@ -1022,10 +1528,10 @@ ipmi_sysinfo_main(struct ipmi_intf *intf, int argc, char ** argv, int is_set)
{
char *str;
unsigned char infostr[256];
- unsigned char paramdata[18];
+ char paramdata[18];
int len, maxset, param, pos, rc, set;
- if (argc == 2 && strcmp(argv[1], "help") == 0) {
+ if (argc == 2 && !strcmp(argv[1], "help")) {
printf_sysinfo_usage(1);
return 0;
}
@@ -1109,7 +1615,7 @@ ipmi_sysinfo_main(struct ipmi_intf *intf, int argc, char ** argv, int is_set)
}
else if (rc > 0) {
lprintf(LOG_ERR, "%s command failed: %s", argv[0],
- val2str(rc, completion_code_vals));
+ CC_STRING(rc));
}
return rc;
}