diff options
Diffstat (limited to 'lib/ipmi_mc.c')
-rw-r--r-- | lib/ipmi_mc.c | 774 |
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; } |