mirror of
https://github.com/ipmitool/ipmitool.git
synced 2025-05-10 18:47:22 +00:00
Cleanup all unused-parameter warnings. Each warning was examined to verify it wasn't simply a case of a build macro difference. Partially resolves ipmitool/ipmitool#13 Signed-off-by: Patrick Venture <venture@google.com>
2083 lines
51 KiB
C
2083 lines
51 KiB
C
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/select.h>
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
|
|
#if defined(HAVE_CONFIG_H)
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#if defined(HAVE_TERMIOS_H)
|
|
# include <termios.h>
|
|
#elif defined (HAVE_SYS_TERMIOS_H)
|
|
# include <sys/termios.h>
|
|
#endif
|
|
|
|
#include <ipmitool/helper.h>
|
|
#include <ipmitool/log.h>
|
|
#include <ipmitool/ipmi.h>
|
|
#include <ipmitool/ipmi_intf.h>
|
|
#include <ipmitool/ipmi_sol.h>
|
|
#include <ipmitool/ipmi_strings.h>
|
|
#include <ipmitool/bswap.h>
|
|
|
|
|
|
#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) {
|
|
lprintf(LOG_ERR, "Error %sabling SOL payload for user %d on channel %d",
|
|
enable ? "en" : "dis", userid, channel);
|
|
rc = (-1);
|
|
} else if (rsp->ccode) {
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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.
|
|
*
|
|
* base parameter currently unused, left in for extension.
|
|
*/
|
|
int ipmi_sol_set_param_isvalid_uint8_t(const char *strval,
|
|
const char *name,
|
|
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, 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, 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, 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, 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) {
|
|
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) {
|
|
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))
|
|
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) {
|
|
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 [<channel number>]");
|
|
lprintf(LOG_NOTICE, " set <parameter> <value> [channel]");
|
|
lprintf(LOG_NOTICE, " payload <enable|disable|status> [channel] [userid]");
|
|
lprintf(LOG_NOTICE, " activate [<usesolkeepalive|nokeepalive>] [instance=<number>]");
|
|
lprintf(LOG_NOTICE, " deactivate [instance=<number>]");
|
|
lprintf(LOG_NOTICE, " looptest [<loop times> [<loop interval(in ms)> [<instance>]]]");
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* 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 <in 5 ms increments>");
|
|
lprintf(LOG_NOTICE, " character-send-threshold N");
|
|
lprintf(LOG_NOTICE, " retry-count N");
|
|
lprintf(LOG_NOTICE, " retry-interval <in 10 ms increments>");
|
|
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)) {
|
|
/* Deactivate */
|
|
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 Deactivate */
|
|
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;
|
|
}
|