diff options
| author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-23 15:03:01 +0200 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2014-07-23 15:03:01 +0200 | 
| commit | 777af8a8761d05c30588abec7444b143fe7393f0 (patch) | |
| tree | 5a135c37eaa9ac94772819a28ce5beedd18e5c4a /lib/ipmi_firewall.c | |
| parent | c3445516ecd58e97de483cf4b7fafcc1104890d7 (diff) | |
| parent | b32d92e890caac903491116e9d817aa780c0323b (diff) | |
Merge tag 'upstream/1.8.14'
Upstream version 1.8.14
Diffstat (limited to 'lib/ipmi_firewall.c')
| -rw-r--r-- | lib/ipmi_firewall.c | 1191 | 
1 files changed, 1191 insertions, 0 deletions
| diff --git a/lib/ipmi_firewall.c b/lib/ipmi_firewall.c new file mode 100644 index 0000000..8bda398 --- /dev/null +++ b/lib/ipmi_firewall.c @@ -0,0 +1,1191 @@ +/* + * 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 * d, 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; +	} + +	d = rsp->data; + +	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; +	} + +	d = rsp->data; +	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}; +	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}; +	struct bmc_fn_support * bmc_fn_support; +	unsigned int l, n, c, ret; +	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}; +	struct bmc_fn_support * bmc_fn_support; +	unsigned int l, n, c, ret; +	unsigned char enables[MAX_COMMAND_BYTES]; + +	if (argc > 0 || (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; n+=2) { +			p.netfn = n; +			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; +} | 
