/*
* Copyright (c) 2005 International Business Machines, Inc. All Rights Reserved.
* 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 <stdio.h>
#include <time.h>
#include <ipmitool/helper.h>
#include <ipmitool/log.h>
#include <ipmitool/bswap.h>
#include <ipmitool/ipmi.h>
#include <ipmitool/ipmi_intf.h>
#include <ipmitool/ipmi_firewall.h>
#include <ipmitool/ipmi_strings.h>
static void
printf_firewall_usage(void)
{
lprintf(LOG_NOTICE,
"Firmware Firewall Commands:");
lprintf(LOG_NOTICE,
"\tinfo [channel H] [lun L]");
lprintf(LOG_NOTICE,
"\tinfo [channel H] [lun L [netfn N [command C [subfn S]]]]");
lprintf(LOG_NOTICE,
"\tenable [channel H] [lun L [netfn N [command C [subfn S]]]]");
lprintf(LOG_NOTICE,
"\tdisable [channel H] [lun L [netfn N [command C [subfn S]]]] [force])");
lprintf(LOG_NOTICE,
"\treset [channel H]");
lprintf(LOG_NOTICE,
"\t\twhere H is a Channel, L is a LUN, N is a NetFn,");
lprintf(LOG_NOTICE,
"\t\tC is a Command and S is a Sub-Function");
}
void
printf_firewall_info_usage(void)
{
lprintf(LOG_NOTICE,
"info [channel H]");
lprintf(LOG_NOTICE,
"\tList all of the firewall information for all LUNs, NetFns");
lprintf(LOG_NOTICE,
"\tand Commands, This is a long list and is not very human readable.");
lprintf(LOG_NOTICE,
"info [channel H] lun L");
lprintf(LOG_NOTICE,
"\tThis also prints a long list that is not very human readable.");
lprintf(LOG_NOTICE,
"info [channel H] lun L netfn N");
lprintf(LOG_NOTICE,
"\tThis prints out information for a single LUN/NetFn pair.");
lprintf(LOG_NOTICE,
"\tThat is not really very usable, but at least it is short.");
lprintf(LOG_NOTICE,
"info [channel H] lun L netfn N command C");
lprintf(LOG_NOTICE,
"\tThis is the one you want -- it prints out detailed human");
lprintf(LOG_NOTICE,
"\treadable information. It shows the support, configurable, and");
lprintf(LOG_NOTICE,
"\tenabled bits for the Command C on LUN/NetFn pair L,N and the");
lprintf(LOG_NOTICE,
"\tsame information about each of its Sub-functions.");
}
// print n bytes of bit field bf (if invert, print ~bf)
static void print_bitfield(const unsigned char * bf, int n, int invert, int loglevel) {
int i = 0;
if (loglevel < 0) {
while (i<n) {
printf("%02x", (unsigned char) (invert?~bf[i]:bf[i]));
if (++i % 4 == 0)
printf(" ");
}
printf("\n");
} else {
while (i<n) {
lprintf(loglevel, "%02x", (unsigned char) (invert?~bf[i]:bf[i]));
if (++i % 4 == 0)
lprintf(loglevel, " ");
}
lprintf(loglevel, "\n");
}
}
static int
ipmi_firewall_parse_args(int argc, char ** argv, struct ipmi_function_params * p)
{
int i;
uint8_t conv_err = 0;
if (!p) {
lprintf(LOG_ERR, "ipmi_firewall_parse_args: p is NULL");
return -1;
}
for (i=0; i<argc; i++) {
if (strncmp(argv[i], "channel", 7) == 0 && (++i < argc)) {
uint8_t channel_tmp = 0;
if (is_ipmi_channel_num(argv[i], &channel_tmp) != 0) {
conv_err = 1;
break;
} else {
p->channel = channel_tmp;
}
}
else if (strncmp(argv[i], "lun", 3) == 0 && (++i < argc)) {
if (str2int(argv[i], &(p->lun)) != 0) {
lprintf(LOG_ERR, "Given lun '%s' is invalid.", argv[i]);
conv_err = 1;
break;
}
}
else if (strncmp(argv[i], "force", 5) == 0) {
p->force = 1;
}
else if (strncmp(argv[i], "netfn", 5) == 0 && (++i < argc)) {
if (str2int(argv[i], &(p->netfn)) != 0) {
lprintf(LOG_ERR, "Given netfn '%s' is invalid.", argv[i]);
conv_err = 1;
break;
}
}
else if (strncmp(argv[i], "command", 7) == 0 && (++i < argc)) {
if (str2int(argv[i], &(p->command)) != 0) {
lprintf(LOG_ERR, "Given command '%s' is invalid.", argv[i]);
conv_err = 1;
break;
}
}
else if (strncmp(argv[i], "subfn", 5) == 0 && (++i < argc)) {
if (str2int(argv[i], &(p->subfn)) != 0) {
lprintf(LOG_ERR, "Given subfn '%s' is invalid.", argv[i]);
conv_err = 1;
break;
}
}
}
if (conv_err != 0) {
return (-1);
}
if (p->subfn >= MAX_SUBFN) {
lprintf(LOG_ERR, "subfn is out of range (0-%d)", MAX_SUBFN-1);
return -1;
}
if (p->command >= MAX_COMMAND) {
lprintf(LOG_ERR, "command is out of range (0-%d)", MAX_COMMAND-1);
return -1;
}
if (p->netfn >= MAX_NETFN) {
lprintf(LOG_ERR, "netfn is out of range (0-%d)", MAX_NETFN-1);
return -1;
}
if (p->lun >= MAX_LUN) {
lprintf(LOG_ERR, "lun is out of range (0-%d)", MAX_LUN-1);
return -1;
}
if (p->netfn >= 0 && p->lun < 0) {
lprintf(LOG_ERR, "if netfn is set, so must be lun");
return -1;
}
if (p->command >= 0 && p->netfn < 0) {
lprintf(LOG_ERR, "if command is set, so must be netfn");
return -1;
}
if (p->subfn >= 0 && p->command < 0) {
lprintf(LOG_ERR, "if subfn is set, so must be command");
return -1;
}
return 0;
}
/* _get_netfn_suport
*
* @intf: ipmi interface
* @channel: ipmi channel
* @lun: a pointer to a 4 byte field
* @netfn: a pointer to a 128-bit bitfield (16 bytes)
*
* returns 0 on success and fills in the bitfield for
* the 32 netfn * 4 LUN pairs that support commands
* returns -1 on error
*/
static int
_get_netfn_support(struct ipmi_intf * intf, int channel, unsigned char * lun, unsigned char * netfn)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
unsigned char * d, rqdata;
unsigned int l;
if (!lun || !netfn) {
lprintf(LOG_ERR, "_get_netfn_suport: lun or netfn is NULL");
return -1;
}
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_GET_NETFN_SUPPORT;
rqdata = (unsigned char) channel;
req.msg.data = &rqdata;
req.msg.data_len = 1;
rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
lprintf(LOG_ERR, "Get NetFn Support command failed");
return -1;
}
if (rsp->ccode > 0) {
lprintf(LOG_ERR, "Get NetFn Support command failed: %s",
val2str(rsp->ccode, completion_code_vals));
return -1;
}
d = rsp->data;
for (l=0; l<4; l++) {
lun[l] = (*d)>>(2*l) & 0x3;
}
d++;
memcpy(netfn, d, 16);
return 0;
}
/* _get_command_suport
*
* @intf: ipmi interface
* @p: a pointer to a struct ipmi_function_params
* @lnfn: a pointer to a struct lun_netfn_support
*
* returns 0 on success and fills in lnfn according to the request in p
* returns -1 on error
*/
static int
_get_command_support(struct ipmi_intf * intf,
struct ipmi_function_params * p, struct lun_netfn_support * lnfn)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
unsigned char * d, rqdata[3];
unsigned int c;
if (!p || !lnfn) {
lprintf(LOG_ERR, "_get_netfn_suport: p or lnfn is NULL");
return -1;
}
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_GET_COMMAND_SUPPORT;
rqdata[0] = (unsigned char) p->channel;
rqdata[1] = p->netfn;
rqdata[2] = p->lun;
req.msg.data = rqdata;
req.msg.data_len = 3;
rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
lprintf(LOG_ERR, "Get Command Support (LUN=%d, NetFn=%d, op=0) command failed", p->lun, p->netfn);
return -1;
}
if (rsp->ccode > 0) {
lprintf(LOG_ERR, "Get Command Support (LUN=%d, NetFn=%d, op=0) command failed: %s",
p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
return -1;
}
d = rsp->data;
for (c=0; c<128; c++) {
if (!(d[c>>3] & (1<<(c%8))))
lnfn->command[c].support |= BIT_AVAILABLE;
}
memcpy(lnfn->command_mask, d, MAX_COMMAND_BYTES/2);
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_GET_COMMAND_SUPPORT;
rqdata[0] = (unsigned char) p->channel;
rqdata[1] = 0x40 | p->netfn;
rqdata[2] = p->lun;
req.msg.data = rqdata;
req.msg.data_len = 3;
rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
lprintf(LOG_ERR, "Get Command Support (LUN=%d, NetFn=%d, op=1) command failed", p->lun, p->netfn);
return -1;
}
if (rsp->ccode > 0) {
lprintf(LOG_ERR, "Get Command Support (LUN=%d, NetFn=%d, op=1) command failed: %s",
p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
return -1;
}
d = rsp->data;
for (c=0; c<128; c++) {
if (!(d[c>>3] & (1<<(c%8))))
lnfn->command[128+c].support |= BIT_AVAILABLE;
}
memcpy(lnfn->command_mask+MAX_COMMAND_BYTES/2, d, MAX_COMMAND_BYTES/2);
return 0;
}
/* _get_command_configurable
*
* @intf: ipmi interface
* @p: a pointer to a struct ipmi_function_params
* @lnfn: a pointer to a struct lun_netfn_support
*
* returns 0 on success and fills in lnfn according to the request in p
* returns -1 on error
*/
static int
_get_command_configurable(struct ipmi_intf * intf,
struct ipmi_function_params * p, struct lun_netfn_support * lnfn)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
unsigned char * d, rqdata[3];
unsigned int c;
if (!p || !lnfn) {
lprintf(LOG_ERR, "_get_command_configurable: p or lnfn is NULL");
return -1;
}
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_GET_CONFIGURABLE_COMMANDS;
rqdata[0] = (unsigned char) p->channel;
rqdata[1] = p->netfn;
rqdata[2] = p->lun;
req.msg.data = rqdata;
req.msg.data_len = 3;
rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
lprintf(LOG_ERR, "Get Configurable Command (LUN=%d, NetFn=%d, op=0) command failed", p->lun, p->netfn);
return -1;
}
if (rsp->ccode > 0) {
lprintf(LOG_ERR, "Get Configurable Command (LUN=%d, NetFn=%d, op=0) command failed: %s",
p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
return -1;
}
d = rsp->data;
for (c=0; c<128; c++) {
if (d[c>>3] & (1<<(c%8)))
lnfn->command[c].support |= BIT_CONFIGURABLE;
}
memcpy(lnfn->config_mask, d, MAX_COMMAND_BYTES/2);
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_GET_CONFIGURABLE_COMMANDS;
rqdata[0] = (unsigned char) p->channel;
rqdata[1] = 0x40 | p->netfn;
rqdata[2] = p->lun;
req.msg.data = rqdata;
req.msg.data_len = 3;
rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
lprintf(LOG_ERR, "Get Configurable Command (LUN=%d, NetFn=%d, op=1) command failed", p->lun, p->netfn);
return -1;
}
if (rsp->ccode > 0) {
lprintf(LOG_ERR, "Get Configurable Command (LUN=%d, NetFn=%d, op=1) command failed: %s",
p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
return -1;
}
d = rsp->data;
for (c=0; c<128; c++) {
if (d[c>>3] & (1<<(c%8)))
lnfn->command[128+c].support |= BIT_CONFIGURABLE;
}
memcpy(lnfn->config_mask+MAX_COMMAND_BYTES/2, d, MAX_COMMAND_BYTES/2);
return 0;
}
/* _get_command_enables
*
* @intf: ipmi interface
* @p: a pointer to a struct ipmi_function_params
* @lnfn: a pointer to a struct lun_netfn_support
*
* returns 0 on success and fills in lnfn according to the request in p
* returns -1 on error
*/
static int
_get_command_enables(struct ipmi_intf * intf,
struct ipmi_function_params * p, struct lun_netfn_support * lnfn)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
unsigned char * d, rqdata[3];
unsigned int c;
if (!p || !lnfn) {
lprintf(LOG_ERR, "_get_command_enables: p or lnfn is NULL");
return -1;
}
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_GET_COMMAND_ENABLES;
rqdata[0] = (unsigned char) p->channel;
rqdata[1] = p->netfn;
rqdata[2] = p->lun;
req.msg.data = rqdata;
req.msg.data_len = 3;
rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
lprintf(LOG_ERR, "Get Command Enables (LUN=%d, NetFn=%d, op=0) command failed", p->lun, p->netfn);
return -1;
}
if (rsp->ccode > 0) {
lprintf(LOG_ERR, "Get Command Enables (LUN=%d, NetFn=%d, op=0) command failed: %s",
p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
return -1;
}
d = rsp->data;
for (c=0; c<128; c++) {
if (d[c>>3] & (1<<(c%8)))
lnfn->command[c].support |= BIT_ENABLED;
}
memcpy(lnfn->enable_mask, d, MAX_COMMAND_BYTES/2);
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_GET_COMMAND_ENABLES;
rqdata[0] = (unsigned char) p->channel;
rqdata[1] = 0x40 | p->netfn;
rqdata[2] = p->lun;
req.msg.data = rqdata;
req.msg.data_len = 3;
rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
lprintf(LOG_ERR, "Get Command Enables (LUN=%d, NetFn=%d, op=1) command failed", p->lun, p->netfn);
return -1;
}
if (rsp->ccode > 0) {
lprintf(LOG_ERR, "Get Command Enables (LUN=%d, NetFn=%d, op=1) command failed: %s",
p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
return -1;
}
d = rsp->data;
for (c=0; c<128; c++) {
if (d[c>>3] & (1<<(c%8)))
lnfn->command[128+c].support |= BIT_ENABLED;
}
memcpy(lnfn->enable_mask+MAX_COMMAND_BYTES/2, d, MAX_COMMAND_BYTES/2);
return 0;
}
/* _set_command_enables
*
* @intf: ipmi interface
* @p: a pointer to a struct ipmi_function_params
* @lnfn: a pointer to a struct lun_netfn_support that contains current info
* @enable: a pointer to a 32 byte bitfield that contains the desired enable state
* @gun: here is a gun to shoot yourself in the foot. If this is true
* you are allowed to disable this command
*
* returns 0 on success
* returns -1 on error
*/
static int
_set_command_enables(struct ipmi_intf * intf,
struct ipmi_function_params * p, struct lun_netfn_support * lnfn,
unsigned char * enable, int gun)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
unsigned char rqdata[19];
unsigned int c;
if (!p || !lnfn) {
lprintf(LOG_ERR, "_set_command_enables: p or lnfn is NULL");
return -1;
}
lprintf(LOG_INFO, "support: ");
print_bitfield(lnfn->command_mask, MAX_COMMAND_BYTES, 1, LOG_INFO);
lprintf(LOG_INFO, "configurable: ");
print_bitfield(lnfn->config_mask, MAX_COMMAND_BYTES, 0, LOG_INFO);
lprintf(LOG_INFO, "enabled: ");
print_bitfield(lnfn->enable_mask, MAX_COMMAND_BYTES, 0, LOG_INFO);
lprintf(LOG_INFO, "enable mask before: ");
print_bitfield(enable, MAX_COMMAND_BYTES, 0, LOG_INFO);
// mask off the appropriate bits (if not configurable, set enable bit
// must be the same as the current enable bit)
for (c=0; c<(MAX_COMMAND_BYTES); c++) {
enable[c] = (lnfn->config_mask[c] & enable[c]) |
(~lnfn->config_mask[c] & lnfn->enable_mask[c]);
}
// take the gun out of their hand if they are not supposed to have it
if (!gun) {
enable[SET_COMMAND_ENABLE_BYTE] =
(lnfn->config_mask[SET_COMMAND_ENABLE_BYTE]
& SET_COMMAND_ENABLE_BIT) |
(~lnfn->config_mask[SET_COMMAND_ENABLE_BYTE]
& lnfn->enable_mask[SET_COMMAND_ENABLE_BYTE]);
}
lprintf(LOG_INFO, "enable mask after: ");
print_bitfield(enable, MAX_COMMAND_BYTES, 0, LOG_INFO);
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_SET_COMMAND_ENABLES;
rqdata[0] = (unsigned char) p->channel;
rqdata[1] = p->netfn;
rqdata[2] = p->lun;
memcpy(&rqdata[3], enable, MAX_COMMAND_BYTES/2);
req.msg.data = rqdata;
req.msg.data_len = 19;
rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
lprintf(LOG_ERR, "Set Command Enables (LUN=%d, NetFn=%d, op=0) command failed", p->lun, p->netfn);
return -1;
}
if (rsp->ccode > 0) {
lprintf(LOG_ERR, "Set Command Enables (LUN=%d, NetFn=%d, op=0) command failed: %s",
p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
return -1;
}
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_SET_COMMAND_ENABLES;
rqdata[0] = (unsigned char) p->channel;
rqdata[1] = 0x40 | p->netfn;
rqdata[2] = p->lun;
memcpy(&rqdata[3], enable+MAX_COMMAND_BYTES/2, MAX_COMMAND_BYTES/2);
req.msg.data = rqdata;
req.msg.data_len = 19;
rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
lprintf(LOG_ERR, "Set Command Enables (LUN=%d, NetFn=%d, op=1) command failed", p->lun, p->netfn);
return -1;
}
if (rsp->ccode > 0) {
lprintf(LOG_ERR, "Set Command Enables (LUN=%d, NetFn=%d, op=1) command failed: %s",
p->lun, p->netfn, val2str(rsp->ccode, completion_code_vals));
return -1;
}
return 0;
}
/* _get_subfn_support
*
* @intf: ipmi interface
* @p: a pointer to a struct ipmi_function_params
* @cmd: a pointer to a struct command_support
*
* returns 0 on success and fills in cmd according to the request in p
* returns -1 on error
*/
static int
_get_subfn_support(struct ipmi_intf * intf,
struct ipmi_function_params * p, struct command_support * cmd)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
unsigned char rqdata[4];
if (!p || !cmd) {
lprintf(LOG_ERR, "_get_subfn_support: p or cmd is NULL");
return -1;
}
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_GET_COMMAND_SUBFUNCTION_SUPPORT;
rqdata[0] = (unsigned char) p->channel;
rqdata[1] = p->netfn;
rqdata[2] = p->lun;
rqdata[3] = p->command;
req.msg.data = rqdata;
req.msg.data_len = 4;
rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
lprintf(LOG_ERR, "Get Command Sub-function Support (LUN=%d, NetFn=%d, command=%d) command failed", p->lun, p->netfn, p->command);
return -1;
}
if (rsp->ccode > 0) {
lprintf(LOG_ERR, "Get Command Sub-function Support (LUN=%d, NetFn=%d, command=%d) command failed: %s",
p->lun, p->netfn, p->command, val2str(rsp->ccode, completion_code_vals));
return -1;
}
memcpy(cmd->subfn_support, rsp->data, sizeof(cmd->subfn_support));
return 0;
}
/* _get_subfn_configurable
*
* @intf: ipmi interface
* @p: a pointer to a struct ipmi_function_params
* @cmd: a pointer to a struct command_support
*
* returns 0 on success and fills in cmd according to the request in p
* returns -1 on error
*/
static int
_get_subfn_configurable(struct ipmi_intf * intf,
struct ipmi_function_params * p, struct command_support * cmd)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
unsigned char rqdata[4];
if (!p || !cmd) {
lprintf(LOG_ERR, "_get_subfn_configurable: p or cmd is NULL");
return -1;
}
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_GET_CONFIGURABLE_COMMAND_SUBFUNCTIONS;
rqdata[0] = (unsigned char) p->channel;
rqdata[1] = p->netfn;
rqdata[2] = p->lun;
rqdata[3] = p->command;
req.msg.data = rqdata;
req.msg.data_len = 4;
rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
lprintf(LOG_ERR, "Get Configurable Command Sub-function (LUN=%d, NetFn=%d, command=%d) command failed", p->lun, p->netfn, p->command);
return -1;
}
if (rsp->ccode > 0) {
lprintf(LOG_ERR, "Get Configurable Command Sub-function (LUN=%d, NetFn=%d, command=%d) command failed: %s",
p->lun, p->netfn, p->command, val2str(rsp->ccode, completion_code_vals));
return -1;
}
memcpy(cmd->subfn_config, rsp->data, sizeof(cmd->subfn_config));
return 0;
}
/* _get_subfn_enables
*
* @intf: ipmi interface
* @p: a pointer to a struct ipmi_function_params
* @cmd: a pointer to a struct command_support
*
* returns 0 on success and fills in cmd according to the request in p
* returns -1 on error
*/
static int
_get_subfn_enables(struct ipmi_intf * intf,
struct ipmi_function_params * p, struct command_support * cmd)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
unsigned char rqdata[4];
if (!p || !cmd) {
lprintf(LOG_ERR, "_get_subfn_enables: p or cmd is NULL");
return -1;
}
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_GET_COMMAND_SUBFUNCTION_ENABLES;
rqdata[0] = (unsigned char) p->channel;
rqdata[1] = p->netfn;
rqdata[2] = p->lun;
rqdata[3] = p->command;
req.msg.data = rqdata;
req.msg.data_len = 4;
rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
lprintf(LOG_ERR, "Get Command Sub-function Enables (LUN=%d, NetFn=%d, command=%d) command failed", p->lun, p->netfn, p->command);
return -1;
}
if (rsp->ccode > 0) {
lprintf(LOG_ERR, "Get Command Sub-function Enables (LUN=%d, NetFn=%d, command=%d) command failed: %s",
p->lun, p->netfn, p->command, val2str(rsp->ccode, completion_code_vals));
return -1;
}
memcpy(cmd->subfn_enable, rsp->data, sizeof(cmd->subfn_enable));
return 0;
}
/* _set_subfn_enables
*
* @intf: ipmi interface
* @p: a pointer to a struct ipmi_function_params
* @cmd: a pointer to a struct command_support
* @enable: a pointer to a 4 byte bitfield that contains the desired enable state
*
* returns 0 on success (and modifies enable to be the bits it actually set)
* returns -1 on error
*/
static int
_set_subfn_enables(struct ipmi_intf * intf,
struct ipmi_function_params * p, struct command_support * cmd,
unsigned char * enable)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
unsigned char rqdata[8];
unsigned int c;
if (!p || !cmd) {
lprintf(LOG_ERR, "_set_subfn_enables: p or cmd is NULL");
return -1;
}
lprintf(LOG_INFO, "support: ");
print_bitfield(cmd->subfn_support, MAX_SUBFN_BYTES, 1, LOG_INFO);
lprintf(LOG_INFO, "configurable: ");
print_bitfield(cmd->subfn_config, MAX_SUBFN_BYTES, 0, LOG_INFO);
lprintf(LOG_INFO, "enabled: ");
print_bitfield(cmd->subfn_enable, MAX_SUBFN_BYTES, 0, LOG_INFO);
lprintf(LOG_INFO, "enable mask before: ");
print_bitfield(enable, MAX_SUBFN_BYTES, 0, LOG_INFO);
// mask off the appropriate bits (if not configurable, set enable bit
// must be the same as the current enable bit)
for (c=0; c<sizeof(cmd->subfn_enable); c++) {
enable[c] = (cmd->subfn_config[c] & enable[c]) |
(~cmd->subfn_config[c] & cmd->subfn_enable[c]);
}
lprintf(LOG_INFO, "enable mask after: ");
print_bitfield(enable, MAX_SUBFN_BYTES, 0, LOG_INFO);
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_APP;
req.msg.cmd = BMC_SET_COMMAND_SUBFUNCTION_ENABLES;
rqdata[0] = (unsigned char) p->channel;
rqdata[1] = p->netfn;
rqdata[2] = p->lun;
rqdata[3] = p->command;
memcpy(&rqdata[4], enable, MAX_SUBFN_BYTES);
req.msg.data = rqdata;
req.msg.data_len = 8;
rsp = intf->sendrecv(intf, &req);
if (rsp == NULL) {
lprintf(LOG_ERR, "Set Command Sub-function Enables (LUN=%d, NetFn=%d, command=%d) command failed", p->lun, p->netfn, p->command);
return -1;
}
if (rsp->ccode > 0) {
lprintf(LOG_ERR, "Set Command Sub-function Enables (LUN=%d, NetFn=%d, command=%d) command failed: %s",
p->lun, p->netfn, p->command, val2str(rsp->ccode, completion_code_vals));
return -1;
}
return 0;
}
/* _gather_info
*
* @intf: ipmi interface
* @p: a pointer to a struct ipmi_function_params
* @bmc: a pointer to a struct bmc_fn_support
* @enable: a pointer to a 4 byte bitfield that contains the desired enable state
*
* returns 0 on success and fills in bmc according to request p
* returns -1 on error
*/
static int _gather_info(struct ipmi_intf * intf, struct ipmi_function_params * p, struct bmc_fn_support * bmc)
{
int ret, l, n;
unsigned char lun[MAX_LUN], netfn[16];
ret = _get_netfn_support(intf, p->channel, lun, netfn);
if (!ret) {
for (l=0; l<MAX_LUN; l++) {
if (p->lun >= 0 && p->lun != l)
continue;
bmc->lun[l].support = lun[l];
if (lun[l]) {
for (n=0; n<MAX_NETFN_PAIR; n++) {
int offset = l*MAX_NETFN_PAIR+n;
bmc->lun[l].netfn[n].support =
!!(netfn[offset>>3] & (1<<(offset%8)));
}
}
}
}
if (p->netfn >= 0) {
if (!((p->lun < 0 || bmc->lun[p->lun].support) &&
(p->netfn < 0 || bmc->lun[p->lun].netfn[p->netfn>>1].support))) {
lprintf(LOG_ERR, "LUN or LUN/NetFn pair %d,%d not supported", p->lun, p->netfn);
return 0;
}
ret = _get_command_support(intf, p, &(bmc->lun[p->lun].netfn[p->netfn>>1]));
ret |= _get_command_configurable(intf, p, &(bmc->lun[p->lun].netfn[p->netfn>>1]));
ret |= _get_command_enables(intf, p, &(bmc->lun[p->lun].netfn[p->netfn>>1]));
if (!ret && p->command >= 0) {
ret = _get_subfn_support(intf, p,
&(bmc->lun[p->lun].netfn[p->netfn>>1].command[p->command]));
ret |= _get_subfn_configurable(intf, p,
&(bmc->lun[p->lun].netfn[p->netfn>>1].command[p->command]));
ret |= _get_subfn_enables(intf, p,
&(bmc->lun[p->lun].netfn[p->netfn>>1].command[p->command]));
}
}
else if (p->lun >= 0) {
l = p->lun;
if (bmc->lun[l].support) {
for (n=0; n<MAX_NETFN_PAIR; n++) {
p->netfn = n*2;
if (bmc->lun[l].netfn[n].support) {
ret = _get_command_support(intf, p, &(bmc->lun[l].netfn[n]));
ret |= _get_command_configurable(intf, p, &(bmc->lun[l].netfn[n]));
ret |= _get_command_enables(intf, p, &(bmc->lun[l].netfn[n]));
}
if (ret)
bmc->lun[l].netfn[n].support = 0;
}
}
p->netfn = -1;
} else {
for (l=0; l<4; l++) {
p->lun = l;
if (bmc->lun[l].support) {
for (n=0; n<MAX_NETFN_PAIR; n++) {
p->netfn = n*2;
if (bmc->lun[l].netfn[n].support) {
ret = _get_command_support(intf, p, &(bmc->lun[l].netfn[n]));
ret |= _get_command_configurable(intf, p, &(bmc->lun[l].netfn[n]));
ret |= _get_command_enables(intf, p, &(bmc->lun[l].netfn[n]));
}
if (ret)
bmc->lun[l].netfn[n].support = 0;
}
}
}
p->lun = -1;
p->netfn = -1;
}
return 0;
}
/* ipmi_firewall_info - print out info for firewall functions
*
* @intf: ipmi inteface
* @argc: argument count
* @argv: argument list
*
* returns 0 on success
* returns -1 on error
*/
static int
ipmi_firewall_info(struct ipmi_intf * intf, int argc, char ** argv)
{
int ret = 0;
struct ipmi_function_params p = {0xe, -1, -1, -1, -1, 0};
struct bmc_fn_support * bmc_fn_support;
unsigned int l, n, c;
if ((argc > 0 && strncmp(argv[0], "help", 4) == 0) || ipmi_firewall_parse_args(argc, argv, &p) < 0)
{
printf_firewall_info_usage();
return 0;
}
bmc_fn_support = malloc(sizeof(struct bmc_fn_support));
if (!bmc_fn_support) {
lprintf(LOG_ERR, "malloc struct bmc_fn_support failed");
return -1;
}
ret = _gather_info(intf, &p, bmc_fn_support);
if (p.command >= 0) {
struct command_support * cmd;
if (!((p.lun < 0 || bmc_fn_support->lun[p.lun].support) &&
(p.netfn < 0 || bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].support) &&
bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].command[p.command].support))
{
lprintf(LOG_ERR, "Command 0x%02x not supported on LUN/NetFn pair %02x,%02x",
p.command, p.lun, p.netfn);
free(bmc_fn_support);
bmc_fn_support = NULL;
return 0;
}
cmd =
&bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].command[p.command];
c = cmd->support;
printf("(A)vailable, (C)onfigurable, (E)nabled: | A | C | E |\n");
printf("-----------------------------------------------------\n");
printf("LUN %01d, NetFn 0x%02x, Command 0x%02x: | %c | %c | %c |\n",
p.lun, p.netfn, p.command,
(c & BIT_AVAILABLE) ? 'X' : ' ',
(c & BIT_CONFIGURABLE) ? 'X' : ' ',
(c & BIT_ENABLED) ? 'X': ' ');
for (n=0; n<MAX_SUBFN; n++) {
printf("sub-function 0x%02x: | %c | %c | %c |\n", n,
(!bit_test(cmd->subfn_support, n)) ? 'X' : ' ',
(bit_test(cmd->subfn_config, n)) ? 'X' : ' ',
(bit_test(cmd->subfn_enable, n)) ? 'X' : ' ');
}
}
else if (p.netfn >= 0) {
if (!((p.lun < 0 || bmc_fn_support->lun[p.lun].support) &&
(bmc_fn_support->lun[p.lun].netfn[p.netfn>>1].support)))
{
lprintf(LOG_ERR, "LUN or LUN/NetFn pair %02x,%02x not supported",
p.lun, p.netfn);
free(bmc_fn_support);
bmc_fn_support = NULL;
return 0;
}
n = p.netfn >> 1;
l = p.lun;
printf("Commands on LUN 0x%02x, NetFn 0x%02x\n", p.lun, p.netfn);
printf("support: ");
print_bitfield(bmc_fn_support->lun[l].netfn[n].command_mask,
MAX_COMMAND_BYTES, 1, -1);
printf("configurable: ");
print_bitfield(bmc_fn_support->lun[l].netfn[n].config_mask,
MAX_COMMAND_BYTES, 0, -1);
printf("enabled: ");
print_bitfield(bmc_fn_support->lun[l].netfn[n].enable_mask,
MAX_COMMAND_BYTES, 0, -1);
}
else {
for (l=0; l<4; l++) {
p.lun = l;
if (bmc_fn_support->lun[l].support) {
for (n=0; n<MAX_NETFN_PAIR; n++) {
p.netfn = n*2;
if (bmc_fn_support->lun[l].netfn[n].support) {
printf("%02x,%02x support: ", p.lun, p.netfn);
print_bitfield(bmc_fn_support->lun[l].netfn[n].command_mask,
MAX_COMMAND_BYTES, 1, -1);
printf("%02x,%02x configurable: ", p.lun, p.netfn);
print_bitfield(bmc_fn_support->lun[l].netfn[n].config_mask,
MAX_COMMAND_BYTES, 0, -1);
printf("%02x,%02x enabled: ", p.lun, p.netfn);
print_bitfield(bmc_fn_support->lun[l].netfn[n].enable_mask,
MAX_COMMAND_BYTES, 0, -1);
}
}
}
}
p.lun = -1;
p.netfn = -1;
}
free(bmc_fn_support);
bmc_fn_support = NULL;
return ret;
}
/* ipmi_firewall_enable_disable - enable/disable BMC functions
*
* @intf: ipmi inteface
* @enable: whether to enable or disable
* @argc: argument count
* @argv: argument list
*
* returns 0 on success
* returns -1 on error
*/
static int
ipmi_firewall_enable_disable(struct ipmi_intf * intf, int enable, int argc, char ** argv)
{
struct ipmi_function_params p = {0xe, -1, -1, -1, -1, 0};
struct bmc_fn_support * bmc_fn_support;
int ret;
unsigned int l, n, c;
unsigned char enables[MAX_COMMAND_BYTES];
if (argc < 1 || strncmp(argv[0], "help", 4) == 0) {
char * s1 = enable?"en":"dis";
char * s2 = enable?"":" [force]";
printf("%sable [channel H] lun L netfn N%s\n", s1, s2);
printf("\t%sable all commands on this LUN/NetFn pair\n", s1);
printf("%sable [channel H] lun L netfn N command C%s\n", s1, s2);
printf("\t%sable Command C and all its Sub-functions for this LUN/NetFn pair\n", s1);
printf("%sable [channel H] lun L netfn N command C subfn S\n", s1);
printf("\t%sable Sub-function S for Command C for this LUN/NetFn pair\n", s1);
if (!enable) {
printf("* force will allow you to disable the \"Command Set Enable\" command\n");
printf("\tthereby letting you shoot yourself in the foot\n");
printf("\tthis is only recommended for advanced users\n");
}
return 0;
}
if (ipmi_firewall_parse_args(argc, argv, &p) < 0)
return -1;
bmc_fn_support = malloc(sizeof(struct bmc_fn_support));
if (!bmc_fn_support) {
lprintf(LOG_ERR, "malloc struct bmc_fn_support failed");
return -1;
}
ret = _gather_info(intf, &p, bmc_fn_support);
if (ret < 0) {
free(bmc_fn_support);
bmc_fn_support = NULL;
return ret;
}
l = p.lun;
n = p.netfn>>1;
c = p.command;
if (p.subfn >= 0) {
// firewall (en|dis)able [channel c] lun l netfn n command m subfn s
// (en|dis)able this sub-function for this commnad on this lun/netfn pair
memcpy(enables,
bmc_fn_support->lun[l].netfn[n].command[c].subfn_enable,
MAX_SUBFN_BYTES);
bit_set(enables, p.subfn, enable);
ret = _set_subfn_enables(intf, &p,
&bmc_fn_support->lun[l].netfn[n].command[c], enables);
} else if (p.command >= 0) {
// firewall (en|dis)able [channel c] lun l netfn n command m
// (en|dis)able all subfn and command for this commnad on this lun/netfn pair
memset(enables, enable?0xff:0, MAX_SUBFN_BYTES);
ret = _set_subfn_enables(intf, &p,
&bmc_fn_support->lun[l].netfn[n].command[c], enables);
memcpy(enables,
&bmc_fn_support->lun[l].netfn[n].enable_mask, sizeof(enables));
bit_set(enables, p.command, enable);
ret |= _set_command_enables(intf, &p,
&bmc_fn_support->lun[l].netfn[n], enables, p.force);
} else if (p.netfn >= 0) {
// firewall (en|dis)able [channel c] lun l netfn n
// (en|dis)able all commnads on this lun/netfn pair
memset(enables, enable?0xff:0, sizeof(enables));
ret = _set_command_enables(intf, &p,
&bmc_fn_support->lun[l].netfn[n], enables, p.force);
/*
} else if (p.lun >= 0) {
// firewall (en|dis)able [channel c] lun l
// (en|dis)able all commnads on all netfn pairs for this lun
*/
}
free(bmc_fn_support);
bmc_fn_support = NULL;
return ret;
}
/* ipmi_firewall_reset - reset firmware firewall to enable everything
*
* @intf: ipmi inteface
* @argc: argument count
* @argv: argument list
*
* returns 0 on success
* returns -1 on error
*/
static int
ipmi_firewall_reset(struct ipmi_intf * intf, int argc, char ** argv)
{
struct ipmi_function_params p = {0xe, -1, -1, -1, -1, 0};
struct bmc_fn_support * bmc_fn_support;
int ret;
unsigned int l, n, c;
unsigned char enables[MAX_COMMAND_BYTES];
if (argc < 1) {
lprintf(LOG_ERR, "Not enough parameters given.");
printf_firewall_usage();
return (-1);
} else if (argc > 0 && strncmp(argv[0], "help", 4) == 0) {
printf_firewall_usage();
return 0;
}
if (ipmi_firewall_parse_args(argc, argv, &p) < 0)
return -1;
bmc_fn_support = malloc(sizeof(struct bmc_fn_support));
if (!bmc_fn_support) {
lprintf(LOG_ERR, "malloc struct bmc_fn_support failed");
return -1;
}
ret = _gather_info(intf, &p, bmc_fn_support);
if (ret < 0) {
free(bmc_fn_support);
bmc_fn_support = NULL;
return ret;
}
for (l=0; l<MAX_LUN; l++) {
p.lun = l;
for (n=0; n<MAX_NETFN_PAIR; n++) {
p.netfn = n*2;
for (c=0; c<MAX_COMMAND; c++) {
p.command = c;
printf("reset lun %d, netfn %d, command %d, subfn\n", l, n, c);
memset(enables, 0xff, MAX_SUBFN_BYTES);
ret = _set_subfn_enables(intf, &p,
&bmc_fn_support->lun[l].netfn[n].command[c], enables);
}
printf("reset lun %d, netfn %d, command\n", l, n);
memset(enables, 0xff, sizeof(enables));
ret = _set_command_enables(intf, &p,
&bmc_fn_support->lun[l].netfn[n], enables, 0);
}
}
free(bmc_fn_support);
bmc_fn_support = NULL;
return ret;
}
/* ipmi_firewall_main - top-level handler for firmware firewall functions
*
* @intf: ipmi interface
* @argc: number of arguments
* @argv: argument list
*
* returns 0 on success
* returns -1 on error
*/
int
ipmi_firewall_main(struct ipmi_intf * intf, int argc, char ** argv)
{
int rc = 0;
if (argc < 1 || strncmp(argv[0], "help", 4) == 0) {
printf_firewall_usage();
}
else if (strncmp(argv[0], "info", 4) == 0) {
rc = ipmi_firewall_info(intf, argc-1, &(argv[1]));
}
else if (strncmp(argv[0], "enable", 6) == 0) {
rc = ipmi_firewall_enable_disable(intf, 1, argc-1, &(argv[1]));
}
else if (strncmp(argv[0], "disable", 7) == 0) {
rc = ipmi_firewall_enable_disable(intf, 0, argc-1, &(argv[1]));
}
else if (strncmp(argv[0], "reset", 5) == 0) {
rc = ipmi_firewall_reset(intf, argc-1, &(argv[1]));
}
else {
printf_firewall_usage();
}
return rc;
}