/* * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #define _XOPEN_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const struct valstr sunoem_led_type_vals[] = { { 0, "OK2RM" }, { 1, "SERVICE" }, { 2, "ACT" }, { 3, "LOCATE" }, { 0xFF, NULL }, }; static const struct valstr sunoem_led_mode_vals[] = { { 0, "OFF" }, { 1, "ON" }, { 2, "STANDBY" }, { 3, "SLOW" }, { 4, "FAST" }, { 0xFF, NULL }, }; static const struct valstr sunoem_led_mode_optvals[] = { { 0, "STEADY_OFF" }, { 1, "STEADY_ON" }, { 2, "STANDBY_BLINK" }, { 3, "SLOW_BLINK" }, { 4, "FAST_BLINK" }, { 0xFF, NULL }, }; #define SUNOEM_SUCCESS 1 #define IPMI_SUNOEM_GETFILE_VERSION {3,2,0,0} #define IPMI_SUNOEM_GETBEHAVIOR_VERSION {3,2,0,0} /* * PRINT_NORMAL: print out the LED value as normal * PRINT_ERROR: print out "na" for the LED value */ typedef enum { PRINT_NORMAL = 0, PRINT_ERROR } print_status_t; int ret_get = 0; int ret_set = 0; static void ipmi_sunoem_usage(void) { lprintf(LOG_NOTICE, "Usage: sunoem [option...]"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, "Commands:"); lprintf(LOG_NOTICE, " - cli [ ...]"); lprintf(LOG_NOTICE, " Execute SP CLI commands."); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - led get [] [ledtype]"); lprintf(LOG_NOTICE, " - Read status of LED found in Generic Device Locator."); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - led set [led_type]"); lprintf(LOG_NOTICE, " - Set mode of LED found in Generic Device Locator."); lprintf(LOG_NOTICE, " - You can pass 'all' as the to change the LED mode of all sensors."); lprintf(LOG_NOTICE, " - Use 'sdr list generic' command to get list of Generic"); lprintf(LOG_NOTICE, " - Devices that are controllable LEDs."); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - Required SIS LED Mode:"); lprintf(LOG_NOTICE, " OFF Off"); lprintf(LOG_NOTICE, " ON Steady On"); lprintf(LOG_NOTICE, " STANDBY 100ms on 2900ms off blink rate"); lprintf(LOG_NOTICE, " SLOW 1HZ blink rate"); lprintf(LOG_NOTICE, " FAST 4HZ blink rate"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - Optional SIS LED Type:"); lprintf(LOG_NOTICE, " OK2RM OK to Remove"); lprintf(LOG_NOTICE, " SERVICE Service Required"); lprintf(LOG_NOTICE, " ACT Activity"); lprintf(LOG_NOTICE, " LOCATE Locate"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - nacname "); lprintf(LOG_NOTICE, " - Returns the full nac name"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - ping NUMBER "); lprintf(LOG_NOTICE, " - Send and Receive NUMBER (64 Byte) packets."); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - q - Quiet. Displays output at start and end"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - getval "); lprintf(LOG_NOTICE, " - Returns the ILOM property value"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - setval "); lprintf(LOG_NOTICE, " - Sets the ILOM property value"); lprintf(LOG_NOTICE, " - If timeout is not specified, the default is 5 sec."); lprintf(LOG_NOTICE, " - NOTE: must be executed locally on host, not remotely over LAN!"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - sshkey del "); lprintf(LOG_NOTICE, " - Delete ssh key for user id from authorized_keys,"); lprintf(LOG_NOTICE, " - view users with 'user list' command."); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - sshkey set "); lprintf(LOG_NOTICE, " - Set ssh key for a userid into authorized_keys,"); lprintf(LOG_NOTICE, " - view users with 'user list' command."); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - version"); lprintf(LOG_NOTICE, " - Display the software version"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - nacname "); lprintf(LOG_NOTICE, " - Returns the full nac name"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - getfile "); lprintf(LOG_NOTICE, " - Copy file to "); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - File string ids:"); lprintf(LOG_NOTICE, " SSH_PUBKEYS"); lprintf(LOG_NOTICE, " DIAG_PASSED"); lprintf(LOG_NOTICE, " DIAG_FAILED"); lprintf(LOG_NOTICE, " DIAG_END_TIME"); lprintf(LOG_NOTICE, " DIAG_INVENTORY"); lprintf(LOG_NOTICE, " DIAG_TEST_LOG"); lprintf(LOG_NOTICE, " DIAG_START_TIME"); lprintf(LOG_NOTICE, " DIAG_UEFI_LOG"); lprintf(LOG_NOTICE, " DIAG_TEST_LOG"); lprintf(LOG_NOTICE, " DIAG_LAST_LOG"); lprintf(LOG_NOTICE, " DIAG_LAST_CMD"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - getbehavior "); lprintf(LOG_NOTICE, " - Test if ILOM behavior is enabled"); lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, " - Behavior string ids:"); lprintf(LOG_NOTICE, " SUPPORTS_SIGNED_PACKAGES"); lprintf(LOG_NOTICE, " REQUIRES_SIGNED_PACKAGES"); lprintf(LOG_NOTICE, ""); } #define SUNOEM_FAN_MODE_AUTO 0x00 #define SUNOEM_FAN_MODE_MANUAL 0x01 static void __sdr_list_empty(struct sdr_record_list * head) { struct sdr_record_list * e, *f; for (e = head; e != NULL; e = f) { f = e->next; free(e); } head = NULL; } /* * led_print * Print out the led name and the state, if stat is PRINT_NORMAL. * Otherwise, print out the led name and "na". * The state parameter is not referenced if stat is not PRINT_NORMAL. */ static void led_print(const char * name, print_status_t stat, uint8_t state) { const char *theValue; if (stat == PRINT_NORMAL) { theValue = val2str(state, sunoem_led_mode_vals); } else { theValue = "na"; } if (csv_output) { printf("%s,%s\n", name, theValue); } else { printf("%-16s | %s\n", name, theValue); } } #define CC_NORMAL 0x00 #define CC_PARAM_OUT_OF_RANGE 0xc9 #define CC_DEST_UNAVAILABLE 0xd3 #define CC_UNSPECIFIED_ERR 0xff #define CC_INSUFFICIENT_PRIVILEGE 0xd4 #define CC_INV_CMD 0xc1 #define CC_INV_DATA_FIELD 0xcc /* * sunoem_led_get(....) * * OUTPUT: * SUNOEM_EC_INVALID_ARG if dev is NULL, * SUNOEM_EC_BMC_NOT_RESPONDING if no reply is obtained from BMC, * SUNOEM_EC_BMC_CCODE_NONZERO if completion code is nonzero, * SUNOEM_EC_SUCCESS otherwise. */ static sunoem_ec_t sunoem_led_get(struct ipmi_intf * intf, struct sdr_record_generic_locator * dev, int ledtype, struct ipmi_rs **loc_rsp) { struct ipmi_rs * rsp; struct ipmi_rq req; uint8_t rqdata[7]; int rqdata_len; if (dev == NULL) { *loc_rsp = NULL; return (SUNOEM_EC_INVALID_ARG); } rqdata[0] = dev->dev_slave_addr; if (ledtype == 0xFF) rqdata[1] = dev->oem; else rqdata[1] = ledtype; rqdata[2] = dev->dev_access_addr; rqdata[3] = dev->oem; rqdata[4] = dev->entity.id; rqdata[5] = dev->entity.instance; rqdata[6] = 0; rqdata_len = 7; req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_LED_GET; req.msg.lun = dev->lun; req.msg.data = rqdata; req.msg.data_len = rqdata_len; rsp = intf->sendrecv(intf, &req); /* * Just return NULL if there was * an error. */ if (rsp == NULL) { *loc_rsp = NULL; return (SUNOEM_EC_BMC_NOT_RESPONDING); } else if (rsp->ccode > 0) { *loc_rsp = rsp; return (SUNOEM_EC_BMC_CCODE_NONZERO); } else { *loc_rsp = rsp; return (SUNOEM_EC_SUCCESS); } } static struct ipmi_rs * sunoem_led_set(struct ipmi_intf * intf, struct sdr_record_generic_locator * dev, int ledtype, int ledmode) { struct ipmi_rs * rsp; struct ipmi_rq req; uint8_t rqdata[9]; int rqdata_len; if (dev == NULL) return NULL; rqdata[0] = dev->dev_slave_addr; if (ledtype == 0xFF) rqdata[1] = dev->oem; else rqdata[1] = ledtype; rqdata[2] = dev->dev_access_addr; rqdata[3] = dev->oem; rqdata[4] = ledmode; rqdata[5] = dev->entity.id; rqdata[6] = dev->entity.instance; rqdata[7] = 0; rqdata[8] = 0; rqdata_len = 9; req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_LED_SET; req.msg.lun = dev->lun; req.msg.data = rqdata; req.msg.data_len = rqdata_len; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM Set LED command failed."); return NULL; } else if (rsp->ccode > 0) { lprintf(LOG_ERR, "Sun OEM Set LED command failed: %s", val2str(rsp->ccode, completion_code_vals)); return NULL; } return (rsp); } static void sunoem_led_get_byentity(struct ipmi_intf * intf, uint8_t entity_id, uint8_t entity_inst, int ledtype) { struct ipmi_rs * rsp; struct sdr_record_list *elist, *e; struct entity_id entity; sunoem_ec_t res; if (entity_id == 0) return; /* lookup sdrs with this entity */ memset(&entity, 0, sizeof(struct entity_id)); entity.id = entity_id; entity.instance = entity_inst; elist = ipmi_sdr_find_sdr_byentity(intf, &entity); if (elist == NULL) ret_get = -1; /* for each generic sensor get its led state */ for (e = elist; e != NULL; e = e->next) { if (e->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) continue; res = sunoem_led_get(intf, e->record.genloc, ledtype, &rsp); if (res == SUNOEM_EC_SUCCESS && rsp && rsp->data_len == 1) { led_print((const char *) e->record.genloc->id_string, PRINT_NORMAL, rsp->data[0]); } else { led_print((const char *) e->record.genloc->id_string, PRINT_ERROR, 0); if (res != SUNOEM_EC_BMC_CCODE_NONZERO|| !rsp || rsp->ccode != CC_DEST_UNAVAILABLE) { ret_get = -1; } } } __sdr_list_empty(elist); } static void sunoem_led_set_byentity(struct ipmi_intf * intf, uint8_t entity_id, uint8_t entity_inst, int ledtype, int ledmode) { struct ipmi_rs * rsp; struct sdr_record_list *elist, *e; struct entity_id entity; if (entity_id == 0) return; /* lookup sdrs with this entity */ memset(&entity, 0, sizeof(struct entity_id)); entity.id = entity_id; entity.instance = entity_inst; elist = ipmi_sdr_find_sdr_byentity(intf, &entity); if (elist == NULL) ret_set = -1; /* for each generic sensor set its led state */ for (e = elist; e != NULL; e = e->next) { if (e->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) continue; rsp = sunoem_led_set(intf, e->record.genloc, ledtype, ledmode); if (rsp && rsp->data_len == 0) { led_print((const char *) e->record.genloc->id_string, PRINT_NORMAL, ledmode); } else if (rsp == NULL) { ret_set = -1; } } __sdr_list_empty(elist); } /* * IPMI Request Data: 5 bytes * * [byte 0] devAddr Value from the "Device Slave Address" field in * LED's Generic Device Locator record in the SDR * [byte 1] led LED Type: OK2RM, ACT, LOCATE, SERVICE * [byte 2] ctrlrAddr Controller address; value from the "Device * Access Address" field, 0x20 if the LED is local * [byte 3] hwInfo The OEM field from the SDR record * [byte 4] force 1 = directly access the device * 0 = go thru its controller * Ignored if LED is local * * The format below is for Sun Blade Modular systems only * [byte 4] entityID The entityID field from the SDR record * [byte 5] entityIns The entityIns field from the SDR record * [byte 6] force 1 = directly access the device * 0 = go thru its controller * Ignored if LED is local */ static int ipmi_sunoem_led_get(struct ipmi_intf * intf, int argc, char ** argv) { struct ipmi_rs * rsp; struct sdr_record_list *sdr; struct sdr_record_list *alist, *a; struct sdr_record_entity_assoc *assoc; int ledtype = 0xFF; int i; sunoem_ec_t res; /* * sunoem led/sbled get [type] */ if (argc < 1 || strncmp(argv[0], "help", 4) == 0) { ipmi_sunoem_usage(); return (0); } if (argc > 1) { ledtype = str2val(argv[1], sunoem_led_type_vals); if (ledtype == 0xFF) lprintf(LOG_ERR, "Unknown ledtype, will use data from the SDR oem field"); } if (strncasecmp(argv[0], "all", 3) == 0) { /* do all generic sensors */ alist = ipmi_sdr_find_sdr_bytype(intf, SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR); if (alist == NULL) return (-1); for (a = alist; a != NULL; a = a->next) { if (a->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) continue; if (a->record.genloc->entity.logical) continue; res = sunoem_led_get(intf, a->record.genloc, ledtype, &rsp); if (res == SUNOEM_EC_SUCCESS && rsp && rsp->data_len == 1) { led_print((const char *) a->record.genloc->id_string, PRINT_NORMAL, rsp->data[0]); } else { led_print((const char *) a->record.genloc->id_string, PRINT_ERROR, 0); if (res != SUNOEM_EC_BMC_CCODE_NONZERO|| !rsp || rsp->ccode != CC_DEST_UNAVAILABLE) { ret_get = -1; } } } __sdr_list_empty(alist); if (ret_get == -1) return (-1); return (0); } /* look up generic device locator record in SDR */ sdr = ipmi_sdr_find_sdr_byid(intf, argv[0]); if (sdr == NULL) { lprintf(LOG_ERR, "No Sensor Data Record found for %s", argv[0]); return (-1); } if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) { lprintf(LOG_ERR, "Invalid SDR type %d", sdr->type); return (-1); } if (!sdr->record.genloc->entity.logical) { /* * handle physical entity */ res = sunoem_led_get(intf, sdr->record.genloc, ledtype, &rsp); if (res == SUNOEM_EC_SUCCESS && rsp && rsp->data_len == 1) { led_print((const char *) sdr->record.genloc->id_string, PRINT_NORMAL, rsp->data[0]); } else { led_print((const char *) sdr->record.genloc->id_string, PRINT_ERROR, 0); if (res != SUNOEM_EC_BMC_CCODE_NONZERO|| !rsp || rsp->ccode != CC_DEST_UNAVAILABLE) { ret_get = -1; } } if (ret_get == -1) return (-1); return (0); } /* * handle logical entity for LED grouping */ lprintf(LOG_INFO, "LED %s is logical device", argv[0]); /* get entity assoc records */ alist = ipmi_sdr_find_sdr_bytype(intf, SDR_RECORD_TYPE_ENTITY_ASSOC); if (alist == NULL) return (-1); for (a = alist; a != NULL; a = a->next) { if (a->type != SDR_RECORD_TYPE_ENTITY_ASSOC) continue; assoc = a->record.entassoc; if (assoc == NULL) continue; /* check that the entity id/instance matches our generic record */ if (assoc->entity.id != sdr->record.genloc->entity.id || assoc->entity.instance != sdr->record.genloc->entity.instance) continue; if (assoc->flags.isrange) { /* * handle ranged entity associations * * the test for non-zero entity id is handled in * sunoem_led_get_byentity() */ /* first range set - id 1 and 2 must be equal */ if (assoc->entity_id_1 == assoc->entity_id_2) for (i = assoc->entity_inst_1; i <= assoc->entity_inst_2; i++) sunoem_led_get_byentity(intf, assoc->entity_id_1, i, ledtype); /* second range set - id 3 and 4 must be equal */ if (assoc->entity_id_3 == assoc->entity_id_4) for (i = assoc->entity_inst_3; i <= assoc->entity_inst_4; i++) sunoem_led_get_byentity(intf, assoc->entity_id_3, i, ledtype); } else { /* * handle entity list */ sunoem_led_get_byentity(intf, assoc->entity_id_1, assoc->entity_inst_1, ledtype); sunoem_led_get_byentity(intf, assoc->entity_id_2, assoc->entity_inst_2, ledtype); sunoem_led_get_byentity(intf, assoc->entity_id_3, assoc->entity_inst_3, ledtype); sunoem_led_get_byentity(intf, assoc->entity_id_4, assoc->entity_inst_4, ledtype); } } __sdr_list_empty(alist); if (ret_get == -1) return (-1); return (0); } /* * IPMI Request Data: 7 bytes * * [byte 0] devAddr Value from the "Device Slave Address" field in * LED's Generic Device Locator record in the SDR * [byte 1] led LED Type: OK2RM, ACT, LOCATE, SERVICE * [byte 2] ctrlrAddr Controller address; value from the "Device * Access Address" field, 0x20 if the LED is local * [byte 3] hwInfo The OEM field from the SDR record * [byte 4] mode LED Mode: OFF, ON, STANDBY, SLOW, FAST * [byte 5] force TRUE - directly access the device * FALSE - go thru its controller * Ignored if LED is local * [byte 6] role Used by BMC for authorization purposes * * The format below is for Sun Blade Modular systems only * [byte 5] entityID The entityID field from the SDR record * [byte 6] entityIns The entityIns field from the SDR record * [byte 7] force TRUE - directly access the device * FALSE - go thru its controller * Ignored if LED is local * [byte 8] role Used by BMC for authorization purposes * * * IPMI Response Data: 1 byte * * [byte 0] mode LED Mode: OFF, ON, STANDBY, SLOW, FAST */ static int ipmi_sunoem_led_set(struct ipmi_intf * intf, int argc, char ** argv) { struct ipmi_rs * rsp; struct sdr_record_list *sdr; struct sdr_record_list *alist, *a; struct sdr_record_entity_assoc *assoc; int ledmode; int ledtype = 0xFF; int i; /* * sunoem led/sbled set [type] */ if (argc < 2 || strncmp(argv[0], "help", 4) == 0) { ipmi_sunoem_usage(); return (0); } ledmode = str2val(argv[1], sunoem_led_mode_vals); if (ledmode == 0xFF) { ledmode = str2val(argv[1], sunoem_led_mode_optvals); if (ledmode == 0xFF) { lprintf(LOG_NOTICE, "Invalid LED Mode: %s", argv[1]); return (-1); } } if (argc > 3) { ledtype = str2val(argv[2], sunoem_led_type_vals); if (ledtype == 0xFF) lprintf(LOG_ERR, "Unknown ledtype, will use data from the SDR oem field"); } if (strncasecmp(argv[0], "all", 3) == 0) { /* do all generic sensors */ alist = ipmi_sdr_find_sdr_bytype(intf, SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR); if (alist == NULL) return (-1); for (a = alist; a != NULL; a = a->next) { if (a->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) continue; if (a->record.genloc->entity.logical) continue; rsp = sunoem_led_set(intf, a->record.genloc, ledtype, ledmode); if (rsp && rsp->ccode == 0) led_print((const char *) a->record.genloc->id_string, PRINT_NORMAL, ledmode); else ret_set = -1; } __sdr_list_empty(alist); if (ret_set == -1) return (-1); return (0); } /* look up generic device locator records in SDR */ sdr = ipmi_sdr_find_sdr_byid(intf, argv[0]); if (sdr == NULL) { lprintf(LOG_ERR, "No Sensor Data Record found for %s", argv[0]); return (-1); } if (sdr->type != SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR) { lprintf(LOG_ERR, "Invalid SDR type %d", sdr->type); return (-1); } if (!sdr->record.genloc->entity.logical) { /* * handle physical entity */ rsp = sunoem_led_set(intf, sdr->record.genloc, ledtype, ledmode); if (rsp && rsp->ccode == 0) led_print(argv[0], PRINT_NORMAL, ledmode); else return (-1); return (0); } /* * handle logical entity for LED grouping */ lprintf(LOG_INFO, "LED %s is logical device", argv[0]); /* get entity assoc records */ alist = ipmi_sdr_find_sdr_bytype(intf, SDR_RECORD_TYPE_ENTITY_ASSOC); if (alist == NULL) return (-1); for (a = alist; a != NULL; a = a->next) { if (a->type != SDR_RECORD_TYPE_ENTITY_ASSOC) continue; assoc = a->record.entassoc; if (assoc == NULL) continue; /* check that the entity id/instance matches our generic record */ if (assoc->entity.id != sdr->record.genloc->entity.id || assoc->entity.instance != sdr->record.genloc->entity.instance) continue; if (assoc->flags.isrange) { /* * handle ranged entity associations * * the test for non-zero entity id is handled in * sunoem_led_get_byentity() */ /* first range set - id 1 and 2 must be equal */ if (assoc->entity_id_1 == assoc->entity_id_2) for (i = assoc->entity_inst_1; i <= assoc->entity_inst_2; i++) sunoem_led_set_byentity(intf, assoc->entity_id_1, i, ledtype, ledmode); /* second range set - id 3 and 4 must be equal */ if (assoc->entity_id_3 == assoc->entity_id_4) for (i = assoc->entity_inst_3; i <= assoc->entity_inst_4; i++) sunoem_led_set_byentity(intf, assoc->entity_id_3, i, ledtype, ledmode); } else { /* * handle entity list */ sunoem_led_set_byentity(intf, assoc->entity_id_1, assoc->entity_inst_1, ledtype, ledmode); sunoem_led_set_byentity(intf, assoc->entity_id_2, assoc->entity_inst_2, ledtype, ledmode); sunoem_led_set_byentity(intf, assoc->entity_id_3, assoc->entity_inst_3, ledtype, ledmode); sunoem_led_set_byentity(intf, assoc->entity_id_4, assoc->entity_inst_4, ledtype, ledmode); } } __sdr_list_empty(alist); if (ret_set == -1) return (-1); return (0); } static int ipmi_sunoem_sshkey_del(struct ipmi_intf * intf, uint8_t uid) { struct ipmi_rs * rsp; struct ipmi_rq req; memset(&req, 0, sizeof(struct ipmi_rq)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_DEL_SSH_KEY; req.msg.data = &uid; req.msg.data_len = 1; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Unable to delete ssh key for UID %d", uid); return (-1); } else if (rsp->ccode > 0) { lprintf(LOG_ERR, "Unable to delete ssh key for UID %d: %s", uid, val2str(rsp->ccode, completion_code_vals)); return (-1); } printf("Deleted SSH key for user id %d\n", uid); return (0); } #define SSHKEY_BLOCK_SIZE 64 static int ipmi_sunoem_sshkey_set(struct ipmi_intf * intf, uint8_t uid, char * ifile) { struct ipmi_rs * rsp; struct ipmi_rq req; FILE * fp; int count = 0; uint8_t wbuf[SSHKEY_BLOCK_SIZE + 3]; int32_t i_size = 0; int32_t r = 0; int32_t size = 0; if (ifile == NULL) { lprintf(LOG_ERR, "Invalid or misisng input filename."); return (-1); } fp = ipmi_open_file_read(ifile); if (fp == NULL) { lprintf(LOG_ERR, "Unable to open file '%s' for reading.", ifile); return (-1); } memset(&req, 0, sizeof(struct ipmi_rq)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_SET_SSH_KEY; req.msg.data = wbuf; if (fseek(fp, 0, SEEK_END) == (-1)) { lprintf(LOG_ERR, "Failed to seek in file '%s'.", ifile); if (fp != NULL) fclose(fp); return (-1); } size = (int32_t) ftell(fp); if (size < 0) { lprintf(LOG_ERR, "Failed to seek in file '%s'.", ifile); if (fp != NULL) fclose(fp); return (-1); } else if (size == 0) { lprintf(LOG_ERR, "File '%s' is empty.", ifile); if (fp != NULL) fclose(fp); return (-1); } if (fseek(fp, 0, SEEK_SET) == (-1)) { lprintf(LOG_ERR, "Failed to seek in file '%s'.", ifile); if (fp != NULL) fclose(fp); return (-1); } printf("Setting SSH key for user id %d...", uid); for (r = 0; r < size; r += i_size) { i_size = size - r; if (i_size > SSHKEY_BLOCK_SIZE) i_size = SSHKEY_BLOCK_SIZE; memset(wbuf, 0, SSHKEY_BLOCK_SIZE); fseek(fp, r, SEEK_SET); count = fread(wbuf + 3, 1, i_size, fp); if (count != i_size) { printf("failed\n"); lprintf(LOG_ERR, "Unable to read %ld bytes from file '%s'.", i_size, ifile); if (fp != NULL) fclose(fp); return (-1); } printf("."); fflush(stdout); wbuf[0] = uid; if ((r + SSHKEY_BLOCK_SIZE) >= size) wbuf[1] = 0xff; else { if ((r / SSHKEY_BLOCK_SIZE) > UINT8_MAX) { printf("failed\n"); lprintf(LOG_ERR, "Unable to pack byte %ld from file '%s'.", r, ifile); if (fp != NULL) fclose(fp); return (-1); } wbuf[1] = (uint8_t) (r / SSHKEY_BLOCK_SIZE); } wbuf[2] = (uint8_t) i_size; req.msg.data_len = i_size + 3; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { printf("failed\n"); lprintf(LOG_ERR, "Unable to set ssh key for UID %d.", uid); if (fp != NULL) fclose(fp); return (-1); } /* if (rsp == NULL) */ if (rsp->ccode != 0) { printf("failed\n"); lprintf(LOG_ERR, "Unable to set ssh key for UID %d, %s.", uid, val2str(rsp->ccode, completion_code_vals)); if (fp != NULL) fclose(fp); return (-1); } /* if (rsp->ccode != 0) */ } printf("done\n"); fclose(fp); return (0); } /* * This structure is used in both the request to and response from the BMC. */ #define SUNOEM_CLI_LEGACY_VERSION 1 #define SUNOEM_CLI_SEQNUM_VERSION 2 #define SUNOEM_CLI_VERSION SUNOEM_CLI_SEQNUM_VERSION #define SUNOEM_CLI_HEADER 8 /* command + spare + handle */ #define SUNOEM_CLI_BUF_SIZE (80 - SUNOEM_CLI_HEADER) /* Total 80 bytes */ #define SUNOEM_CLI_MSG_SIZE(msg) (SUNOEM_CLI_HEADER + strlen((msg).buf) + 1) #ifdef HAVE_PRAGMA_PACK #pragma pack(push, 1) #endif typedef struct { /* * Set version to SUNOEM_CLI_VERSION. */ uint8_t version; /* * The command in a request, or in a response indicates an error if * non-zero. */ uint8_t command_response; uint8_t seqnum; uint8_t spare; /* * Opaque 4-byte handle, supplied in the response to an OPEN request, * and used in all subsequent POLL and CLOSE requests. */ uint8_t handle[4]; /* * The client data in a request, or the server data in a response. Must * by null terminated, i.e., it must be at least one byte, but can be * smaller if there's less data. */ char buf[SUNOEM_CLI_BUF_SIZE]; }__attribute__((packed)) sunoem_cli_msg_t; #ifdef HAVE_PRAGMA_PACK #pragma pack(pop) #endif /* * Command codes for the command_request field in each request. */ #define SUNOEM_CLI_CMD_OPEN 0 /* Open a new connection */ #define SUNOEM_CLI_CMD_FORCE 1 /* Close any existing connection, then open */ #define SUNOEM_CLI_CMD_CLOSE 2 /* Close the current connection */ #define SUNOEM_CLI_CMD_POLL 3 /* Poll for new data to/from the server */ #define SUNOEM_CLI_CMD_EOF 4 /* Poll, client is out of data */ #define SUNOEM_CLI_MAX_RETRY 3 /* Maximum number of retries */ #define SUNOEM_CLI_INVALID_VER_ERR "Invalid version" #define SUNOEM_CLI_BUSY_ERR "Busy" typedef enum { C_CTL_B = 0x02, /* same as left arrow */ C_CTL_C = 0x03, C_CTL_D = 0x04, C_CTL_F = 0x06, /* same as right arrow */ C_CTL_N = 0x0E, /* same as down arrow */ C_CTL_P = 0x10, /* same as up arrow */ C_DEL = 0x7f } canon_char_t; static int sunoem_cli_unbufmode_start(FILE *f, struct termios *orig_ts) { struct termios ts; int rc; if ((rc = tcgetattr(fileno(f), &ts))) { return (rc); } *orig_ts = ts; ts.c_lflag &= ~(ICANON | ECHO | ISIG); ts.c_cc[VMIN] = 1; if ((rc = tcsetattr(fileno(f), TCSAFLUSH, &ts))) { return (rc); } return (0); } static int sunoem_cli_unbufmode_stop(FILE *f, struct termios *ts) { int rc; if ((rc = tcsetattr(fileno(f), TCSAFLUSH, ts))) { return (rc); } return (0); } static int ipmi_sunoem_cli(struct ipmi_intf * intf, int argc, char *argv[]) { struct ipmi_rs *rsp; struct ipmi_rq req; sunoem_cli_msg_t cli_req; sunoem_cli_msg_t *cli_rsp; int arg_num = 0; int arg_pos = 0; time_t wait_time = 0; int retries; static uint8_t SunOemCliActingVersion = SUNOEM_CLI_VERSION; unsigned short first_char = 0; /*first char on the line*/ struct termios orig_ts; int error = 0; time_t now = 0; int delay = 0; /* Prepare to open an SP shell session */ memset(&cli_req, 0, sizeof(cli_req)); cli_req.version = SunOemCliActingVersion; cli_req.command_response = SUNOEM_CLI_CMD_OPEN; if (argc > 0 && strcmp(argv[0], "force") == 0) { cli_req.command_response = SUNOEM_CLI_CMD_FORCE; argc--; argv++; } memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_CLI; req.msg.data = (uint8_t *) &cli_req; req.msg.data_len = SUNOEM_CLI_HEADER + 1; retries = 0; while (1) { cli_req.version = SunOemCliActingVersion; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM cli command failed"); return (-1); } cli_rsp = (sunoem_cli_msg_t *) rsp->data; if ((cli_rsp->command_response != 0) || (rsp->ccode != 0)) { if (strncmp(cli_rsp->buf, SUNOEM_CLI_INVALID_VER_ERR, sizeof(SUNOEM_CLI_INVALID_VER_ERR) - 1) == 0 || strncmp(&(cli_rsp->buf[1]), SUNOEM_CLI_INVALID_VER_ERR, sizeof(SUNOEM_CLI_INVALID_VER_ERR) - 1) == 0) { if (SunOemCliActingVersion == SUNOEM_CLI_VERSION) { /* Server doesn't support version SUNOEM_CLI_VERSION Fall back to legacy version, and try again*/ SunOemCliActingVersion = SUNOEM_CLI_LEGACY_VERSION; continue; } /* Server doesn't support legacy version either */ lprintf(LOG_ERR, "Failed to connect: %s", cli_rsp->buf); return (-1); } else if (strncmp(cli_rsp->buf, SUNOEM_CLI_BUSY_ERR, sizeof(SUNOEM_CLI_BUSY_ERR) - 1) == 0) { if (retries++ < SUNOEM_CLI_MAX_RETRY) { lprintf(LOG_INFO, "Failed to connect: %s, retrying", cli_rsp->buf); sleep(2); continue; } lprintf(LOG_ERR, "Failed to connect: %s", cli_rsp->buf); return (-1); } else { lprintf(LOG_ERR, "Failed to connect: %s", cli_rsp->buf); return (-1); } } break; } if (SunOemCliActingVersion == SUNOEM_CLI_SEQNUM_VERSION) { /* * Bit 1 of seqnum is used as an alternating sequence number * to allow a server that supports it to detect when a retry is being sent from the host IPMI driver. * Typically when this occurs, the server's last response message would have been dropped. * Once the server detects this condition, it will know that it should retry sending the response. */ cli_req.seqnum ^= 0x1; } printf("Connected. Use ^D to exit.\n"); fflush(NULL); /* * Remember the handle provided in the response, and issue a * series of "poll" commands to send and get data */ memcpy(cli_req.handle, cli_rsp->handle, 4); cli_req.command_response = SUNOEM_CLI_CMD_POLL; /* * If no arguments make input unbuffered and so interactive */ if (argc == 0) { if (sunoem_cli_unbufmode_start(stdin, &orig_ts)) { lprintf(LOG_ERR, "Failed to set interactive mode: %s", strerror(errno)); return (-1); } } while (rsp->ccode == 0 && cli_rsp->command_response == 0) { int rc = 0; int count = 0; cli_req.buf[0] = '\0'; if (argc == 0) { /* * Accept input from stdin. Use select so we don't hang if * there's no input to read. Select timeout is 500 msec. */ struct timeval tv = { 0, 500000 }; /* 500 msec */ fd_set rfds; FD_ZERO(&rfds); FD_SET(0, &rfds); rc = select(1, &rfds, NULL, NULL, &tv); if (rc < 0) { /* Select returned an error so close and exit */ printf("Broken pipe\n"); cli_req.command_response = SUNOEM_CLI_CMD_CLOSE; } else if (rc > 0) { /* Read data from stdin */ count = read(0, cli_req.buf, 1 /* sizeof (cli_req.buf) - 1 */); /* * If select said there was data but there was nothing to * read. This implies user hit ^D. * Also handle ^D input when pressed as first char at a new line. */ if (count <= 0 || (first_char && cli_req.buf[0] == C_CTL_D)) { cli_req.command_response = SUNOEM_CLI_CMD_EOF; count = 0; } first_char = cli_req.buf[0] == '\n' || cli_req.buf[0] == '\r'; } } else { /* * Get data from command line arguments */ now = time(NULL); if (now < wait_time) { /* Do nothing; we're waiting */ } else if (arg_num >= argc) { /* Last arg was sent. Set EOF */ cli_req.command_response = SUNOEM_CLI_CMD_EOF; } else if (strncmp(argv[arg_num], "@wait=", 6) == 0) { /* This is a wait command */ char *s = &argv[arg_num][6]; delay = 0; if (*s != '\0') { if (str2int(s, &delay)) { delay = 0; } if (delay < 0) { delay = 0; } } wait_time = now + delay; arg_num++; } else { /* * Take data from args. It may be that the argument is larger * than the request buffer can hold. So pull off BUF_SIZE * number of characters at a time. When we've consumed the * entire arg, append a newline and advance to the next arg. */ int i; char *s = argv[arg_num]; for (i = arg_pos; s[i] != '\0' && count < (SUNOEM_CLI_BUF_SIZE - 2); i++, count++) { cli_req.buf[count] = s[i]; } if (s[i] == '\0') { /* Reached end of the arg string, so append a newline */ cli_req.buf[count++] = '\n'; /* Reset pos to 0 and advance to the next arg next time */ arg_pos = 0; arg_num++; } else { /* * Otherwise, there's still more characters in the arg * to send, so remember where we left off */ arg_pos = i; } } } /* * Now send the clients's data (if any) and get data back from the * server. Loop while the server is giving us data until we suck * it dry. */ do { cli_req.buf[count++] = '\0'; /* Terminate the string */ memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = 0x19; req.msg.data = (uint8_t *) &cli_req; req.msg.data_len = SUNOEM_CLI_HEADER + count; for (retries = 0; retries <= SUNOEM_CLI_MAX_RETRY; retries++) { rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Communication error."); error = 1; goto cleanup; } if (rsp->ccode == IPMI_CC_TIMEOUT) { /* Retry if timed out. */ if (retries == SUNOEM_CLI_MAX_RETRY) { /* If it's the last retry. */ lprintf(LOG_ERR, "Excessive timeout."); error = 1; goto cleanup; } continue; } break; } /* for (retries = 0; retries <= SUNOEM_CLI_MAX_RETRY; retries++) */ if (SunOemCliActingVersion == SUNOEM_CLI_SEQNUM_VERSION) { cli_req.seqnum ^= 0x1; /* Toggle sequence number after request is sent */ } cli_rsp = (sunoem_cli_msg_t *) rsp->data; /* Make sure response string is null terminated */ cli_rsp->buf[sizeof(cli_rsp->buf) - 1] = '\0'; printf("%s", cli_rsp->buf); fflush(NULL); /* Flush partial lines to stdout */ count = 0; /* Don't re-send the client's data */ if (cli_req.command_response == SUNOEM_CLI_CMD_EOF && cli_rsp->command_response != 0 && rsp->ccode == 0) { cli_rsp->command_response = 1; } } while (cli_rsp->command_response == 0 && cli_rsp->buf[0] != '\0'); } cleanup: /* Restore original input mode if cli was running interactively */ if (argc == 0) { if (sunoem_cli_unbufmode_stop(stdin, &orig_ts)) { lprintf(LOG_ERR, "Failed to restore interactive mode: %s", strerror(errno)); return (-1); } } return ((error == 0 && cli_rsp->command_response == SUNOEM_SUCCESS) ? 0 : -1); } #define ECHO_DATA_SIZE 64 #ifdef HAVE_PRAGMA_PACK #pragma pack(push, 1) #endif typedef struct { uint16_t seq_num; unsigned char data[ECHO_DATA_SIZE]; }__attribute__((packed)) sunoem_echo_msg_t; #ifdef HAVE_PRAGMA_PACK #pragma pack(pop) #endif /* * Send and receive X packets to the BMC. Each packet has a * payload size of (sunoem_echo_msg_t) bytes. Each packet is tagged with a * sequence number */ static int ipmi_sunoem_echo(struct ipmi_intf * intf, int argc, char *argv[]) { struct ipmi_rs *rsp; struct ipmi_rq req; sunoem_echo_msg_t echo_req; sunoem_echo_msg_t *echo_rsp; struct timeval start_time; struct timeval end_time; int rc = 0; int received = 0; int transmitted = 0; int quiet_mode = 0; uint16_t num, i, j; uint32_t total_time, resp_time, min_time, max_time; if (argc < 1) { return (1); } if (argc == 2) { if (*(argv[1]) == 'q') { quiet_mode = 1; } else { lprintf(LOG_ERR, "Unknown option '%s' given.", argv[1]); return (-1); } } else if (argc > 2) { lprintf(LOG_ERR, "Too many parameters given. See help for more information."); return (-1); } /* The number of packets to send/receive */ if (str2ushort(argv[0], &num) != 0) { lprintf(LOG_ERR, "Given number of packets is either invalid or out of range."); return (-1); } /* Fill in data packet */ for (i = 0; i < ECHO_DATA_SIZE; i++) { echo_req.data[i] = (uint8_t) i; } memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_ECHO; req.msg.data = (uint8_t *) &echo_req; req.msg.data_len = sizeof(sunoem_echo_msg_t); echo_req.seq_num = i; min_time = INT_MAX; max_time = 0; total_time = 0; for (i = 0; i < num; i++) { echo_req.seq_num = i; transmitted++; gettimeofday(&start_time, NULL); rsp = intf->sendrecv(intf, &req); gettimeofday(&end_time, NULL); resp_time = ((end_time.tv_sec - start_time.tv_sec) * 1000) + ((end_time.tv_usec - start_time.tv_usec) / 1000); if ((rsp == NULL) || (rsp->ccode != 0)) { lprintf(LOG_ERR, "Sun OEM echo command failed. Seq # %d", echo_req.seq_num); rc = (-2); break; } echo_rsp = (sunoem_echo_msg_t *) rsp->data; /* Test if sequence # is valid */ if (echo_rsp->seq_num != echo_req.seq_num) { printf("Invalid Seq # Expecting %d Received %d\n", echo_req.seq_num, echo_rsp->seq_num); rc = (-2); break; } /* Test if response length is valid */ if (rsp->session.msglen == req.msg.data_len) { printf("Invalid payload size for seq # %d. " "Expecting %d Received %d\n", echo_rsp->seq_num, req.msg.data_len, rsp->session.msglen); rc = (-2); break; } /* Test if the data is valid */ for (j = 0; j < ECHO_DATA_SIZE; j++) { if (echo_rsp->data[j] != j) { printf("Corrupt data packet. Seq # %d Offset %d\n", echo_rsp->seq_num, j); break; } } /* for (j = 0; j < ECHO_DATA_SIZE; j++) */ /* If the for loop terminated early - data is corrupt */ if (j != ECHO_DATA_SIZE) { rc = (-2); break; } /* cumalative time */ total_time += resp_time; /* min time */ if (resp_time < min_time) { min_time = resp_time; } /* max time */ if (resp_time > max_time) { max_time = resp_time; } received++; if (!quiet_mode) { printf("Receive %lu Bytes - Seq. # %d time=%d ms\n", sizeof(sunoem_echo_msg_t), echo_rsp->seq_num, resp_time); } } /* for (i = 0; i < num; i++) */ printf("%d packets transmitted, %d packets received\n", transmitted, received); if (received) { printf("round-trip min/avg/max = %d/%d/%d ms\n", min_time, total_time / received, max_time); } return (rc); } /* ipmi_sunoem_echo(...) */ #ifdef HAVE_PRAGMA_PACK #pragma pack(push, 1) #endif typedef struct { unsigned char oem_record_ver_num; unsigned char major; unsigned char minor; unsigned char update; unsigned char micro; char nano[10]; char revision[10]; char version[40]; /* * When adding new fields (using the spare bytes), * add it immediately after the spare field to * ensure backward compatability. * * e.g. char version[40]; * unsigned char spare[11]; * int new_item; * } sunoem_version_response_t; */ unsigned char spare[15]; }__attribute__((packed)) sunoem_version_response_t; #ifdef HAVE_PRAGMA_PACK #pragma pack(pop) #endif typedef struct { unsigned char major; unsigned char minor; unsigned char update; unsigned char micro; } supported_version_t; static int ipmi_sunoem_getversion(struct ipmi_intf * intf, sunoem_version_response_t **version_rsp) { struct ipmi_rs *rsp; struct ipmi_rq req; memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_VERSION; req.msg.data = NULL; req.msg.data_len = 0; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM Get SP Version Failed."); return (-1); } if (rsp->ccode != 0) { lprintf(LOG_ERR, "Sun OEM Get SP Version Failed: %d", rsp->ccode); return (-1); } *version_rsp = (sunoem_version_response_t *) rsp->data; return (0); } static void ipmi_sunoem_print_required_version(const supported_version_t* supp_ver) { lprintf(LOG_ERR, "Command is not supported by this version of ILOM," " required at least: %d.%d.%d.%d", supp_ver->major, supp_ver->minor, supp_ver->update, supp_ver->micro); } /* * Function checks current version result against required version. * Returns: * - negative value if current ILOM version is smaller than required or * in case of error * - positive value if current ILOM version is greater than required * - 0 if there is an exact ILOM version match */ static int ipmi_sunoem_checkversion(struct ipmi_intf * intf, supported_version_t* supp_ver) { sunoem_version_response_t *version_rsp; int i = 1; if (ipmi_sunoem_getversion(intf, &version_rsp)) { lprintf(LOG_ERR, "Unable to get ILOM version"); return (-1); } if (version_rsp->major < supp_ver->major) return (-i); if (version_rsp->major > supp_ver->major) return (i); /*version_rsp->major == supp_ver->major*/ ++i; if (version_rsp->minor < supp_ver->minor) return (-i); if (version_rsp->minor > supp_ver->minor) return (i); /*version_rsp->minor == supp_ver->minor*/ ++i; if (version_rsp->update < supp_ver->update) return (-i); if (version_rsp->update > supp_ver->update) return (i); /*version_rsp->update == supp_ver->update*/ ++i; if (version_rsp->micro < supp_ver->micro) return (-i); if (version_rsp->micro > supp_ver->micro) return (i); /*version_rsp->micro == supp_ver->micro*/ return (0); } /* * Extract the SP version data including * - major # * - minor # * - update # * - micro # * - nano # * - Revision/Build # */ static int ipmi_sunoem_version(struct ipmi_intf * intf) { sunoem_version_response_t *version_rsp; int rc = ipmi_sunoem_getversion(intf, &version_rsp); if (!rc) { printf("Version: %s\n", version_rsp->version); } return (rc); } /* * IPMI Max string length is 16 bytes * define in usr/src/common/include/ami/IPMI_SDRRecord.h */ #define MAX_ID_STR_LEN 16 #define MAX_SUNOEM_NAC_SIZE 64 #define LUAPI_MAX_OBJ_PATH_LEN 256 #define LUAPI_MAX_OBJ_VAL_LEN 1024 #ifdef HAVE_PRAGMA_PACK #pragma pack(push, 1) #endif typedef struct { unsigned char seq_num; char nac_name[MAX_SUNOEM_NAC_SIZE]; }__attribute__((packed)) sunoem_nacname_t; #ifdef HAVE_PRAGMA_PACK #pragma pack(pop) #endif /* * Retrieve the full NAC name of the IPMI target. * * The returned nac name may be larger than the payload size. * In which case, it make take several request/payload to retrieve * the entire full path name * * The initial seq_num is set to 0. If the return seq_num is incremented, * only the 1st 72 bytes of the nac name is returned and the caller * needs to get the next set of string data. * If the returned seq_num is identical to the input seq_num, all data * has been returned. */ static int ipmi_sunoem_nacname(struct ipmi_intf * intf, int argc, char *argv[]) { struct ipmi_rs *rsp; struct ipmi_rq req; sunoem_nacname_t nacname_req; sunoem_nacname_t *nacname_rsp; char full_nac_name[LUAPI_MAX_OBJ_PATH_LEN]; if (argc < 1) { return (1); } if (strlen(argv[0]) > MAX_ID_STR_LEN) { lprintf(LOG_ERR, "Sun OEM nacname command failed: Max size on IPMI name"); return (-1); } nacname_req.seq_num = 0; strcpy(nacname_req.nac_name, argv[0]); full_nac_name[0] = '\0'; while (1) { memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_NACNAME; req.msg.data = (uint8_t *) &nacname_req; req.msg.data_len = sizeof(sunoem_nacname_t); rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM nacname command failed."); return (-1); } if (rsp->ccode != 0) { lprintf(LOG_ERR, "Sun OEM nacname command failed: %d", rsp->ccode); return (-1); } nacname_rsp = (sunoem_nacname_t *) rsp->data; strncat(full_nac_name, nacname_rsp->nac_name, MAX_SUNOEM_NAC_SIZE); /* * break out of the loop if there is no more data * In most cases, if not all, the NAC name fits into a * single payload */ if (nacname_req.seq_num == nacname_rsp->seq_num) { break; } /* Get the next seq of string bytes */ nacname_req.seq_num = nacname_rsp->seq_num; /* Check if we exceeded the size of the full nac name */ if ((nacname_req.seq_num * MAX_SUNOEM_NAC_SIZE) > LUAPI_MAX_OBJ_PATH_LEN) { lprintf(LOG_ERR, "Sun OEM nacname command failed: invalid path length"); return (-1); } } printf("NAC Name: %s\n", full_nac_name); return (0); } /* Constants used by ipmi_sunoem_getval */ #define MAX_SUNOEM_VAL_PAYLOAD 79 #define MAX_SUNOEM_VAL_COMPACT_PAYLOAD 56 /* * SUNOEM GET/SET LUAPI Commands * * SUNOEM_REQ_VAL - Request LUAPI Property Value * SUNOEM_GET_VAL - Return the value from SUNOEM_REQ_VAL * SUNOEM_SET_VAL - Set the LUAPI Property value * SUNOEM_GET_STATUS - Return the Status from SUNOEM_SET_VAL */ #define SUNOEM_REQ_VAL 1 #define SUNOEM_GET_VAL 2 #define SUNOEM_SET_VAL 3 #define SUNOEM_GET_STATUS 4 /* Status Code */ #define SUNOEM_REQ_RECV 1 #define SUNOEM_REQ_FAILED 2 #define SUNOEM_DATA_READY 3 #define SUNOEM_DATA_NOT_READY 4 #define SUNOEM_DATA_NOT_FOUND 5 #define GETVAL_MAX_RETRIES 5 /* Parameter type Codes */ #define SUNOEM_LUAPI_TARGET 0 #define SUNOEM_LUAPI_VALUE 1 #ifdef HAVE_PRAGMA_PACK #pragma pack(push, 1) #endif typedef struct { unsigned char cmd_code; unsigned char luapi_value[MAX_SUNOEM_VAL_PAYLOAD]; }__attribute__((packed)) sunoem_getval_t; #ifdef HAVE_PRAGMA_PACK #pragma pack(pop) #endif /* * REQUEST PAYLOAD * * cmd_code - SUNOEM GET/SET LUAPI Cmds - see above * param_type: 0: luapi_data contains the luapi property name * 1: luapi_data contains the luapi value * luapi_data: Either luapi property name or value * tid: Transaction ID. If 0. This is the initial request for the * param_type. If tid > 0, this luapi_data string is a concatenation * of the previous request. Handle cases where the LUAPI target name * or value is > MAX_SUNOEM_VAL_COMPACT_PAYLOAD * eof: If non zero, this is the last payload for the request */ #ifdef HAVE_PRAGMA_PACK #pragma pack(push, 1) #endif typedef struct { unsigned char cmd_code; unsigned char param_type; unsigned char tid; unsigned char eof; char luapi_data[MAX_SUNOEM_VAL_COMPACT_PAYLOAD]; }__attribute__((packed)) sunoem_setval_t; #ifdef HAVE_PRAGMA_PACK #pragma pack(pop) #endif /* * RESPONSE PAYLOAD * * status_code - see above for code definitions * tid - transaction ID - assigned ny the ILOM stack */ #ifdef HAVE_PRAGMA_PACK #pragma pack(push, 1) #endif typedef struct { unsigned char status_code; unsigned char tid; }__attribute__((packed)) sunoem_setval_resp_t; #ifdef HAVE_PRAGMA_PACK #pragma pack(pop) #endif /* * Return the ILOM target property value */ static int ipmi_sunoem_getval(struct ipmi_intf * intf, int argc, char *argv[]) { struct ipmi_rs *rsp; struct ipmi_rq req; sunoem_getval_t getval_req; sunoem_getval_t *getval_rsp; int i; const char* sp_path = "/SP"; supported_version_t supp_ver = { 3, 2, 0, 0 }; if (argc < 1) { return (1); } if (strlen(argv[0]) > MAX_SUNOEM_VAL_PAYLOAD) { lprintf(LOG_ERR, "Sun OEM get value command failed: Max size on IPMI name"); return (-1); } if ((ipmi_sunoem_checkversion(intf, &supp_ver) < 0) && (!strncmp(argv[0], sp_path, strlen(sp_path)))) { argv[0][1] = 'X'; /*replace SP by X to gain access to hidden properties*/ memmove(&argv[0][2], &argv[0][3], strlen(argv[0]) - 2); } /* * Setup the initial request to fetch the data. * Upon function return, the next cmd (SUNOEM_GET_VAL) * can be requested. */ memset(&getval_req, 0, sizeof(getval_req)); strncpy((char*) getval_req.luapi_value, argv[0], MAX_SUNOEM_VAL_PAYLOAD); getval_req.cmd_code = SUNOEM_REQ_VAL; memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_GETVAL; req.msg.data = (uint8_t *) &getval_req; req.msg.data_len = sizeof(sunoem_getval_t); rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM getval1 command failed."); return (-1); } if (rsp->ccode != 0) { lprintf(LOG_ERR, "Sun OEM getval1 command failed: %d", rsp->ccode); return (-1); } /* * Fetch the data value - if it is not ready, * retry the request up to GETVAL_MAX_RETRIES */ for (i = 0; i < GETVAL_MAX_RETRIES; i++) { memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_GETVAL; getval_req.cmd_code = SUNOEM_GET_VAL; req.msg.data = (uint8_t *) &getval_req; req.msg.data_len = sizeof(sunoem_getval_t); rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM getval2 command failed."); return (-1); } if (rsp->ccode != 0) { lprintf(LOG_ERR, "Sun OEM getval2 command failed: %d", rsp->ccode); return (-1); } getval_rsp = (sunoem_getval_t *) rsp->data; if (getval_rsp->cmd_code == SUNOEM_DATA_READY) { printf("Target Value: %s\n", getval_rsp->luapi_value); return (0); } else if (getval_rsp->cmd_code == SUNOEM_DATA_NOT_FOUND) { lprintf(LOG_ERR, "Target: %s not found", getval_req.luapi_value); return (-1); } sleep(1); } lprintf(LOG_ERR, "Unable to retrieve target value."); return (-1); } static int send_luapi_prop_name(struct ipmi_intf * intf, int len, char *prop_name, unsigned char *tid_num) { int i = 0; struct ipmi_rs *rsp; struct ipmi_rq req; sunoem_setval_t setval_req; sunoem_setval_resp_t *setval_rsp; *tid_num = 0; while (i < len) { /* * Setup the request, * Upon function return, the next cmd (SUNOEM_SET_VAL) * can be requested. */ memset(&req, 0, sizeof(req)); memset(&setval_req, 0, sizeof(sunoem_setval_t)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_SETVAL; setval_req.cmd_code = SUNOEM_SET_VAL; setval_req.param_type = SUNOEM_LUAPI_TARGET; setval_req.tid = *tid_num; setval_req.eof = 0; /* * If the property name is > payload, only copy * the payload size and increment the string offset (i) * for the next payload */ if (strlen(&(prop_name[i])) > MAX_SUNOEM_VAL_COMPACT_PAYLOAD) { strncpy(setval_req.luapi_data, &(prop_name[i]), MAX_SUNOEM_VAL_COMPACT_PAYLOAD); } else { strncpy(setval_req.luapi_data, &(prop_name[i]), strlen(&(prop_name[i]))); } req.msg.data = (uint8_t *) &setval_req; req.msg.data_len = sizeof(sunoem_setval_t); rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM setval prop name: response is NULL"); return (-1); } if (rsp->ccode != 0) { lprintf(LOG_ERR, "Sun OEM setval prop name: request failed: %d", rsp->ccode); return (-1); } setval_rsp = (sunoem_setval_resp_t *) rsp->data; /* * If the return code is other than data received, the * request failed */ if (setval_rsp->status_code != SUNOEM_REQ_RECV) { lprintf(LOG_ERR, "Sun OEM setval prop name: invalid status code: %d", setval_rsp->status_code); return (-1); } /* Use the tid returned by ILOM */ *tid_num = setval_rsp->tid; /* Increment the string offset */ i += MAX_SUNOEM_VAL_COMPACT_PAYLOAD; } return (0); } static int send_luapi_prop_value(struct ipmi_intf * intf, int len, char *prop_value, unsigned char tid_num) { int i = 0; struct ipmi_rs *rsp; struct ipmi_rq req; sunoem_setval_t setval_req; sunoem_setval_resp_t *setval_rsp; while (i < len) { /* * Setup the request, * Upon function return, the next cmd (SUNOEM_GET_VAL) * can be requested. */ memset(&req, 0, sizeof(req)); memset(&setval_req, 0, sizeof(sunoem_setval_t)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_SETVAL; setval_req.cmd_code = SUNOEM_SET_VAL; setval_req.param_type = SUNOEM_LUAPI_VALUE; setval_req.tid = tid_num; /* * If the property name is > payload, only copy the * the payload size and increment the string offset * for the next payload */ if (strlen(&(prop_value[i])) > MAX_SUNOEM_VAL_COMPACT_PAYLOAD) { strncpy(setval_req.luapi_data, &(prop_value[i]), MAX_SUNOEM_VAL_COMPACT_PAYLOAD); } else { /* Captured the entire string, mark this as the last payload */ strncpy(setval_req.luapi_data, &(prop_value[i]), strlen(&(prop_value[i]))); setval_req.eof = 1; } req.msg.data = (uint8_t *) &setval_req; req.msg.data_len = sizeof(sunoem_setval_t); rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM setval prop value: response is NULL"); return (-1); } if (rsp->ccode != 0) { lprintf(LOG_ERR, "Sun OEM setval prop value: request failed: %d", rsp->ccode); return (-1); } setval_rsp = (sunoem_setval_resp_t *) rsp->data; /* * If the return code is other than data received, the * request failed */ if (setval_rsp->status_code != SUNOEM_REQ_RECV) { lprintf(LOG_ERR, "Sun OEM setval prop value: invalid status code: %d", setval_rsp->status_code); return (-1); } /* Increment the string offset */ i += MAX_SUNOEM_VAL_COMPACT_PAYLOAD; } return (0); } static int ipmi_sunoem_setval(struct ipmi_intf * intf, int argc, char *argv[]) { struct ipmi_rs *rsp; struct ipmi_rq req; sunoem_setval_t setval_req; sunoem_setval_resp_t *setval_rsp; int prop_len; int value_len; int i; unsigned char tid_num; int retries; prop_len = strlen(argv[0]); value_len = strlen(argv[1]); if (prop_len > LUAPI_MAX_OBJ_PATH_LEN) { lprintf(LOG_ERR, "Sun OEM set value command failed: Max size on property name"); return (-1); } if (value_len > LUAPI_MAX_OBJ_VAL_LEN) { lprintf(LOG_ERR, "Sun OEM set value command failed: Max size on property value"); return (-1); } /* Test if there is a timeout specified */ if (argc == 3) { if ((str2int(argv[2], &retries) != 0) || retries < 0) { lprintf(LOG_ERR, "Invalid input given or out of range for time-out parameter."); return (-1); } } else { retries = GETVAL_MAX_RETRIES; } /* Send the property name 1st */ if (send_luapi_prop_name(intf, prop_len, argv[0], &tid_num) != 0) { /* return if there is an error */ return (-1); } if (send_luapi_prop_value(intf, value_len, argv[1], tid_num) != 0) { /* return if there is an error */ return (-1); } /* * Get The status of the command. * if it is not ready, retry the request up to * GETVAL_MAX_RETRIES */ for (i = 0; i < retries; i++) { memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_SETVAL; setval_req.cmd_code = SUNOEM_GET_STATUS; setval_req.tid = tid_num; req.msg.data = (uint8_t *) &setval_req; req.msg.data_len = sizeof(sunoem_setval_t); rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM setval command failed."); return (-1); } if (rsp->ccode != 0) { lprintf(LOG_ERR, "Sun OEM setval command failed: %d", rsp->ccode); return (-1); } setval_rsp = (sunoem_setval_resp_t *) rsp->data; if (setval_rsp->status_code == SUNOEM_DATA_READY) { printf("Sun OEM setval command successful.\n"); return (0); } else if (setval_rsp->status_code != SUNOEM_DATA_NOT_READY) { lprintf(LOG_ERR, "Sun OEM setval command failed."); return (-1); } sleep(1); } /* If we reached here, retries exceeded */ lprintf(LOG_ERR, "Sun OEM setval command failed: Command Timed Out"); return (-1); } #define MAX_FILE_DATA_SIZE 1024 #define MAX_FILEID_LEN 16 #define CORE_TUNNEL_SUBCMD_GET_FILE 11 #ifdef HAVE_PRAGMA_PACK #pragma pack(push, 1) #endif typedef struct { unsigned char cmd_code; unsigned char file_id[MAX_FILEID_LEN]; unsigned int block_num; }__attribute__((packed)) getfile_req_t; typedef struct { unsigned int block_num; unsigned int data_size; unsigned char eof; unsigned char data[MAX_FILE_DATA_SIZE]; }__attribute__((packed)) getfile_rsp_t; #ifdef HAVE_PRAGMA_PACK #pragma pack(pop) #endif static int ipmi_sunoem_getfile(struct ipmi_intf * intf, int argc, char *argv[]) { struct ipmi_rs *rsp; struct ipmi_rq req; getfile_req_t getfile_req; getfile_rsp_t *getfile_rsp; int block_num = 0; int nbo_blk_num; /* Network Byte Order Block Num */ FILE *fp; unsigned data_size; supported_version_t supp_ver = IPMI_SUNOEM_GETFILE_VERSION; if (argc < 1) { return (-1); } /*check if command is supported by this version of ilom*/ if (ipmi_sunoem_checkversion(intf, &supp_ver) < 0) { ipmi_sunoem_print_required_version(&supp_ver); return (-1); } /* * File ID is < MAX_FILEID_LEN * Save 1 byte for null Terminated string */ if (strlen(argv[0]) >= MAX_FILE_DATA_SIZE) { lprintf(LOG_ERR, "File ID >= %d characters", MAX_FILEID_LEN); return (-1); } memset(&getfile_req, 0, sizeof(getfile_req)); strncpy((char*) getfile_req.file_id, argv[0], MAX_FILEID_LEN - 1); /* Create the destination file */ fp = ipmi_open_file_write(argv[1]); if (fp == NULL) { lprintf(LOG_ERR, "Unable to open file: %s", argv[1]); return (-1); } memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_CORE_TUNNEL; req.msg.data = (uint8_t *) &getfile_req; req.msg.data_len = sizeof(getfile_req_t); getfile_req.cmd_code = CORE_TUNNEL_SUBCMD_GET_FILE; do { nbo_blk_num = htonl(block_num); /* Block Num must be in network byte order */ memcpy(&(getfile_req.block_num), &nbo_blk_num, sizeof(getfile_req.block_num)); rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM getfile command failed."); fclose(fp); return (-1); } if (rsp->ccode != 0) { lprintf(LOG_ERR, "Sun OEM getfile command failed: %d", rsp->ccode); fclose(fp); return (-1); } getfile_rsp = (getfile_rsp_t *) rsp->data; memcpy(&data_size, &(getfile_rsp->data_size), sizeof(getfile_rsp->data_size)); data_size = ntohl(data_size); if (data_size > MAX_FILE_DATA_SIZE) { lprintf(LOG_ERR, "Sun OEM getfile invalid data size: %d", data_size); fclose(fp); return (-1); } /* Check if Block Num matches */ if (memcmp(&(getfile_req.block_num), &(getfile_rsp->block_num), sizeof(getfile_req.block_num)) != 0) { lprintf(LOG_ERR, "Sun OEM getfile Incorrect Block Num Returned"); lprintf(LOG_ERR, "Expecting: %x Received: %x", getfile_req.block_num, getfile_rsp->block_num); fclose(fp); return (-1); } if (fwrite(getfile_rsp->data, 1, data_size, fp) != data_size) { lprintf(LOG_ERR, "Sun OEM getfile write failed: %d", rsp->ccode); fclose(fp); return (-1); } block_num++; } while (getfile_rsp->eof == 0); fclose(fp); return (0); } /* * Query BMC for capability/behavior. */ #define CORE_TUNNEL_SUBCMD_GET_BEHAVIOR 15 #define SUNOEM_BEHAVIORID_SIZE 32 #ifdef HAVE_PRAGMA_PACK #pragma pack(push, 1) #endif typedef struct { unsigned char cmd_code; unsigned char behavior_id[SUNOEM_BEHAVIORID_SIZE]; }__attribute__((packed)) getbehavior_req_t; typedef struct { unsigned char enabled; }__attribute__((packed)) getbehavior_rsp_t; #ifdef HAVE_PRAGMA_PACK #pragma pack(pop) #endif static int ipmi_sunoem_getbehavior(struct ipmi_intf * intf, int argc, char *argv[]) { struct ipmi_rq req; struct ipmi_rs *rsp; getbehavior_req_t getbehavior_req; getbehavior_rsp_t *getbehavior_rsp; supported_version_t supp_ver = IPMI_SUNOEM_GETBEHAVIOR_VERSION; if (argc < 1) { return (-1); } /*check if command is supported by this version of ilom*/ if (ipmi_sunoem_checkversion(intf, &supp_ver) < 0) { ipmi_sunoem_print_required_version(&supp_ver); return (-1); } /* * Behavior ID is < SUNOEM_BEHAVIORID_SIZE. * Save 1 byte for null terminated string */ if (strlen(argv[0]) >= SUNOEM_BEHAVIORID_SIZE) { lprintf(LOG_ERR, "Behavior ID >= %d characters", SUNOEM_BEHAVIORID_SIZE); return (-1); } memset(&getbehavior_req, 0, sizeof(getbehavior_req)); strncpy(getbehavior_req.behavior_id, argv[0], SUNOEM_BEHAVIORID_SIZE - 1); memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_SUNOEM; req.msg.cmd = IPMI_SUNOEM_CORE_TUNNEL; req.msg.data = (uint8_t *) &getbehavior_req; req.msg.data_len = sizeof(getbehavior_req_t); getbehavior_req.cmd_code = CORE_TUNNEL_SUBCMD_GET_BEHAVIOR; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Sun OEM getbehavior command failed."); return (-1); } if (rsp->ccode != 0) { lprintf(LOG_ERR, "Sun OEM getbehavior command failed: %d", rsp->ccode); return (-1); } getbehavior_rsp = (getbehavior_rsp_t *) rsp->data; printf("ILOM behavior %s %s enabled\n", getbehavior_req.behavior_id, getbehavior_rsp->enabled ? "is" : "is not"); return (0); } int ipmi_sunoem_main(struct ipmi_intf * intf, int argc, char ** argv) { int rc = 0; if (argc == 0 || strcmp(argv[0], "help") == 0) { ipmi_sunoem_usage(); return (0); } /* if (argc == 0 || strcmp(argv[0], "help") == 0) */ if (strcmp(argv[0], "cli") == 0) { rc = ipmi_sunoem_cli(intf, argc - 1, &argv[1]); } else if ((strcmp(argv[0], "led") == 0) || (strcmp(argv[0], "sbled") == 0)) { if (argc < 2) { ipmi_sunoem_usage(); return (-1); } if (strcmp(argv[1], "get") == 0) { if (argc < 3) { char * arg[] = { "all" }; rc = ipmi_sunoem_led_get(intf, 1, arg); } else { rc = ipmi_sunoem_led_get(intf, argc - 2, &(argv[2])); } } else if (strcmp(argv[1], "set") == 0) { if (argc < 4) { ipmi_sunoem_usage(); return (-1); } rc = ipmi_sunoem_led_set(intf, argc - 2, &(argv[2])); } else { ipmi_sunoem_usage(); return (-1); } } else if (strcmp(argv[0], "sshkey") == 0) { uint8_t uid = 0; if (argc < 3) { ipmi_sunoem_usage(); return (-1); } rc = str2uchar(argv[2], &uid); if (rc == 0) { /* conversion should be OK. */ } else if (rc == 2) { lprintf(LOG_NOTICE, "Invalid interval given."); return (-1); } else { /* defaults to rc = 3 */ lprintf(LOG_NOTICE, "Given interval is too big."); return (-1); } if (strcmp(argv[1], "del") == 0) { /* number of arguments, three, is already checked at this point */ rc = ipmi_sunoem_sshkey_del(intf, uid); } else if (strcmp(argv[1], "set") == 0) { if (argc < 4) { ipmi_sunoem_usage(); return (-1); } rc = ipmi_sunoem_sshkey_set(intf, uid, argv[3]); } else { ipmi_sunoem_usage(); return (-1); } } else if (strcmp(argv[0], "ping") == 0) { if (argc < 2) { ipmi_sunoem_usage(); return (-1); } rc = ipmi_sunoem_echo(intf, argc - 1, &(argv[1])); } else if (strcmp(argv[0], "version") == 0) { rc = ipmi_sunoem_version(intf); } else if (strcmp(argv[0], "nacname") == 0) { if (argc < 2) { ipmi_sunoem_usage(); return (-1); } rc = ipmi_sunoem_nacname(intf, argc - 1, &(argv[1])); } else if (strcmp(argv[0], "getval") == 0) { if (argc < 2) { ipmi_sunoem_usage(); return (-1); } rc = ipmi_sunoem_getval(intf, argc - 1, &(argv[1])); } else if (strcmp(argv[0], "setval") == 0) { if (argc < 3) { ipmi_sunoem_usage(); return (-1); } rc = ipmi_sunoem_setval(intf, argc - 1, &(argv[1])); } else if (strcmp(argv[0], "getfile") == 0) { if (argc < 3) { ipmi_sunoem_usage(); return (-1); } rc = ipmi_sunoem_getfile(intf, argc - 1, &(argv[1])); } else if (strcmp(argv[0], "getbehavior") == 0) { if (argc < 2) { ipmi_sunoem_usage(); return (-1); } rc = ipmi_sunoem_getbehavior(intf, argc - 1, &(argv[1])); } else { lprintf(LOG_ERR, "Invalid sunoem command: %s", argv[0]); return (-1); } /* if (strcmp(argv[0], "cli") == 0) */ return (rc); }