/* * Copyright (c) 2003 Sun Microsystems, Inc. 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 #define _BSD_SOURCE || \ (_XOPEN_SOURCE >= 500 || \ _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) && \ !(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700) #include #include #include #include #include #include #include #include #include #include #include #if defined(HAVE_CONFIG_H) # include #endif #if defined(HAVE_TERMIOS_H) # include #elif defined (HAVE_SYS_TERMIOS_H) # include #endif #include #include #include #include #include #include #include #define SOL_PARAMETER_SET_IN_PROGRESS 0x00 #define SOL_PARAMETER_SOL_ENABLE 0x01 #define SOL_PARAMETER_SOL_AUTHENTICATION 0x02 #define SOL_PARAMETER_CHARACTER_INTERVAL 0x03 #define SOL_PARAMETER_SOL_RETRY 0x04 #define SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE 0x05 #define SOL_PARAMETER_SOL_VOLATILE_BIT_RATE 0x06 #define SOL_PARAMETER_SOL_PAYLOAD_CHANNEL 0x07 #define SOL_PARAMETER_SOL_PAYLOAD_PORT 0x08 #define MAX_SOL_RETRY 6 const struct valstr sol_parameter_vals[] = { { SOL_PARAMETER_SET_IN_PROGRESS, "Set In Progress (0)" }, { SOL_PARAMETER_SOL_ENABLE, "Enable (1)" }, { SOL_PARAMETER_SOL_AUTHENTICATION, "Authentication (2)" }, { SOL_PARAMETER_CHARACTER_INTERVAL, "Character Interval (3)" }, { SOL_PARAMETER_SOL_RETRY, "Retry (4)" }, { SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE, "Nonvolatile Bitrate (5)" }, { SOL_PARAMETER_SOL_VOLATILE_BIT_RATE, "Volatile Bitrate (6)" }, { SOL_PARAMETER_SOL_PAYLOAD_CHANNEL, "Payload Channel (7)" }, { SOL_PARAMETER_SOL_PAYLOAD_PORT, "Payload Port (8)" }, { 0x00, NULL }, }; static struct timeval _start_keepalive; static struct termios _saved_tio; static int _in_raw_mode = 0; static int _disable_keepalive = 0; static int _use_sol_for_keepalive = 0; extern int verbose; /* * ipmi_sol_payload_access */ int ipmi_sol_payload_access(struct ipmi_intf * intf, uint8_t channel, uint8_t userid, int enable) { struct ipmi_rq req; struct ipmi_rs *rsp; int rc = (-1); uint8_t data[6]; memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_APP; req.msg.cmd = IPMI_SET_USER_PAYLOAD_ACCESS; req.msg.data = data; req.msg.data_len = 6; memset(data, 0, 6); /* channel */ data[0] = channel & 0xf; /* user id */ data[1] = userid & 0x3f; if (!enable) { /* disable */ data[1] |= 0x40; } /* payload 1 is SOL */ data[2] = 0x02; rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d", enable ? "en" : "dis", userid, channel); rc = (-1); } else if (rsp->ccode != 0) { lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d: %s", enable ? "en" : "dis", userid, channel, val2str(rsp->ccode, completion_code_vals)); rc = (-1); } else { rc = 0; } return rc; } int ipmi_sol_payload_access_status(struct ipmi_intf * intf, uint8_t channel, uint8_t userid) { struct ipmi_rq req; struct ipmi_rs *rsp; uint8_t data[2]; memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_APP; req.msg.cmd = IPMI_GET_USER_PAYLOAD_ACCESS; req.msg.data = data; req.msg.data_len = sizeof(data); data[0] = channel & 0xf; /* channel */ data[1] = userid & 0x3f; /* user id */ rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Error. No valid response received."); return -1; } switch(rsp->ccode) { case 0x00: if (rsp->data_len != 4) { lprintf(LOG_ERR, "Error parsing SOL payload status for user %d on channel %d", userid, channel); return -1; } printf("User %d on channel %d is %sabled\n", userid, channel, (rsp->data[0] & 0x02) ? "en":"dis"); return 0; default: lprintf(LOG_ERR, "Error getting SOL payload status for user %d on channel %d: %s", userid, channel, val2str(rsp->ccode, completion_code_vals)); return -1; } } /* * ipmi_get_sol_info */ int ipmi_get_sol_info( struct ipmi_intf * intf, uint8_t channel, struct sol_config_parameters * params) { struct ipmi_rs * rsp; struct ipmi_rq req; uint8_t data[4]; memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_TRANSPORT; req.msg.cmd = IPMI_GET_SOL_CONFIG_PARAMETERS; req.msg.data_len = 4; req.msg.data = data; /* * set in progress */ memset(data, 0, sizeof(data)); data[0] = channel; /* channel number */ data[1] = SOL_PARAMETER_SET_IN_PROGRESS; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", val2str(data[1], sol_parameter_vals)); return (-1); } switch (rsp->ccode) { case 0x00: if (rsp->data_len == 2) { params->set_in_progress = rsp->data[1]; } else { lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " "for SOL parameter '%s'", rsp->data_len, val2str(data[1], sol_parameter_vals)); } break; case 0x80: lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", val2str(data[1], sol_parameter_vals), val2str(rsp->ccode, completion_code_vals)); return (-1); } /* * SOL enable */ memset(data, 0, sizeof(data)); data[0] = channel; /* channel number */ data[1] = SOL_PARAMETER_SOL_ENABLE; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", val2str(data[1], sol_parameter_vals)); return (-1); } switch (rsp->ccode) { case 0x00: if (rsp->data_len == 2) { params->enabled = rsp->data[1]; } else { lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " "for SOL parameter '%s'", rsp->data_len, val2str(data[1], sol_parameter_vals)); } break; case 0x80: lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", val2str(data[1], sol_parameter_vals), val2str(rsp->ccode, completion_code_vals)); return (-1); } /* * SOL authentication */ memset(data, 0, sizeof(data)); data[0] = channel; /* channel number */ data[1] = SOL_PARAMETER_SOL_AUTHENTICATION; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", val2str(data[1], sol_parameter_vals)); return (-1); } switch (rsp->ccode) { case 0x00: if (rsp->data_len == 2) { params->force_encryption = ((rsp->data[1] & 0x80)? 1 : 0); params->force_authentication = ((rsp->data[1] & 0x40)? 1 : 0); params->privilege_level = rsp->data[1] & 0x0F; } else { lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " "for SOL parameter '%s'", rsp->data_len, val2str(data[1], sol_parameter_vals)); } break; case 0x80: lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", val2str(data[1], sol_parameter_vals), val2str(rsp->ccode, completion_code_vals)); return (-1); } /* * Character accumulate interval and character send interval */ memset(data, 0, sizeof(data)); data[0] = channel; /* channel number */ data[1] = SOL_PARAMETER_CHARACTER_INTERVAL; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", val2str(data[1], sol_parameter_vals)); return (-1); } switch (rsp->ccode) { case 0x00: if (rsp->data_len == 3) { params->character_accumulate_level = rsp->data[1]; params->character_send_threshold = rsp->data[2]; } else { lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " "for SOL parameter '%s'", rsp->data_len, val2str(data[1], sol_parameter_vals)); } break; case 0x80: lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", val2str(data[1], sol_parameter_vals), val2str(rsp->ccode, completion_code_vals)); return (-1); } /* * SOL retry */ memset(data, 0, sizeof(data)); data[0] = channel; /* channel number */ data[1] = SOL_PARAMETER_SOL_RETRY; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", val2str(data[1], sol_parameter_vals)); return (-1); } switch (rsp->ccode) { case 0x00: if (rsp->data_len == 3) { params->retry_count = rsp->data[1]; params->retry_interval = rsp->data[2]; } else { lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " "for SOL parameter '%s'", rsp->data_len, val2str(data[1], sol_parameter_vals)); } break; case 0x80: lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", val2str(data[1], sol_parameter_vals), val2str(rsp->ccode, completion_code_vals)); return (-1); } /* * SOL non-volatile bit rate */ memset(data, 0, sizeof(data)); data[0] = channel; /* channel number */ data[1] = SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", val2str(data[1], sol_parameter_vals)); return (-1); } switch (rsp->ccode) { case 0x00: if (rsp->data_len == 2) { params->non_volatile_bit_rate = rsp->data[1] & 0x0F; } else { lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " "for SOL parameter '%s'", rsp->data_len, val2str(data[1], sol_parameter_vals)); } break; case 0x80: lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", val2str(data[1], sol_parameter_vals), val2str(rsp->ccode, completion_code_vals)); return (-1); } /* * SOL volatile bit rate */ memset(data, 0, sizeof(data)); data[0] = channel; /* channel number */ data[1] = SOL_PARAMETER_SOL_VOLATILE_BIT_RATE; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", val2str(data[1], sol_parameter_vals)); return (-1); } switch (rsp->ccode) { case 0x00: if (rsp->data_len == 2) { params->volatile_bit_rate = rsp->data[1] & 0x0F; } else { lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " "for SOL parameter '%s'", rsp->data_len, val2str(data[1], sol_parameter_vals)); } break; case 0x80: lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported", val2str(data[1], sol_parameter_vals)); break; default: lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", val2str(data[1], sol_parameter_vals), val2str(rsp->ccode, completion_code_vals)); return (-1); } /* * SOL payload channel */ memset(data, 0, sizeof(data)); data[0] = channel; /* channel number */ data[1] = SOL_PARAMETER_SOL_PAYLOAD_CHANNEL; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", val2str(data[1], sol_parameter_vals)); return (-1); } switch (rsp->ccode) { case 0x00: if (rsp->data_len == 2) { params->payload_channel = rsp->data[1]; } else { lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " "for SOL parameter '%s'", rsp->data_len, val2str(data[1], sol_parameter_vals)); } break; case 0x80: lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to 0x%02x", val2str(data[1], sol_parameter_vals), channel); params->payload_channel = channel; break; default: lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", val2str(data[1], sol_parameter_vals), val2str(rsp->ccode, completion_code_vals)); return (-1); } /* * SOL payload port */ memset(data, 0, sizeof(data)); data[0] = channel; /* channel number */ data[1] = SOL_PARAMETER_SOL_PAYLOAD_PORT; /* parameter selector */ data[2] = 0x00; /* set selector */ data[3] = 0x00; /* block selector */ rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Error: No response requesting SOL parameter '%s'", val2str(data[1], sol_parameter_vals)); return (-1); } switch (rsp->ccode) { case 0x00: if (rsp->data_len == 3) { params->payload_port = (rsp->data[1]) | (rsp->data[2] << 8); } else { lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " "for SOL parameter '%s'", rsp->data_len, val2str(data[1], sol_parameter_vals)); } break; case 0x80: if( intf->session != NULL ) { lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - defaulting to %d", val2str(data[1], sol_parameter_vals), intf->ssn_params.port); params->payload_port = intf->ssn_params.port; } else { lprintf(LOG_ERR, "Info: SOL parameter '%s' not supported - can't determine which " "payload port to use on NULL session", val2str(data[1], sol_parameter_vals)); return (-1); } break; default: lprintf(LOG_ERR, "Error requesting SOL parameter '%s': %s", val2str(data[1], sol_parameter_vals), val2str(rsp->ccode, completion_code_vals)); return (-1); } return 0; } /* * ipmi_print_sol_info */ static int ipmi_print_sol_info(struct ipmi_intf * intf, uint8_t channel) { struct sol_config_parameters params = {0}; if (ipmi_get_sol_info(intf, channel, ¶ms)) return -1; if (csv_output) { printf("%s,", val2str(params.set_in_progress & 0x03, ipmi_set_in_progress_vals)); printf("%s,", params.enabled?"true": "false"); printf("%s,", params.force_encryption?"true":"false"); printf("%s,", params.force_encryption?"true":"false"); printf("%s,", val2str(params.privilege_level, ipmi_privlvl_vals)); printf("%d,", params.character_accumulate_level * 5); printf("%d,", params.character_send_threshold); printf("%d,", params.retry_count); printf("%d,", params.retry_interval * 10); printf("%s,", val2str(params.volatile_bit_rate, ipmi_bit_rate_vals)); printf("%s,", val2str(params.non_volatile_bit_rate, ipmi_bit_rate_vals)); printf("%d,", params.payload_channel); printf("%d\n", params.payload_port); } else { printf("Set in progress : %s\n", val2str(params.set_in_progress & 0x03, ipmi_set_in_progress_vals)); printf("Enabled : %s\n", params.enabled?"true": "false"); printf("Force Encryption : %s\n", params.force_encryption?"true":"false"); printf("Force Authentication : %s\n", params.force_authentication?"true":"false"); printf("Privilege Level : %s\n", val2str(params.privilege_level, ipmi_privlvl_vals)); printf("Character Accumulate Level (ms) : %d\n", params.character_accumulate_level * 5); printf("Character Send Threshold : %d\n", params.character_send_threshold); printf("Retry Count : %d\n", params.retry_count); printf("Retry Interval (ms) : %d\n", params.retry_interval * 10); printf("Volatile Bit Rate (kbps) : %s\n", val2str(params.volatile_bit_rate, ipmi_bit_rate_vals)); printf("Non-Volatile Bit Rate (kbps) : %s\n", val2str(params.non_volatile_bit_rate, ipmi_bit_rate_vals)); printf("Payload Channel : %d (0x%02x)\n", params.payload_channel, params.payload_channel); printf("Payload Port : %d\n", params.payload_port); } return 0; } /* * Small function to validate that user-supplied SOL * configuration parameter values we store in uint8_t * data type falls within valid range. With minval * and maxval parameters we can use the same function * to validate parameters that have different ranges * of values. * * function will return -1 if value is not valid, or * will return 0 if valid. */ int ipmi_sol_set_param_isvalid_uint8_t( const char *strval, const char *name, int base, uint8_t minval, uint8_t maxval, uint8_t *out_value) { if (str2uchar(strval, out_value) != 0 || (*out_value < minval) || (*out_value > maxval)) { lprintf(LOG_ERR, "Invalid value %s for parameter %s", strval, name); lprintf(LOG_ERR, "Valid values are %d-%d", minval, maxval); return -1; } return 0; } /* * ipmi_sol_set_param * * Set the specified Serial Over LAN value to the specified * value * * return 0 on success, * -1 on failure */ static int ipmi_sol_set_param(struct ipmi_intf * intf, uint8_t channel, const char * param, const char * value, uint8_t guarded) { struct ipmi_rs * rsp; struct ipmi_rq req; uint8_t data[4]; int bGuarded = guarded; /* Use set-in-progress indicator? */ memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_TRANSPORT; /* 0x0c */ req.msg.cmd = IPMI_SET_SOL_CONFIG_PARAMETERS; /* 0x21 */ req.msg.data = data; data[0] = channel; /* * set-in-progress */ if (! strcmp(param, "set-in-progress")) { bGuarded = 0; /* We _ARE_ the set-in-progress indicator */ req.msg.data_len = 3; data[1] = SOL_PARAMETER_SET_IN_PROGRESS; if (! strcmp(value, "set-complete")) data[2] = 0x00; else if (! strcmp(value, "set-in-progress")) data[2] = 0x01; else if (! strcmp(value, "commit-write")) data[2] = 0x02; else { lprintf(LOG_ERR, "Invalid value %s for parameter %s", value, param); lprintf(LOG_ERR, "Valid values are set-complete, set-in-progress " "and commit-write"); return -1; } } /* * enabled */ else if (! strcmp(param, "enabled")) { req.msg.data_len = 3; data[1] = SOL_PARAMETER_SOL_ENABLE; if (! strcmp(value, "true")) data[2] = 0x01; else if (! strcmp(value, "false")) data[2] = 0x00; else { lprintf(LOG_ERR, "Invalid value %s for parameter %s", value, param); lprintf(LOG_ERR, "Valid values are true and false"); return -1; } } /* * force-payload-encryption */ else if (! strcmp(param, "force-encryption")) { struct sol_config_parameters params; req.msg.data_len = 3; data[1] = SOL_PARAMETER_SOL_AUTHENTICATION; if (! strcmp(value, "true")) data[2] = 0x80; else if (! strcmp(value, "false")) data[2] = 0x00; else { lprintf(LOG_ERR, "Invalid value %s for parameter %s", value, param); lprintf(LOG_ERR, "Valid values are true and false"); return -1; } /* We need other values to complete the request */ if (ipmi_get_sol_info(intf, channel, ¶ms)) { lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", param); return -1; } data[2] |= params.force_authentication? 0x40 : 0x00; data[2] |= params.privilege_level; } /* * force-payload-authentication */ else if (! strcmp(param, "force-authentication")) { struct sol_config_parameters params; req.msg.data_len = 3; data[1] = SOL_PARAMETER_SOL_AUTHENTICATION; if (! strcmp(value, "true")) data[2] = 0x40; else if (! strcmp(value, "false")) data[2] = 0x00; else { lprintf(LOG_ERR, "Invalid value %s for parameter %s", value, param); lprintf(LOG_ERR, "Valid values are true and false"); return -1; } /* We need other values to complete the request */ if (ipmi_get_sol_info(intf, channel, ¶ms)) { lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", param); return -1; } data[2] |= params.force_encryption? 0x80 : 0x00; data[2] |= params.privilege_level; } /* * privilege-level */ else if (! strcmp(param, "privilege-level")) { struct sol_config_parameters params; req.msg.data_len = 3; data[1] = SOL_PARAMETER_SOL_AUTHENTICATION; if (! strcmp(value, "user")) data[2] = 0x02; else if (! strcmp(value, "operator")) data[2] = 0x03; else if (! strcmp(value, "admin")) data[2] = 0x04; else if (! strcmp(value, "oem")) data[2] = 0x05; else { lprintf(LOG_ERR, "Invalid value %s for parameter %s", value, param); lprintf(LOG_ERR, "Valid values are user, operator, admin, and oem"); return -1; } /* We need other values to complete the request */ if (ipmi_get_sol_info(intf, channel, ¶ms)) { lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", param); return -1; } data[2] |= params.force_encryption? 0x80 : 0x00; data[2] |= params.force_authentication? 0x40 : 0x00; } /* * character-accumulate-level */ else if (! strcmp(param, "character-accumulate-level")) { struct sol_config_parameters params; req.msg.data_len = 4; data[1] = SOL_PARAMETER_CHARACTER_INTERVAL; /* validate user-supplied input */ if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 1, 255, &data[2])) return -1; /* We need other values to complete the request */ if (ipmi_get_sol_info(intf, channel, ¶ms)) { lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", param); return -1; } data[3] = params.character_send_threshold; } /* * character-send-threshold */ else if (! strcmp(param, "character-send-threshold")) { struct sol_config_parameters params; req.msg.data_len = 4; data[1] = SOL_PARAMETER_CHARACTER_INTERVAL; /* validate user-supplied input */ if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 255, &data[3])) return -1; /* We need other values to complete the request */ if (ipmi_get_sol_info(intf, channel, ¶ms)) { lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", param); return -1; } data[2] = params.character_accumulate_level; } /* * retry-count */ else if (! strcmp(param, "retry-count")) { struct sol_config_parameters params; req.msg.data_len = 4; data[1] = SOL_PARAMETER_SOL_RETRY; /* validate user input, 7 is max value */ if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 7, &data[2])) return -1; /* We need other values to complete the request */ if (ipmi_get_sol_info(intf, channel, ¶ms)) { lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", param); return -1; } data[3] = params.retry_interval; } /* * retry-interval */ else if (! strcmp(param, "retry-interval")) { struct sol_config_parameters params; req.msg.data_len = 4; data[1] = SOL_PARAMETER_SOL_RETRY; /* validate user-supplied input */ if (ipmi_sol_set_param_isvalid_uint8_t(value, param, 0, 0, 255, &data[3])) return -1; /* We need other values to complete the request */ if (ipmi_get_sol_info(intf, channel, ¶ms)) { lprintf(LOG_ERR, "Error fetching SOL parameters for %s update", param); return -1; } data[2] = params.retry_count; } /* * non-volatile-bit-rate */ else if (! strcmp(param, "non-volatile-bit-rate")) { req.msg.data_len = 3; data[1] = SOL_PARAMETER_SOL_NON_VOLATILE_BIT_RATE; if (!strcmp(value, "serial")) { data[2] = 0x00; } else if (!strcmp(value, "9.6")) { data[2] = 0x06; } else if (!strcmp(value, "19.2")) { data[2] = 0x07; } else if (!strcmp(value, "38.4")) { data[2] = 0x08; } else if (!strcmp(value, "57.6")) { data[2] = 0x09; } else if (!strcmp(value, "115.2")) { data[2] = 0x0A; } else { lprintf(LOG_ERR, "Invalid value \"%s\" for parameter \"%s\"", value, param); lprintf(LOG_ERR, "Valid values are serial, 9.6 19.2, 38.4, 57.6 and 115.2"); return -1; } } /* * volatile-bit-rate */ else if (! strcmp(param, "volatile-bit-rate")) { req.msg.data_len = 3; data[1] = SOL_PARAMETER_SOL_VOLATILE_BIT_RATE; if (!strcmp(value, "serial")) { data[2] = 0x00; } else if (!strcmp(value, "9.6")) { data[2] = 0x06; } else if (!strcmp(value, "19.2")) { data[2] = 0x07; } else if (!strcmp(value, "38.4")) { data[2] = 0x08; } else if (!strcmp(value, "57.6")) { data[2] = 0x09; } else if (!strcmp(value, "115.2")) { data[2] = 0x0A; } else { lprintf(LOG_ERR, "Invalid value \"%s\" for parameter \"%s\"", value, param); lprintf(LOG_ERR, "Valid values are serial, 9.6 19.2, 38.4, 57.6 and 115.2"); return -1; } } else { lprintf(LOG_ERR, "Error: invalid SOL parameter %s", param); return -1; } /* * Execute the request */ if (bGuarded && (ipmi_sol_set_param(intf, channel, "set-in-progress", "set-in-progress", bGuarded))) { lprintf(LOG_ERR, "Error: set of parameter \"%s\" failed", param); return -1; } /* The command proper */ rsp = intf->sendrecv(intf, &req); if (rsp == NULL) { lprintf(LOG_ERR, "Error setting SOL parameter '%s'", param); return -1; } if (!(!strncmp(param, "set-in-progress", 15) && !strncmp(value, "commit-write", 12)) && rsp->ccode > 0) { switch (rsp->ccode) { case 0x80: lprintf(LOG_ERR, "Error setting SOL parameter '%s': " "Parameter not supported", param); break; case 0x81: lprintf(LOG_ERR, "Error setting SOL parameter '%s': " "Attempt to set set-in-progress when not in set-complete state", param); break; case 0x82: lprintf(LOG_ERR, "Error setting SOL parameter '%s': " "Attempt to write read-only parameter", param); break; case 0x83: lprintf(LOG_ERR, "Error setting SOL parameter '%s': " "Attempt to read write-only parameter", param); break; default: lprintf(LOG_ERR, "Error setting SOL parameter '%s' to '%s': %s", param, value, val2str(rsp->ccode, completion_code_vals)); break; } if (bGuarded && (ipmi_sol_set_param(intf, channel, "set-in-progress", "set-complete", bGuarded))) { lprintf(LOG_ERR, "Error could not set \"set-in-progress\" " "to \"set-complete\""); } return -1; } /* * The commit write could very well fail, but that's ok. * It may not be implemented. */ if (bGuarded) ipmi_sol_set_param(intf, channel, "set-in-progress", "commit-write", bGuarded); if (bGuarded && ipmi_sol_set_param(intf, channel, "set-in-progress", "set-complete", bGuarded)) { lprintf(LOG_ERR, "Error could not set \"set-in-progress\" " "to \"set-complete\""); return -1; } return 0; } void leave_raw_mode(void) { if (!_in_raw_mode) return; if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1) perror("tcsetattr"); else _in_raw_mode = 0; } void enter_raw_mode(void) { struct termios tio; if (tcgetattr(fileno(stdin), &tio) == -1) { perror("tcgetattr"); return; } _saved_tio = tio; tio.c_iflag |= IGNPAR; tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL); // #ifdef IEXTEN tio.c_lflag &= ~IEXTEN; // #endif tio.c_oflag &= ~OPOST; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1) perror("tcsetattr"); else _in_raw_mode = 1; } static void sendBreak(struct ipmi_intf * intf) { struct ipmi_v2_payload v2_payload; memset(&v2_payload, 0, sizeof(v2_payload)); v2_payload.payload.sol_packet.character_count = 0; v2_payload.payload.sol_packet.generate_break = 1; intf->send_sol(intf, &v2_payload); } /* * suspendSelf * * Put ourself in the background * * param bRestoreTty specifies whether we will put our self back * in raw mode when we resume */ static void suspendSelf(int bRestoreTty) { leave_raw_mode(); kill(getpid(), SIGTSTP); if (bRestoreTty) enter_raw_mode(); } /* * printSolEscapeSequences * * Send some useful documentation to the user */ static void printSolEscapeSequences(struct ipmi_intf * intf) { printf( "%c?\n\ Supported escape sequences:\n\ %c. - terminate connection\n\ %c^Z - suspend ipmitool\n\ %c^X - suspend ipmitool, but don't restore tty on restart\n\ %cB - send break\n\ %c? - this message\n\ %c%c - send the escape character by typing it twice\n\ (Note that escapes are only recognized immediately after newline.)\n", intf->ssn_params.sol_escape_char, intf->ssn_params.sol_escape_char, intf->ssn_params.sol_escape_char, intf->ssn_params.sol_escape_char, intf->ssn_params.sol_escape_char, intf->ssn_params.sol_escape_char, intf->ssn_params.sol_escape_char, intf->ssn_params.sol_escape_char); } /* * output * * Send the specified data to stdout */ static void output(struct ipmi_rs * rsp) { /* Add checks to make sure it is actually SOL data, in general I see * outside code mostly trying to guard against this happening, but * some places fail to do so, so I do so here to make sure nothing gets * through. If non-sol data comes through here, there is probably * a packet that won't get processed somewhere else, but the alternative * of outputting corrupt data is worse. Generally I see the get device * id response make it here somehow. I assume it is a heartbeat and the * other code will retry if it cares about the response and misses it. */ if (rsp && (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) && (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)) { int i; for (i = 0; i < rsp->data_len; ++i) putc(rsp->data[i], stdout); fflush(stdout); } } /* * ipmi_sol_deactivate */ static int ipmi_sol_deactivate(struct ipmi_intf * intf, int instance) { struct ipmi_rs * rsp; struct ipmi_rq req; uint8_t data[6]; if ((instance <= 0) || (instance > 15)) { lprintf(LOG_ERR, "Error: Instance must range from 1 to 15"); return -1; } memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_APP; req.msg.cmd = IPMI_DEACTIVATE_PAYLOAD; req.msg.data_len = 6; req.msg.data = data; memset(data, 0, sizeof(data)); data[0] = IPMI_PAYLOAD_TYPE_SOL; /* payload type */ data[1] = instance; /* payload instance. */ /* Lots of important data */ data[2] = 0; data[3] = 0; data[4] = 0; data[5] = 0; rsp = intf->sendrecv(intf, &req); if (NULL != rsp) { switch (rsp->ccode) { case 0x00: return 0; case 0x80: lprintf(LOG_ERR, "Info: SOL payload already de-activated"); break; case 0x81: lprintf(LOG_ERR, "Info: SOL payload type disabled"); break; default: lprintf(LOG_ERR, "Error de-activating SOL payload: %s", val2str(rsp->ccode, completion_code_vals)); break; } } else { lprintf(LOG_ERR, "Error: No response de-activating SOL payload"); } return -1; } /* * processSolUserInput * * Act on user input into the SOL session. The only reason this * is complicated is that we have to process escape sequences. * * return 0 on success * 1 if we should exit * < 0 on error (BMC probably closed the session) */ static int processSolUserInput( struct ipmi_intf * intf, uint8_t * input, uint16_t buffer_length) { static int escape_pending = 0; static int last_was_cr = 1; struct ipmi_v2_payload v2_payload; int length = 0; int retval = 0; char ch; int i; memset(&v2_payload, 0, sizeof(v2_payload)); /* * Our first order of business is to check the input for escape * sequences to act on. */ for (i = 0; i < buffer_length; ++i) { ch = input[i]; if (escape_pending){ escape_pending = 0; /* * Process a possible escape sequence. */ switch (ch) { case '.': printf("%c. [terminated ipmitool]\n", intf->ssn_params.sol_escape_char); retval = 1; break; case 'Z' - 64: printf("%c^Z [suspend ipmitool]\n", intf->ssn_params.sol_escape_char); suspendSelf(1); /* Restore tty back to raw */ continue; case 'X' - 64: printf("%c^Z [suspend ipmitool]\n", intf->ssn_params.sol_escape_char); suspendSelf(0); /* Don't restore to raw mode */ continue; case 'B': printf("%cB [send break]\n", intf->ssn_params.sol_escape_char); sendBreak(intf); continue; case '?': printSolEscapeSequences(intf); continue; default: if (ch != intf->ssn_params.sol_escape_char) v2_payload.payload.sol_packet.data[length++] = intf->ssn_params.sol_escape_char; v2_payload.payload.sol_packet.data[length++] = ch; } } else { if (last_was_cr && (ch == intf->ssn_params.sol_escape_char)) { escape_pending = 1; continue; } v2_payload.payload.sol_packet.data[length++] = ch; } /* * Normal character. Record whether it was a newline. */ last_was_cr = (ch == '\r' || ch == '\n'); } /* * If there is anything left to process we dispatch it to the BMC, * send intf->session->sol_data.max_outbound_payload_size bytes * at a time. */ if (length) { struct ipmi_rs * rsp = NULL; int try = 0; while (try < intf->ssn_params.retry) { v2_payload.payload.sol_packet.character_count = length; rsp = intf->send_sol(intf, &v2_payload); if (rsp) { break; } usleep(5000); try++; } if (! rsp) { lprintf(LOG_ERR, "Error sending SOL data: FAIL"); retval = -1; } /* If the sequence number is set we know we have new data */ if (retval == 0) if ((rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) && (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) && (rsp->payload.sol_packet.packet_sequence_number)) output(rsp); } return retval; } static int ipmi_sol_keepalive_using_sol(struct ipmi_intf * intf) { struct ipmi_v2_payload v2_payload; struct timeval end; if (_disable_keepalive) return 0; gettimeofday(&end, 0); if (end.tv_sec - _start_keepalive.tv_sec > SOL_KEEPALIVE_TIMEOUT) { memset(&v2_payload, 0, sizeof(v2_payload)); v2_payload.payload.sol_packet.character_count = 0; if (intf->send_sol(intf, &v2_payload) == NULL) return -1; /* good return, reset start time */ gettimeofday(&_start_keepalive, 0); } return 0; } static int ipmi_sol_keepalive_using_getdeviceid(struct ipmi_intf * intf) { struct timeval end; if (_disable_keepalive) return 0; gettimeofday(&end, 0); if (end.tv_sec - _start_keepalive.tv_sec > SOL_KEEPALIVE_TIMEOUT) { if (intf->keepalive(intf) != 0) return -1; /* good return, reset start time */ gettimeofday(&_start_keepalive, 0); } return 0; } /* * ipmi_sol_red_pill */ static int ipmi_sol_red_pill(struct ipmi_intf * intf, int instance) { char * buffer; int numRead; int bShouldExit = 0; int bBmcClosedSession = 0; fd_set read_fds; struct timeval tv; int retval; int buffer_size = intf->session->sol_data.max_inbound_payload_size; int keepAliveRet = 0; int retrySol = 0; /* Subtract SOL header from max_inbound_payload_size */ if (buffer_size > 4) buffer_size -= 4; buffer = (char*)malloc(buffer_size); if (buffer == NULL) { lprintf(LOG_ERR, "ipmitool: malloc failure"); return -1; } /* Initialize keepalive start time */ gettimeofday(&_start_keepalive, 0); enter_raw_mode(); while (! bShouldExit) { FD_ZERO(&read_fds); FD_SET(0, &read_fds); FD_SET(intf->fd, &read_fds); if (!ipmi_oem_active(intf,"i82571spt")) { /* Send periodic keepalive packet */ if(_use_sol_for_keepalive == 0) { keepAliveRet = ipmi_sol_keepalive_using_getdeviceid(intf); } else { keepAliveRet = ipmi_sol_keepalive_using_sol(intf); } if (keepAliveRet != 0) { /* * Retrying the keep Alive before declaring a communication * lost state with the IPMC. Helpful when the payload is * reset and brings down the connection temporarily. Otherwise, * if we send getDevice Id to check the status of IPMC during * this down time when the connection is restarting, SOL will * exit even though the IPMC is available and the session is open. */ if (retrySol == MAX_SOL_RETRY) { /* no response to Get Device ID keepalive message */ bShouldExit = 1; continue; } else { retrySol++; } } else { /* if the keep Alive is successful reset retries to zero */ retrySol = 0; } } /* !oem="i82571spt" */ /* Wait up to half a second */ tv.tv_sec = 0; tv.tv_usec = 500000; retval = select(intf->fd + 1, &read_fds, NULL, NULL, &tv); if (retval) { if (retval == -1) { /* ERROR */ perror("select"); return -1; } /* * Process input from the user */ if (FD_ISSET(0, &read_fds)) { memset(buffer, 0, buffer_size); numRead = read(fileno(stdin), buffer, buffer_size); if (numRead > 0) { int rc = processSolUserInput(intf, (uint8_t *)buffer, numRead); if (rc) { if (rc < 0) bShouldExit = bBmcClosedSession = 1; else bShouldExit = 1; } } else { bShouldExit = 1; } } /* * Process input from the BMC */ else if (FD_ISSET(intf->fd, &read_fds)) { struct ipmi_rs * rs =intf->recv_sol(intf); if (rs) { output(rs); } else { bShouldExit = bBmcClosedSession = 1; } } /* * ERROR in select */ else { lprintf(LOG_ERR, "Error: Select returned with nothing to read"); bShouldExit = 1; } } } leave_raw_mode(); if (keepAliveRet != 0) { lprintf(LOG_ERR, "Error: No response to keepalive - Terminating session"); /* attempt to clean up anyway */ ipmi_sol_deactivate(intf, instance); exit(1); } if (bBmcClosedSession) { lprintf(LOG_ERR, "SOL session closed by BMC"); exit(1); } else ipmi_sol_deactivate(intf, instance); return 0; } /* * ipmi_sol_activate */ static int ipmi_sol_activate(struct ipmi_intf * intf, int looptest, int interval, int instance) { struct ipmi_rs * rsp; struct ipmi_rq req; struct activate_payload_rsp ap_rsp; uint8_t data[6]; uint8_t bSolEncryption = 1; uint8_t bSolAuthentication = 1; /* * This command is only available over RMCP+ (the lanplus * interface). */ if (strncmp(intf->name, "lanplus", 7) != 0) { lprintf(LOG_ERR, "Error: This command is only available over the " "lanplus interface"); return -1; } if ((instance <= 0) || (instance > 15)) { lprintf(LOG_ERR, "Error: Instance must range from 1 to 15"); return -1; } /* * Setup a callback so that the lanplus processing knows what * to do with packets that come unexpectedly (while waiting for * an ACK, perhaps. */ intf->session->sol_data.sol_input_handler = output; memset(&req, 0, sizeof(req)); req.msg.netfn = IPMI_NETFN_APP; req.msg.cmd = IPMI_ACTIVATE_PAYLOAD; req.msg.data_len = 6; req.msg.data = data; data[0] = IPMI_PAYLOAD_TYPE_SOL; /* payload type */ data[1] = instance; /* payload instance */ /* Lots of important data. Most is default */ data[2] = bSolEncryption? 0x80 : 0; data[2] |= bSolAuthentication? 0x40 : 0; data[2] |= IPMI_SOL_SERIAL_ALERT_MASK_DEFERRED; if (ipmi_oem_active(intf, "intelplus")) { data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_TRUE; } else if (ipmi_oem_active(intf, "i82571spt")) { /* * A quote from Intel: "Engineering believes the problem * lies within the Auxiliary data being sent with the * 'Activate Payload' command from IPMITool. IPMITool * sends a C6h which sets some bits having to do with * encryption and some behavior dealing with CTS DCD/DSR. * I recommend that the customer modify this request * to send 08h instead. This is what our internal utility * sends and it works without issue. I will work with * engineering to ensure the settings that IPMITool uses * (C6h) are supported in the future. */ data[2] = 0x08; } else { data[2] |= IPMI_SOL_BMC_ASSERTS_CTS_MASK_FALSE; } data[3] = 0x00; /* reserved */ data[4] = 0x00; /* reserved */ data[5] = 0x00; /* reserved */ rsp = intf->sendrecv(intf, &req); if (NULL != rsp) { switch (rsp->ccode) { case 0x00: if (rsp->data_len == 12) { break; } else { lprintf(LOG_ERR, "Error: Unexpected data length (%d) received " "in payload activation response", rsp->data_len); return -1; } break; case 0x80: lprintf(LOG_ERR, "Info: SOL payload already active on another session"); return -1; case 0x81: lprintf(LOG_ERR, "Info: SOL payload disabled"); return -1; case 0x82: lprintf(LOG_ERR, "Info: SOL payload activation limit reached"); return -1; case 0x83: lprintf(LOG_ERR, "Info: cannot activate SOL payload with encryption"); return -1; case 0x84: lprintf(LOG_ERR, "Info: cannot activate SOL payload without encryption"); return -1; default: lprintf(LOG_ERR, "Error activating SOL payload: %s", val2str(rsp->ccode, completion_code_vals)); return -1; } } else { lprintf(LOG_ERR, "Error: No response activating SOL payload"); return -1; } memcpy(&ap_rsp, rsp->data, sizeof(struct activate_payload_rsp)); intf->session->sol_data.max_inbound_payload_size = (ap_rsp.inbound_payload_size[1] << 8) | ap_rsp.inbound_payload_size[0]; intf->session->sol_data.max_outbound_payload_size = (ap_rsp.outbound_payload_size[1] << 8) | ap_rsp.outbound_payload_size[0]; intf->session->sol_data.port = (ap_rsp.payload_udp_port[1] << 8) | ap_rsp.payload_udp_port[0]; intf->session->timeout = 1; /* NOTE: the spec does allow for SOL traffic to be sent on * a different port. we do not yet support that feature. */ if (intf->session->sol_data.port != intf->ssn_params.port) { /* try byteswapping port in case BMC sent it incorrectly */ uint16_t portswap = BSWAP_16(intf->session->sol_data.port); if (portswap == intf->ssn_params.port) { intf->session->sol_data.port = portswap; } else { lprintf(LOG_ERR, "Error: BMC requests SOL session on different port"); return -1; } } printf("[SOL Session operational. Use %c? for help]\n", intf->ssn_params.sol_escape_char); if(looptest == 1) { ipmi_sol_deactivate(intf, instance); usleep(interval*1000); return 0; } /* * At this point we are good to go with our SOL session. We * need to listen to * 1) STDIN for user input * 2) The FD for incoming SOL packets */ if (ipmi_sol_red_pill(intf, instance)) { lprintf(LOG_ERR, "Error in SOL session"); return -1; } return 0; } /* * print_sol_usage */ static void print_sol_usage(void) { lprintf(LOG_NOTICE, "SOL Commands: info []"); lprintf(LOG_NOTICE, " set [channel]"); lprintf(LOG_NOTICE, " payload [channel] [userid]"); lprintf(LOG_NOTICE, " activate [] [instance=]"); lprintf(LOG_NOTICE, " deactivate [instance=]"); lprintf(LOG_NOTICE, " looptest [ [ []]]"); } /* * print_sol_set_usage */ static void print_sol_set_usage(void) { lprintf(LOG_NOTICE, "\nSOL set parameters and values: \n"); lprintf(LOG_NOTICE, " set-in-progress set-complete | " "set-in-progress | commit-write"); lprintf(LOG_NOTICE, " enabled true | false"); lprintf(LOG_NOTICE, " force-encryption true | false"); lprintf(LOG_NOTICE, " force-authentication true | false"); lprintf(LOG_NOTICE, " privilege-level user | operator | admin | oem"); lprintf(LOG_NOTICE, " character-accumulate-level "); lprintf(LOG_NOTICE, " character-send-threshold N"); lprintf(LOG_NOTICE, " retry-count N"); lprintf(LOG_NOTICE, " retry-interval "); lprintf(LOG_NOTICE, " non-volatile-bit-rate " "serial | 9.6 | 19.2 | 38.4 | 57.6 | 115.2"); lprintf(LOG_NOTICE, " volatile-bit-rate " "serial | 9.6 | 19.2 | 38.4 | 57.6 | 115.2"); lprintf(LOG_NOTICE, ""); } /* ipmi_sol_main */ int ipmi_sol_main(struct ipmi_intf * intf, int argc, char ** argv) { int retval = 0; if (!argc || !strncmp(argv[0], "help", 4)) { /* Help */ print_sol_usage(); } else if (!strncmp(argv[0], "info", 4)) { /* Info */ uint8_t channel; if (argc == 1) { /* Ask about the current channel */ channel = 0x0E; } else if (argc == 2) { if (is_ipmi_channel_num(argv[1], &channel) != 0) { return (-1); } } else { print_sol_usage(); return -1; } retval = ipmi_print_sol_info(intf, channel); } else if (!strncmp(argv[0], "payload", 7)) { /* Payload enable or disable */ uint8_t channel = 0xe; uint8_t userid = 1; int enable = -1; if (argc == 1 || argc > 4) { print_sol_usage(); return -1; } if (argc >= 3) { if (is_ipmi_channel_num(argv[2], &channel) != 0) { return (-1); } } if (argc == 4) { if (is_ipmi_user_id(argv[3], &userid) != 0) { return (-1); } } if (!strncmp(argv[1], "enable", 6)) { enable = 1; } else if (!strncmp(argv[1], "disable", 7)) { enable = 0; } else if (!strncmp(argv[1], "status", 6)) { return ipmi_sol_payload_access_status(intf, channel, userid); } else { print_sol_usage(); return -1; } retval = ipmi_sol_payload_access(intf, channel, userid, enable); } else if (!strncmp(argv[0], "set", 3)) { /* Set a parameter value */ uint8_t channel = 0xe; uint8_t guard = 1; if (argc == 3) { channel = 0xe; } else if (argc == 4) { if (!strncmp(argv[3], "noguard", 7)) { guard = 0; } else { if (is_ipmi_channel_num(argv[3], &channel) != 0) { return (-1); } } } else if (argc == 5) { if (is_ipmi_channel_num(argv[3], &channel) != 0) { return (-1); } if (!strncmp(argv[4], "noguard", 7)) { guard = 0; } } else { print_sol_set_usage(); return -1; } retval = ipmi_sol_set_param(intf, channel, argv[1], argv[2], guard); } else if (!strncmp(argv[0], "activate", 8)) { /* Activate */ int i; uint8_t instance = 1; for (i = 1; i < argc; i++) { if (!strncmp(argv[i], "usesolkeepalive", 15)) { _use_sol_for_keepalive = 1; } else if (!strncmp(argv[i], "nokeepalive", 11)) { _disable_keepalive = 1; } else if (!strncmp(argv[i], "instance=", 9)) { if (str2uchar(argv[i] + 9, &instance) != 0) { lprintf(LOG_ERR, "Given instance '%s' is invalid.", argv[i] + 9); print_sol_usage(); return -1; } } else { print_sol_usage(); return -1; } } retval = ipmi_sol_activate(intf, 0, 0, instance); } else if (!strncmp(argv[0], "deactivate", 10)) { /* Dectivate */ int i; uint8_t instance = 1; for (i = 1; i < argc; i++) { if (!strncmp(argv[i], "instance=", 9)) { if (str2uchar(argv[i] + 9, &instance) != 0) { lprintf(LOG_ERR, "Given instance '%s' is invalid.", argv[i] + 9); print_sol_usage(); return -1; } } else { print_sol_usage(); return -1; } } retval = ipmi_sol_deactivate(intf, instance); } else if (!strncmp(argv[0], "looptest", 8)) { /* SOL loop test: Activate and then Dectivate */ int cnt = 200; int interval = 100; /* Unit is: ms */ uint8_t instance = 1; if (argc > 4) { print_sol_usage(); return -1; } if (argc != 1) { /* at least 2 */ if (str2int(argv[1], &cnt) != 0) { lprintf(LOG_ERR, "Given cnt '%s' is invalid.", argv[1]); return (-1); } if (cnt <= 0) { cnt = 200; } } if (argc >= 3) { if (str2int(argv[2], &interval) != 0) { lprintf(LOG_ERR, "Given interval '%s' is invalid.", argv[2]); return (-1); } if (interval < 0) { interval = 0; } } if (argc >= 4) { if (str2uchar(argv[3], &instance) != 0) { lprintf(LOG_ERR, "Given instance '%s' is invalid.", argv[3]); print_sol_usage(); return -1; } } while (cnt > 0) { printf("remain loop test counter: %d\n", cnt); retval = ipmi_sol_activate(intf, 1, interval, instance); if (retval) { printf("SOL looptest failed: %d\n", retval); break; } cnt -= 1; } } else { print_sol_usage(); retval = -1; } return retval; }