diff options
Diffstat (limited to 'lib/ipmi_lanp.c')
-rw-r--r-- | lib/ipmi_lanp.c | 2352 |
1 files changed, 2352 insertions, 0 deletions
diff --git a/lib/ipmi_lanp.c b/lib/ipmi_lanp.c new file mode 100644 index 0000000..060e753 --- /dev/null +++ b/lib/ipmi_lanp.c @@ -0,0 +1,2352 @@ +/* + * 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 <stdio.h> +#include <string.h> +#include <strings.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <errno.h> +#include <unistd.h> +#include <signal.h> +#include <setjmp.h> +#include <netdb.h> +#include <limits.h> + +#include <ipmitool/ipmi.h> +#include <ipmitool/log.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/helper.h> +#include <ipmitool/ipmi_constants.h> +#include <ipmitool/ipmi_strings.h> +#include <ipmitool/ipmi_lanp.h> +#include <ipmitool/ipmi_channel.h> + +extern int verbose; + +/* is_lan_channel - Check if channel is LAN medium + * + * return 1 if channel is LAN + * return 0 if channel is not LAN + * + * @intf: ipmi interface handle + * @chan: channel number to check + */ +static int +is_lan_channel(struct ipmi_intf * intf, uint8_t chan) +{ + uint8_t medium; + + if (chan < 1 || chan > IPMI_CHANNEL_NUMBER_MAX) + return 0; + + medium = ipmi_get_channel_medium(intf, chan); + + if (medium == IPMI_CHANNEL_MEDIUM_LAN || + medium == IPMI_CHANNEL_MEDIUM_LAN_OTHER) + return 1; + + return 0; +} + +/* find_lan_channel - Find first channel that is LAN + * + * return channel number if successful + * return 0 if no lan channel found, which is not a valid LAN channel + * + * @intf: ipmi interface handle + * @start: channel number to start searching from + */ +static uint8_t +find_lan_channel(struct ipmi_intf * intf, uint8_t start) +{ + uint8_t chan = 0; + + for (chan = start; chan < IPMI_CHANNEL_NUMBER_MAX; chan++) { + if (is_lan_channel(intf, chan)) { + return chan; + } + } + return 0; +} + +/* get_lan_param_select - Query BMC for LAN parameter data + * + * return pointer to lan_param if successful + * if parameter not supported then + * return pointer to lan_param with + * lan_param->data == NULL and lan_param->data_len == 0 + * return NULL on error + * + * @intf: ipmi interface handle + * @chan: ipmi channel + * @param: lan parameter id + * @select: lan parameter set selector + */ +static struct lan_param * +get_lan_param_select(struct ipmi_intf * intf, uint8_t chan, int param, int select) +{ + struct lan_param * p = NULL; + struct ipmi_rs * rsp; + struct ipmi_rq req; + int i = 0; + uint8_t msg_data[4]; + + for (i = 0; ipmi_lan_params[i].cmd != (-1); i++) { + if (ipmi_lan_params[i].cmd == param) { + p = &ipmi_lan_params[i]; + break; + } + } + + if (p == NULL) { + lprintf(LOG_INFO, "Get LAN Parameter failed: Unknown parameter."); + return NULL; + } + + msg_data[0] = chan; + msg_data[1] = p->cmd; + msg_data[2] = select; + msg_data[3] = 0; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_TRANSPORT; + req.msg.cmd = IPMI_LAN_GET_CONFIG; + req.msg.data = msg_data; + req.msg.data_len = 4; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_INFO, "Get LAN Parameter '%s' command failed", p->desc); + return NULL; + } + + switch (rsp->ccode) + { + case 0x00: /* successful */ + break; + + case 0x80: /* parameter not supported */ + case 0xc9: /* parameter out of range */ + case 0xcc: /* invalid data field in request */ + + /* these completion codes usually mean parameter not supported */ + lprintf(LOG_INFO, "Get LAN Parameter '%s' command failed: %s", + p->desc, val2str(rsp->ccode, completion_code_vals)); + p->data = NULL; + p->data_len = 0; + return p; + + default: + + /* other completion codes are treated as error */ + lprintf(LOG_INFO, "Get LAN Parameter '%s' command failed: %s", + p->desc, val2str(rsp->ccode, completion_code_vals)); + return NULL; + } + + p->data = rsp->data + 1; + p->data_len = rsp->data_len - 1; + + return p; +} + +/* get_lan_param - Query BMC for LAN parameter data + * + * return pointer to lan_param if successful + * if parameter not supported then + * return pointer to lan_param with + * lan_param->data == NULL and lan_param->data_len == 0 + * return NULL on error + * + * @intf: ipmi interface handle + * @chan: ipmi channel + * @param: lan parameter id + */ +static struct lan_param * +get_lan_param(struct ipmi_intf * intf, uint8_t chan, int param) +{ + return get_lan_param_select(intf, chan, param, 0); +} + +/* set_lan_param_wait - Wait for Set LAN Parameter command to complete + * + * On some systems this can take unusually long so we wait for the write + * to take effect and verify that the data was written successfully + * before continuing or retrying. + * + * returns 0 on success + * returns -1 on error + * + * @intf: ipmi interface handle + * @chan: ipmi channel + * @param: lan parameter id + * @data: lan parameter data + * @len: length of lan parameter data + */ +static int +set_lan_param_wait(struct ipmi_intf * intf, uint8_t chan, + int param, uint8_t * data, int len) +{ + struct lan_param * p; + int retry = 10; /* 10 retries */ + + lprintf(LOG_DEBUG, "Waiting for Set LAN Parameter to complete..."); + if (verbose > 1) + printbuf(data, len, "SET DATA"); + + for (;;) { + p = get_lan_param(intf, chan, param); + if (p == NULL) { + sleep(IPMI_LANP_TIMEOUT); + if (retry-- == 0) + return -1; + continue; + } + if (verbose > 1) + printbuf(p->data, p->data_len, "READ DATA"); + if (p->data_len != len) { + sleep(IPMI_LANP_TIMEOUT); + if (retry-- == 0) { + lprintf(LOG_WARNING, "Mismatched data lengths: %d != %d", + p->data_len, len); + return -1; + } + continue; + } + if (memcmp(data, p->data, len) != 0) { + sleep(IPMI_LANP_TIMEOUT); + if (retry-- == 0) { + lprintf(LOG_WARNING, "LAN Parameter Data does not match! " + "Write may have failed."); + return -1; + } + continue; + } + break; + } + return 0; +} + +/* __set_lan_param - Write LAN Parameter data to BMC + * + * This function does the actual work of writing the LAN parameter + * to the BMC and calls set_lan_param_wait() if requested. + * + * returns 0 on success + * returns -1 on error + * + * @intf: ipmi interface handle + * @chan: ipmi channel + * @param: lan parameter id + * @data: lan parameter data + * @len: length of lan parameter data + * @wait: whether to wait for write completion + */ +static int +__set_lan_param(struct ipmi_intf * intf, uint8_t chan, + int param, uint8_t * data, int len, int wait) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t msg_data[32]; + + if (param < 0) + return -1; + + msg_data[0] = chan; + msg_data[1] = param; + + memcpy(&msg_data[2], data, len); + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_TRANSPORT; + req.msg.cmd = IPMI_LAN_SET_CONFIG; + req.msg.data = msg_data; + req.msg.data_len = len+2; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Set LAN Parameter failed"); + return -1; + } + if ((rsp->ccode > 0) && (wait != 0)) { + lprintf(LOG_DEBUG, "Warning: Set LAN Parameter failed: %s", + val2str(rsp->ccode, completion_code_vals)); + if (rsp->ccode == 0xcc) { + /* retry hack for invalid data field ccode */ + int retry = 10; /* 10 retries */ + lprintf(LOG_DEBUG, "Retrying..."); + for (;;) { + if (retry-- == 0) + break; + sleep(IPMI_LANP_TIMEOUT); + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) + continue; + if (rsp->ccode > 0) + continue; + return set_lan_param_wait(intf, chan, param, data, len); + } + } + else if (rsp->ccode != 0xff) { + /* let 0xff ccode continue */ + return -1; + } + } + + if (wait == 0) + return 0; + return set_lan_param_wait(intf, chan, param, data, len); +} + +/* ipmi_lanp_lock_state - Retrieve set-in-progress status + * + * returns one of: + * IPMI_LANP_WRITE_UNLOCK + * IPMI_LANP_WRITE_LOCK + * IPMI_LANP_WRITE_COMMIT + * -1 on error/if not supported + * + * @intf: ipmi interface handle + * @chan: ipmi channel + */ +static int +ipmi_lanp_lock_state(struct ipmi_intf * intf, uint8_t chan) +{ + struct lan_param * p; + p = get_lan_param(intf, chan, IPMI_LANP_SET_IN_PROGRESS); + if (p == NULL) + return -1; + if (p->data == NULL) + return -1; + return (p->data[0] & 3); +} + +/* ipmi_lanp_lock - Lock set-in-progress bits for our use + * + * Write to the Set-In-Progress LAN parameter to indicate + * to other management software that we are modifying parameters. + * + * No meaningful return value because this is an optional + * requirement in IPMI spec and not found on many BMCs. + * + * @intf: ipmi interface handle + * @chan: ipmi channel + */ +static void +ipmi_lanp_lock(struct ipmi_intf * intf, uint8_t chan) +{ + uint8_t val = IPMI_LANP_WRITE_LOCK; + int retry = 3; + + for (;;) { + int state = ipmi_lanp_lock_state(intf, chan); + if (state == -1) + break; + if (state == val) + break; + if (retry-- == 0) + break; + __set_lan_param(intf, chan, IPMI_LANP_SET_IN_PROGRESS, + &val, 1, 0); + } +} + +/* ipmi_lanp_unlock - Unlock set-in-progress bits + * + * Write to the Set-In-Progress LAN parameter, first with + * a "commit" instruction and then unlocking it. + * + * No meaningful return value because this is an optional + * requirement in IPMI spec and not found on many BMCs. + * + * @intf: ipmi interface handle + * @chan: ipmi channel + */ +static void +ipmi_lanp_unlock(struct ipmi_intf * intf, uint8_t chan) +{ + uint8_t val = IPMI_LANP_WRITE_COMMIT; + int rc; + + rc = __set_lan_param(intf, chan, IPMI_LANP_SET_IN_PROGRESS, &val, 1, 0); + if (rc < 0) { + lprintf(LOG_DEBUG, "LAN Parameter Commit not supported"); + } + + val = IPMI_LANP_WRITE_UNLOCK; + __set_lan_param(intf, chan, IPMI_LANP_SET_IN_PROGRESS, &val, 1, 0); +} + +/* set_lan_param - Wrap LAN parameter write with set-in-progress lock + * + * Returns value from __set_lan_param() + * + * @intf: ipmi interface handle + * @chan: ipmi channel + * @param: lan parameter id + * @data: lan parameter data + * @len: length of lan parameter data + */ +static int +set_lan_param(struct ipmi_intf * intf, uint8_t chan, + int param, uint8_t * data, int len) +{ + int rc; + ipmi_lanp_lock(intf, chan); + rc = __set_lan_param(intf, chan, param, data, len, 1); + ipmi_lanp_unlock(intf, chan); + return rc; +} + +/* set_lan_param_nowait - Wrap LAN parameter write without set-in-progress lock + * + * Returns value from __set_lan_param() + * + * @intf: ipmi interface handle + * @chan: ipmi channel + * @param: lan parameter id + * @data: lan parameter data + * @len: length of lan parameter data + */ +static int +set_lan_param_nowait(struct ipmi_intf * intf, uint8_t chan, + int param, uint8_t * data, int len) +{ + int rc; + ipmi_lanp_lock(intf, chan); + rc = __set_lan_param(intf, chan, param, data, len, 0); + ipmi_lanp_unlock(intf, chan); + return rc; +} + +static int +lan_set_arp_interval(struct ipmi_intf * intf, uint8_t chan, uint8_t ival) +{ + struct lan_param *lp; + uint8_t interval = 0; + int rc = 0; + + lp = get_lan_param(intf, chan, IPMI_LANP_GRAT_ARP); + if (lp == NULL) + return -1; + if (lp->data == NULL) + return -1; + + if (ival != 0) { + if (((UINT8_MAX - 1) / 2) < ival) { + lprintf(LOG_ERR, "Given ARP interval '%u' is too big.", ival); + return (-1); + } + interval = (ival * 2) - 1; + rc = set_lan_param(intf, chan, IPMI_LANP_GRAT_ARP, &interval, 1); + } else { + interval = lp->data[0]; + } + + printf("BMC-generated Gratuitous ARP interval: %.1f seconds\n", + (float)((interval + 1) / 2)); + + return rc; +} + +static int +lan_set_arp_generate(struct ipmi_intf * intf, + uint8_t chan, uint8_t ctl) +{ + struct lan_param *lp; + uint8_t data; + + lp = get_lan_param(intf, chan, IPMI_LANP_BMC_ARP); + if (lp == NULL) + return -1; + if (lp->data == NULL) + return -1; + data = lp->data[0]; + + /* set arp generate bitflag */ + if (ctl == 0) + data &= ~0x1; + else + data |= 0x1; + + printf("%sabling BMC-generated Gratuitous ARPs\n", ctl ? "En" : "Dis"); + return set_lan_param(intf, chan, IPMI_LANP_BMC_ARP, &data, 1); +} + +static int +lan_set_arp_respond(struct ipmi_intf * intf, + uint8_t chan, uint8_t ctl) +{ + struct lan_param *lp; + uint8_t data; + + lp = get_lan_param(intf, chan, IPMI_LANP_BMC_ARP); + if (lp == NULL) + return -1; + if (lp->data == NULL) + return -1; + data = lp->data[0]; + + /* set arp response bitflag */ + if (ctl == 0) + data &= ~0x2; + else + data |= 0x2; + + printf("%sabling BMC-generated ARP responses\n", ctl ? "En" : "Dis"); + return set_lan_param(intf, chan, IPMI_LANP_BMC_ARP, &data, 1); +} + + +static char priv_level_to_char(unsigned char priv_level) +{ + char ret = 'X'; + + switch (priv_level) + { + case IPMI_SESSION_PRIV_CALLBACK: + ret = 'c'; + break; + case IPMI_SESSION_PRIV_USER: + ret = 'u'; + break; + case IPMI_SESSION_PRIV_OPERATOR: + ret = 'o'; + break; + case IPMI_SESSION_PRIV_ADMIN: + ret = 'a'; + break; + case IPMI_SESSION_PRIV_OEM: + ret = 'O'; + break; + } + + return ret; +} + + +static int +ipmi_lan_print(struct ipmi_intf * intf, uint8_t chan) +{ + struct lan_param * p; + int rc = 0; + + if (chan < 1 || chan > IPMI_CHANNEL_NUMBER_MAX) { + lprintf(LOG_ERR, "Invalid Channel %d", chan); + return -1; + } + + /* find type of channel and only accept 802.3 LAN */ + if (!is_lan_channel(intf, chan)) { + lprintf(LOG_ERR, "Channel %d is not a LAN channel", chan); + return -1; + } + + p = get_lan_param(intf, chan, IPMI_LANP_SET_IN_PROGRESS); + if (p == NULL) + return -1; + if (p->data != NULL) { + printf("%-24s: ", p->desc); + p->data[0] &= 3; + switch (p->data[0]) { + case 0: + printf("Set Complete\n"); + break; + case 1: + printf("Set In Progress\n"); + break; + case 2: + printf("Commit Write\n"); + break; + case 3: + printf("Reserved\n"); + break; + default: + printf("Unknown\n"); + } + } + + p = get_lan_param(intf, chan, IPMI_LANP_AUTH_TYPE); + if (p == NULL) + return -1; + if (p->data != NULL) { + printf("%-24s: %s%s%s%s%s\n", p->desc, + (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "", + (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "", + (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "", + (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "", + (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : ""); + } + + p = get_lan_param(intf, chan, IPMI_LANP_AUTH_TYPE_ENABLE); + if (p == NULL) + return -1; + if (p->data != NULL) { + printf("%-24s: Callback : %s%s%s%s%s\n", p->desc, + (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "", + (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "", + (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "", + (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "", + (p->data[0] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : ""); + printf("%-24s: User : %s%s%s%s%s\n", "", + (p->data[1] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "", + (p->data[1] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "", + (p->data[1] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "", + (p->data[1] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "", + (p->data[1] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : ""); + printf("%-24s: Operator : %s%s%s%s%s\n", "", + (p->data[2] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "", + (p->data[2] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "", + (p->data[2] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "", + (p->data[2] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "", + (p->data[2] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : ""); + printf("%-24s: Admin : %s%s%s%s%s\n", "", + (p->data[3] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "", + (p->data[3] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "", + (p->data[3] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "", + (p->data[3] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "", + (p->data[3] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : ""); + printf("%-24s: OEM : %s%s%s%s%s\n", "", + (p->data[4] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "", + (p->data[4] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "", + (p->data[4] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "", + (p->data[4] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "", + (p->data[4] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : ""); + } + + p = get_lan_param(intf, chan, IPMI_LANP_IP_ADDR_SRC); + if (p == NULL) + return -1; + if (p->data != NULL) { + printf("%-24s: ", p->desc); + p->data[0] &= 0xf; + switch (p->data[0]) { + case 0: + printf("Unspecified\n"); + break; + case 1: + printf("Static Address\n"); + break; + case 2: + printf("DHCP Address\n"); + break; + case 3: + printf("BIOS Assigned Address\n"); + break; + default: + printf("Other\n"); + break; + } + } + + p = get_lan_param(intf, chan, IPMI_LANP_IP_ADDR); + if (p == NULL) + return -1; + if (p->data != NULL) + printf("%-24s: %d.%d.%d.%d\n", p->desc, + p->data[0], p->data[1], p->data[2], p->data[3]); + + p = get_lan_param(intf, chan, IPMI_LANP_SUBNET_MASK); + if (p == NULL) + return -1; + if (p->data != NULL) + printf("%-24s: %d.%d.%d.%d\n", p->desc, + p->data[0], p->data[1], p->data[2], p->data[3]); + + p = get_lan_param(intf, chan, IPMI_LANP_MAC_ADDR); + if (p == NULL) + return -1; + if (p->data != NULL) + printf("%-24s: %02x:%02x:%02x:%02x:%02x:%02x\n", p->desc, + p->data[0], p->data[1], p->data[2], p->data[3], p->data[4], p->data[5]); + + p = get_lan_param(intf, chan, IPMI_LANP_SNMP_STRING); + if (p == NULL) + return -1; + if (p->data != NULL) + printf("%-24s: %s\n", p->desc, p->data); + + p = get_lan_param(intf, chan, IPMI_LANP_IP_HEADER); + if (p == NULL) + return -1; + if (p->data != NULL) + printf("%-24s: TTL=0x%02x Flags=0x%02x Precedence=0x%02x TOS=0x%02x\n", + p->desc, p->data[0], p->data[1] & 0xe0, p->data[2] & 0xe0, p->data[2] & 0x1e); + + p = get_lan_param(intf, chan, IPMI_LANP_BMC_ARP); + if (p == NULL) + return -1; + if (p->data != NULL) + printf("%-24s: ARP Responses %sabled, Gratuitous ARP %sabled\n", p->desc, + (p->data[0] & 2) ? "En" : "Dis", (p->data[0] & 1) ? "En" : "Dis"); + + p = get_lan_param(intf, chan, IPMI_LANP_GRAT_ARP); + if (p == NULL) + return -1; + if (p->data != NULL) + printf("%-24s: %.1f seconds\n", p->desc, (float)((p->data[0] + 1) / 2)); + + p = get_lan_param(intf, chan, IPMI_LANP_DEF_GATEWAY_IP); + if (p == NULL) + return -1; + if (p->data != NULL) + printf("%-24s: %d.%d.%d.%d\n", p->desc, + p->data[0], p->data[1], p->data[2], p->data[3]); + + p = get_lan_param(intf, chan, IPMI_LANP_DEF_GATEWAY_MAC); + if (p == NULL) + return -1; + if (p->data != NULL) + printf("%-24s: %02x:%02x:%02x:%02x:%02x:%02x\n", p->desc, + p->data[0], p->data[1], p->data[2], p->data[3], p->data[4], p->data[5]); + + p = get_lan_param(intf, chan, IPMI_LANP_BAK_GATEWAY_IP); + if (p == NULL) + return -1; + if (p->data != NULL) + printf("%-24s: %d.%d.%d.%d\n", p->desc, + p->data[0], p->data[1], p->data[2], p->data[3]); + + p = get_lan_param(intf, chan, IPMI_LANP_BAK_GATEWAY_MAC); + if (p == NULL) + return -1; + if (p->data != NULL) + printf("%-24s: %02x:%02x:%02x:%02x:%02x:%02x\n", p->desc, + p->data[0], p->data[1], p->data[2], p->data[3], p->data[4], p->data[5]); + + p = get_lan_param(intf, chan, IPMI_LANP_VLAN_ID); + if (p != NULL && p->data != NULL) { + int id = ((p->data[1] & 0x0f) << 8) + p->data[0]; + if (p->data[1] & 0x80) + printf("%-24s: %d\n", p->desc, id); + else + printf("%-24s: Disabled\n", p->desc); + } + + p = get_lan_param(intf, chan, IPMI_LANP_VLAN_PRIORITY); + if (p != NULL && p->data != NULL) + printf("%-24s: %d\n", p->desc, p->data[0] & 0x07); + + /* Determine supported Cipher Suites -- Requires two calls */ + p = get_lan_param(intf, chan, IPMI_LANP_RMCP_CIPHER_SUPPORT); + if (p == NULL) + return -1; + else if (p->data != NULL) + { + unsigned char cipher_suite_count = p->data[0]; + p = get_lan_param(intf, chan, IPMI_LANP_RMCP_CIPHERS); + if (p == NULL) + return -1; + + printf("%-24s: ", p->desc); + + /* Now we're dangerous. There are only 15 fixed cipher + suite IDs, but the spec allows for 16 in the return data.*/ + if ((p->data != NULL) && (p->data_len <= 17)) + { + unsigned int i; + for (i = 0; (i < 16) && (i < cipher_suite_count); ++i) + { + printf("%s%d", + (i > 0? ",": ""), + p->data[i + 1]); + } + printf("\n"); + } + else + { + printf("None\n"); + } + } + + /* RMCP+ Messaging Cipher Suite Privilege Levels */ + /* These are the privilege levels for the 15 fixed cipher suites */ + p = get_lan_param(intf, chan, IPMI_LANP_RMCP_PRIV_LEVELS); + if (p == NULL) + return -1; + if ((p->data != NULL) && (p->data_len == 9)) + { + printf("%-24s: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", p->desc, + priv_level_to_char(p->data[1] & 0x0F), + priv_level_to_char(p->data[1] >> 4), + priv_level_to_char(p->data[2] & 0x0F), + priv_level_to_char(p->data[2] >> 4), + priv_level_to_char(p->data[3] & 0x0F), + priv_level_to_char(p->data[3] >> 4), + priv_level_to_char(p->data[4] & 0x0F), + priv_level_to_char(p->data[4] >> 4), + priv_level_to_char(p->data[5] & 0x0F), + priv_level_to_char(p->data[5] >> 4), + priv_level_to_char(p->data[6] & 0x0F), + priv_level_to_char(p->data[6] >> 4), + priv_level_to_char(p->data[7] & 0x0F), + priv_level_to_char(p->data[7] >> 4), + priv_level_to_char(p->data[8] & 0x0F)); + + /* Now print a legend */ + printf("%-24s: %s\n", "", " X=Cipher Suite Unused"); + printf("%-24s: %s\n", "", " c=CALLBACK"); + printf("%-24s: %s\n", "", " u=USER"); + printf("%-24s: %s\n", "", " o=OPERATOR"); + printf("%-24s: %s\n", "", " a=ADMIN"); + printf("%-24s: %s\n", "", " O=OEM"); + } + else + printf("%-24s: Not Available\n", p->desc); + + return rc; +} + +/* Configure Authentication Types */ +static int +ipmi_lan_set_auth(struct ipmi_intf * intf, uint8_t chan, char * level, char * types) +{ + uint8_t data[5]; + uint8_t authtype = 0; + char * p; + struct lan_param * lp; + + if (level == NULL || types == NULL) + return -1; + + lp = get_lan_param(intf, chan, IPMI_LANP_AUTH_TYPE_ENABLE); + if (lp == NULL) + return -1; + if (lp->data == NULL) + return -1; + + lprintf(LOG_DEBUG, "%-24s: callback=0x%02x user=0x%02x operator=0x%02x admin=0x%02x oem=0x%02x", + lp->desc, lp->data[0], lp->data[1], lp->data[2], lp->data[3], lp->data[4]); + + memset(data, 0, 5); + memcpy(data, lp->data, 5); + + p = types; + while (p) { + if (strncasecmp(p, "none", 4) == 0) + authtype |= 1 << IPMI_SESSION_AUTHTYPE_NONE; + else if (strncasecmp(p, "md2", 3) == 0) + authtype |= 1 << IPMI_SESSION_AUTHTYPE_MD2; + else if (strncasecmp(p, "md5", 3) == 0) + authtype |= 1 << IPMI_SESSION_AUTHTYPE_MD5; + else if ((strncasecmp(p, "password", 8) == 0) || + (strncasecmp(p, "key", 3) == 0)) + authtype |= 1 << IPMI_SESSION_AUTHTYPE_KEY; + else if (strncasecmp(p, "oem", 3) == 0) + authtype |= 1 << IPMI_SESSION_AUTHTYPE_OEM; + else + lprintf(LOG_WARNING, "Invalid authentication type: %s", p); + p = strchr(p, ','); + if (p) + p++; + } + + p = level; + while (p) { + if (strncasecmp(p, "callback", 8) == 0) + data[0] = authtype; + else if (strncasecmp(p, "user", 4) == 0) + data[1] = authtype; + else if (strncasecmp(p, "operator", 8) == 0) + data[2] = authtype; + else if (strncasecmp(p, "admin", 5) == 0) + data[3] = authtype; + else + lprintf(LOG_WARNING, "Invalid authentication level: %s", p); + p = strchr(p, ','); + if (p) + p++; + } + + if (verbose > 1) + printbuf(data, 5, "authtype data"); + + return set_lan_param(intf, chan, IPMI_LANP_AUTH_TYPE_ENABLE, data, 5); +} + +static int +ipmi_lan_set_password(struct ipmi_intf * intf, + uint8_t userid, uint8_t * password) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t data[18]; + + memset(&data, 0, sizeof(data)); + data[0] = userid & 0x3f;/* user ID */ + data[1] = 0x02; /* set password */ + + if (password != NULL) + memcpy(data+2, password, __min(strlen((const char *)password), 16)); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x47; + req.msg.data = data; + req.msg.data_len = 18; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Unable to Set LAN Password for user %d", userid); + return -1; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Set LAN Password for user %d failed: %s", + userid, val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + /* adjust our session password + * or we will no longer be able to communicate with BMC + */ + ipmi_intf_session_set_password(intf, (char *)password); + printf("Password %s for user %d\n", + (password == NULL) ? "cleared" : "set", userid); + + return 0; +} + +static int +ipmi_set_alert_enable(struct ipmi_intf * intf, uint8_t channel, uint8_t enable) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t rqdata[3]; + + memset(&req, 0, sizeof(req)); + + /* update non-volatile access */ + rqdata[0] = channel; + rqdata[1] = 0x40; + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x41; + req.msg.data = rqdata; + req.msg.data_len = 2; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Unable to Get Channel Access for channel %d", channel); + return -1; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Get Channel Access for channel %d failed: %s", + channel, val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + /* SAVE TO NVRAM */ + memset(rqdata, 0, 3); + rqdata[0] = channel & 0xf; + rqdata[1] = rsp->data[0]; + if (enable != 0) + rqdata[1] &= ~0x20; + else + rqdata[1] |= 0x20; + rqdata[1] |= 0x40; + rqdata[2] = 0; + + req.msg.cmd = 0x40; + req.msg.data_len = 3; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Unable to Set Channel Access for channel %d", channel); + return -1; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Set Channel Access for channel %d failed: %s", + channel, val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + /* SAVE TO CURRENT */ + rqdata[1] &= 0xc0; + rqdata[1] |= 0x80; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Unable to Set Channel Access for channel %d", channel); + return -1; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Set Channel Access for channel %d failed: %s", + channel, val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + return 0; +} + +static int +ipmi_set_channel_access(struct ipmi_intf * intf, uint8_t channel, uint8_t enable) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t rqdata[3]; + uint8_t byteEnable; + + memset(&req, 0, sizeof(req)); + + /* RETREIVE VALUE IN NVRAM */ + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x41; /* Get Channel Access Command */ + req.msg.data = rqdata; + req.msg.data_len = 2; + + memset(rqdata, 0, 2); + rqdata[0] = channel & 0xf; + rqdata[1] = 0x40; /* retreive NV */ + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Unable to Get Channel Access for channel %d", channel); + return -1; + } else if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Set Channel Access for channel %d failed: %s", + channel, val2str(rsp->ccode, completion_code_vals)); + return -1; + } else { + byteEnable = *(rsp->data + 0); + } + + /* SAVE TO NVRAM */ + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x40; /* Set Channel Access Command */ + req.msg.data = rqdata; + req.msg.data_len = 3; + + memset(rqdata, 0, 3); + rqdata[0] = channel & 0xf; + rqdata[1] = 0x40 | (byteEnable & 0x38); /* use previously set values */ + if (enable != 0) + rqdata[1] |= 0x2; /* set always available if enable is set */ + rqdata[2] = 0x44; /* set channel privilege limit to ADMIN */ + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Unable to Set Channel Access for channel %d", channel); + return -1; + } else if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Set Channel Access for channel %d failed: %s", + channel, val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + /* RETREIVE VALUE IN NVRAM */ + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x41; /* Get Channel Access Command */ + req.msg.data = rqdata; + req.msg.data_len = 2; + + memset(rqdata, 0, 2); + rqdata[0] = channel & 0xf; + rqdata[1] = 0x80; /* retreive NV */ + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Unable to Get Channel Access for channel %d", channel); + return -1; + } else if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Set Channel Access for channel %d failed: %s", + channel, val2str(rsp->ccode, completion_code_vals)); + return -1; + } else { + byteEnable = *(rsp->data + 0); + } + + /* SAVE TO CURRENT */ + memset(&req, 0, sizeof(req)); + + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x40; /* Set Channel Access Command */ + req.msg.data = rqdata; + req.msg.data_len = 3; + + memset(rqdata, 0, 3); + rqdata[0] = channel & 0xf; + rqdata[1] = 0x80 | (byteEnable & 0x38); /* use previously set values */ + if (enable != 0) + rqdata[1] |= 0x2; /* set always available if enable is set */ + rqdata[2] = 0x84; /* set channel privilege limit to ADMIN */ + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Unable to Set Channel Access for channel %d", channel); + return -1; + } else if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Set Channel Access for channel %d failed: %s", + channel, val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + /* can't send close session if access off so abort instead */ + if (enable == 0) + intf->abort = 1; + + return 0; +} + +static int +ipmi_set_user_access(struct ipmi_intf * intf, uint8_t channel, uint8_t userid) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t rqdata[4]; + + memset(rqdata, 0, 4); + rqdata[0] = 0x90 | (channel & 0xf); + rqdata[1] = userid & 0x3f; + rqdata[2] = 0x4; + rqdata[3] = 0; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x43; + req.msg.data = rqdata; + req.msg.data_len = 4; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Unable to Set User Access for channel %d", channel); + return -1; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Set User Access for channel %d failed: %s", + channel, val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + return 0; +} + +static int +get_cmdline_macaddr(char * arg, uint8_t * buf) +{ + uint32_t m1, m2, m3, m4, m5, m6; + if (sscanf(arg, "%02x:%02x:%02x:%02x:%02x:%02x", + &m1, &m2, &m3, &m4, &m5, &m6) != 6) { + lprintf(LOG_ERR, "Invalid MAC address: %s", arg); + return -1; + } + buf[0] = (uint8_t)m1; + buf[1] = (uint8_t)m2; + buf[2] = (uint8_t)m3; + buf[3] = (uint8_t)m4; + buf[4] = (uint8_t)m5; + buf[5] = (uint8_t)m6; + return 0; +} + + +static int +get_cmdline_cipher_suite_priv_data(char * arg, uint8_t * buf) +{ + int i, ret = 0; + + if (strlen(arg) != 15) + { + lprintf(LOG_ERR, "Invalid privilege specification length: %d", + strlen(arg)); + return -1; + } + + /* + * The first byte is reserved (0). The rest of the buffer is setup + * so that each nibble holds the maximum privilege level available for + * that cipher suite number. The number of nibbles (15) matches the number + * of fixed cipher suite IDs. This command documentation mentions 16 IDs + * but table 22-19 shows that there are only 15 (0-14). + * + * data 1 - reserved + * data 2 - maximum priv level for first (LSN) and second (MSN) ciphers + * data 3 - maximum priv level for third (LSN) and fourth (MSN) ciphers + * data 9 - maximum priv level for 15th (LSN) cipher. + */ + bzero(buf, 9); + + for (i = 0; i < 15; ++i) + { + unsigned char priv_level = IPMI_SESSION_PRIV_ADMIN; + + switch (arg[i]) + { + case 'X': + priv_level = IPMI_SESSION_PRIV_UNSPECIFIED; /* 0 */ + break; + case 'c': + priv_level = IPMI_SESSION_PRIV_CALLBACK; /* 1 */ + break; + case 'u': + priv_level = IPMI_SESSION_PRIV_USER; /* 2 */ + break; + case 'o': + priv_level = IPMI_SESSION_PRIV_OPERATOR; /* 3 */ + break; + case 'a': + priv_level = IPMI_SESSION_PRIV_ADMIN; /* 4 */ + break; + case 'O': + priv_level = IPMI_SESSION_PRIV_OEM; /* 5 */ + break; + default: + lprintf(LOG_ERR, "Invalid privilege specification char: %c", + arg[i]); + ret = -1; + break; + } + + if (ret != 0) + break; + else + { + if ((i + 1) % 2) + { + // Odd number cipher suites will be in the LSN + buf[1 + (i / 2)] += priv_level; + } + else + { + // Even number cipher suites will be in the MSN + buf[1 + (i / 2)] += (priv_level << 4); + } + } + } + + return ret; +} + + +static int +get_cmdline_ipaddr(char * arg, uint8_t * buf) +{ + uint32_t ip1, ip2, ip3, ip4; + if (sscanf(arg, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) != 4) { + lprintf(LOG_ERR, "Invalid IP address: %s", arg); + return -1; + } + buf[0] = (uint8_t)ip1; + buf[1] = (uint8_t)ip2; + buf[2] = (uint8_t)ip3; + buf[3] = (uint8_t)ip4; + return 0; +} + +static void ipmi_lan_set_usage(void) +{ + lprintf(LOG_NOTICE, "\nusage: lan set <channel> <command> <parameter>\n"); + lprintf(LOG_NOTICE, "LAN set command/parameter options:"); + lprintf(LOG_NOTICE, " ipaddr <x.x.x.x> Set channel IP address"); + lprintf(LOG_NOTICE, " netmask <x.x.x.x> Set channel IP netmask"); + lprintf(LOG_NOTICE, " macaddr <x:x:x:x:x:x> Set channel MAC address"); + lprintf(LOG_NOTICE, " defgw ipaddr <x.x.x.x> Set default gateway IP address"); + lprintf(LOG_NOTICE, " defgw macaddr <x:x:x:x:x:x> Set default gateway MAC address"); + lprintf(LOG_NOTICE, " bakgw ipaddr <x.x.x.x> Set backup gateway IP address"); + lprintf(LOG_NOTICE, " bakgw macaddr <x:x:x:x:x:x> Set backup gateway MAC address"); + lprintf(LOG_NOTICE, " password <password> Set session password for this channel"); + lprintf(LOG_NOTICE, " snmp <community string> Set SNMP public community string"); + lprintf(LOG_NOTICE, " user Enable default user for this channel"); + lprintf(LOG_NOTICE, " access <on|off> Enable or disable access to this channel"); + lprintf(LOG_NOTICE, " alert <on|off> Enable or disable PEF alerting for this channel"); + lprintf(LOG_NOTICE, " arp respond <on|off> Enable or disable BMC ARP responding"); + lprintf(LOG_NOTICE, " arp generate <on|off> Enable or disable BMC gratuitous ARP generation"); + lprintf(LOG_NOTICE, " arp interval <seconds> Set gratuitous ARP generation interval"); + lprintf(LOG_NOTICE, " vlan id <off|<id>> Disable or enable VLAN and set ID (1-4094)"); + lprintf(LOG_NOTICE, " vlan priority <priority> Set vlan priority (0-7)"); + lprintf(LOG_NOTICE, " auth <level> <type,..> Set channel authentication types"); + lprintf(LOG_NOTICE, " level = CALLBACK, USER, OPERATOR, ADMIN"); + lprintf(LOG_NOTICE, " type = NONE, MD2, MD5, PASSWORD, OEM"); + lprintf(LOG_NOTICE, " ipsrc <source> Set IP Address source"); + lprintf(LOG_NOTICE, " none = unspecified source"); + lprintf(LOG_NOTICE, " static = address manually configured to be static"); + lprintf(LOG_NOTICE, " dhcp = address obtained by BMC running DHCP"); + lprintf(LOG_NOTICE, " bios = address loaded by BIOS or system software"); + lprintf(LOG_NOTICE, " cipher_privs XXXXXXXXXXXXXXX Set RMCP+ cipher suite privilege levels"); + lprintf(LOG_NOTICE, " X = Cipher Suite Unused"); + lprintf(LOG_NOTICE, " c = CALLBACK"); + lprintf(LOG_NOTICE, " u = USER"); + lprintf(LOG_NOTICE, " o = OPERATOR"); + lprintf(LOG_NOTICE, " a = ADMIN"); + lprintf(LOG_NOTICE, " O = OEM\n"); +} + +static void +ipmi_lan_set_vlan_usage(void) +{ + lprintf(LOG_NOTICE, + "lan set <channel> vlan id <id>\n" + "lan set <channel> vlan id off\n" + "lan set <channel> vlan priority <priority>\n"); +} + +static int +ipmi_lan_set_vlan_id(struct ipmi_intf * intf, uint8_t chan, char *string) +{ + uint8_t data[2]; + int rc; + + if (string == NULL) { + data[0] = 0; + data[1] = 0; + } + else { + int id = 0; + if (str2int(string, &id) != 0) { + lprintf(LOG_ERR, "Given VLAN ID '%s' is invalid.", string); + return (-1); + } + + if (id < 1 || id > 4094) { + lprintf(LOG_NOTICE, "vlan id must be between 1 and 4094."); + return -1; + } + else { + data[0] = (uint8_t)id; + data[1] = (uint8_t)(id >> 8) | 0x80; + } + } + rc = set_lan_param(intf, chan, IPMI_LANP_VLAN_ID, data, 2); + return rc; +} + +static int +ipmi_lan_set_vlan_priority(struct ipmi_intf * intf, uint8_t chan, char *string) +{ + uint8_t data; + int rc; + int priority = 0; + if (str2int(string, &priority) != 0) { + lprintf(LOG_ERR, "Given VLAN priority '%s' is invalid.", string); + return (-1); + } + + if (priority < 0 || priority > 7) { + lprintf(LOG_NOTICE, "vlan priority must be between 0 and 7."); + return -1; + } + data = (uint8_t)priority; + rc = set_lan_param(intf, chan, IPMI_LANP_VLAN_PRIORITY, &data, 1); + return rc; +} + +static int +ipmi_lan_set(struct ipmi_intf * intf, int argc, char ** argv) +{ + uint8_t data[32]; + uint8_t chan; + int rc = 0; + + if (argc < 2) { + ipmi_lan_set_usage(); + return (-1); + } + + if (strncmp(argv[0], "help", 4) == 0 || + strncmp(argv[1], "help", 4) == 0) { + ipmi_lan_set_usage(); + return 0; + } + + if (str2uchar(argv[0], &chan) != 0) { + lprintf(LOG_ERR, "Invalid channel: %s", argv[0]); + return (-1); + } + + /* find type of channel and only accept 802.3 LAN */ + if (!is_lan_channel(intf, chan)) { + lprintf(LOG_ERR, "Channel %d is not a LAN channel!", chan); + ipmi_lan_set_usage(); + return -1; + } + + memset(&data, 0, sizeof(data)); + + /* set user access */ + if (strncmp(argv[1], "user", 4) == 0) { + rc = ipmi_set_user_access(intf, chan, 1); + } + /* set channel access mode */ + else if (strncmp(argv[1], "access", 6) == 0) { + if (argc < 3) { + lprintf(LOG_NOTICE, "lan set access <on|off>"); + return (-1); + } + else if (strncmp(argv[2], "help", 4) == 0) { + lprintf(LOG_NOTICE, "lan set access <on|off>"); + return 0; + } + else if (strncmp(argv[2], "on", 2) == 0) { + rc = ipmi_set_channel_access(intf, chan, 1); + } + else if (strncmp(argv[2], "off", 3) == 0) { + rc = ipmi_set_channel_access(intf, chan, 0); + } + else { + lprintf(LOG_NOTICE, "lan set access <on|off>"); + return (-1); + } + } + /* set ARP control */ + else if (strncmp(argv[1], "arp", 3) == 0) { + if (argc < 3) { + lprintf(LOG_NOTICE, + "lan set <channel> arp respond <on|off>\n" + "lan set <channel> arp generate <on|off>\n" + "lan set <channel> arp interval <seconds>\n\n" + "example: lan set 7 arp gratuitous off\n"); + return (-1); + } + else if (strncmp(argv[2], "help", 4) == 0) { + lprintf(LOG_NOTICE, + "lan set <channel> arp respond <on|off>\n" + "lan set <channel> arp generate <on|off>\n" + "lan set <channel> arp interval <seconds>\n\n" + "example: lan set 7 arp gratuitous off\n"); + return 0; + } + else if (strncmp(argv[2], "interval", 8) == 0) { + uint8_t interval = 0; + if (str2uchar(argv[3], &interval) != 0) { + lprintf(LOG_ERR, "Given ARP interval '%s' is invalid.", argv[3]); + return (-1); + } + rc = lan_set_arp_interval(intf, chan, interval); + } + else if (strncmp(argv[2], "generate", 8) == 0) { + if (argc < 4) { + lprintf(LOG_NOTICE, "lan set <channel> arp generate <on|off>"); + return (-1); + } + else if (strncmp(argv[3], "on", 2) == 0) + rc = lan_set_arp_generate(intf, chan, 1); + else if (strncmp(argv[3], "off", 3) == 0) + rc = lan_set_arp_generate(intf, chan, 0); + else { + lprintf(LOG_NOTICE, "lan set <channel> arp generate <on|off>"); + return (-1); + } + } + else if (strncmp(argv[2], "respond", 7) == 0) { + if (argc < 4) { + lprintf(LOG_NOTICE, "lan set <channel> arp respond <on|off>"); + return (-1); + } + else if (strncmp(argv[3], "on", 2) == 0) + rc = lan_set_arp_respond(intf, chan, 1); + else if (strncmp(argv[3], "off", 3) == 0) + rc = lan_set_arp_respond(intf, chan, 0); + else { + lprintf(LOG_NOTICE, "lan set <channel> arp respond <on|off>"); + return (-1); + } + } + else { + lprintf(LOG_NOTICE, + "lan set <channel> arp respond <on|off>\n" + "lan set <channel> arp generate <on|off>\n" + "lan set <channel> arp interval <seconds>\n"); + return (-1); + } + } + /* set authentication types */ + else if (strncmp(argv[1], "auth", 4) == 0) { + if (argc < 3) { + lprintf(LOG_NOTICE, + "lan set <channel> auth <level> <type,type,...>\n" + " level = CALLBACK, USER, OPERATOR, ADMIN\n" + " types = NONE, MD2, MD5, PASSWORD, OEM\n" + "example: lan set 7 auth ADMIN PASSWORD,MD5\n"); + return (-1); + } + else if (strncmp(argv[2], "help", 4) == 0) { + lprintf(LOG_NOTICE, + "lan set <channel> auth <level> <type,type,...>\n" + " level = CALLBACK, USER, OPERATOR, ADMIN\n" + " types = NONE, MD2, MD5, PASSWORD, OEM\n" + "example: lan set 7 auth ADMIN PASSWORD,MD5\n"); + return 0; + } else { + rc = ipmi_lan_set_auth(intf, chan, argv[2], argv[3]); + } + } + /* ip address source */ + else if (strncmp(argv[1], "ipsrc", 5) == 0) { + if (argc < 3) { + lprintf(LOG_NOTICE, + "lan set <channel> ipsrc <source>\n" + " none = unspecified\n" + " static = static address (manually configured)\n" + " dhcp = address obtained by BMC running DHCP\n" + " bios = address loaded by BIOS or system software\n"); + return (-1); + } + else if (strncmp(argv[2], "help", 4) == 0) { + lprintf(LOG_NOTICE, + "lan set <channel> ipsrc <source>\n" + " none = unspecified\n" + " static = static address (manually configured)\n" + " dhcp = address obtained by BMC running DHCP\n" + " bios = address loaded by BIOS or system software\n"); + return 0; + } + else if (strncmp(argv[2], "none", 4) == 0) + data[0] = 0; + else if (strncmp(argv[2], "static", 5) == 0) + data[0] = 1; + else if (strncmp(argv[2], "dhcp", 4) == 0) + data[0] = 2; + else if (strncmp(argv[2], "bios", 4) == 0) + data[0] = 3; + else { + lprintf(LOG_NOTICE, + "lan set <channel> ipsrc <source>\n" + " none = unspecified\n" + " static = static address (manually configured)\n" + " dhcp = address obtained by BMC running DHCP\n" + " bios = address loaded by BIOS or system software\n"); + return -1; + } + rc = set_lan_param(intf, chan, IPMI_LANP_IP_ADDR_SRC, data, 1); + } + /* session password + * not strictly a lan setting, but its used for lan connections */ + else if (strncmp(argv[1], "password", 8) == 0) { + rc = ipmi_lan_set_password(intf, 1, (uint8_t *)argv[2]); + } + /* snmp community string */ + else if (strncmp(argv[1], "snmp", 4) == 0) { + if (argc < 3) { + lprintf(LOG_NOTICE, "lan set <channel> snmp <community string>"); + return (-1); + } + else if (strncmp(argv[2], "help", 4) == 0) { + lprintf(LOG_NOTICE, "lan set <channel> snmp <community string>"); + return 0; + } else { + memcpy(data, argv[2], __min(strlen(argv[2]), 18)); + printf("Setting LAN %s to %s\n", + ipmi_lan_params[IPMI_LANP_SNMP_STRING].desc, data); + rc = set_lan_param(intf, chan, IPMI_LANP_SNMP_STRING, data, 18); + } + } + /* ip address */ + else if (strncmp(argv[1], "ipaddr", 6) == 0) { + if(argc != 3) + { + ipmi_lan_set_usage(); + return -1; + } + rc = get_cmdline_ipaddr(argv[2], data); + if (rc == 0) { + printf("Setting LAN %s to %d.%d.%d.%d\n", + ipmi_lan_params[IPMI_LANP_IP_ADDR].desc, + data[0], data[1], data[2], data[3]); + rc = set_lan_param(intf, chan, IPMI_LANP_IP_ADDR, data, 4); + } + } + /* network mask */ + else if (strncmp(argv[1], "netmask", 7) == 0) { + if(argc != 3) + { + ipmi_lan_set_usage(); + return -1; + } + rc = get_cmdline_ipaddr(argv[2], data); + if (rc == 0) { + printf("Setting LAN %s to %d.%d.%d.%d\n", + ipmi_lan_params[IPMI_LANP_SUBNET_MASK].desc, + data[0], data[1], data[2], data[3]); + rc = set_lan_param(intf, chan, IPMI_LANP_SUBNET_MASK, data, 4); + } + } + /* mac address */ + else if (strncmp(argv[1], "macaddr", 7) == 0) { + if(argc != 3) + { + ipmi_lan_set_usage(); + return -1; + } + rc = get_cmdline_macaddr(argv[2], data); + if (rc == 0) { + printf("Setting LAN %s to %02x:%02x:%02x:%02x:%02x:%02x\n", + ipmi_lan_params[IPMI_LANP_MAC_ADDR].desc, + data[0], data[1], data[2], data[3], data[4], data[5]); + rc = set_lan_param(intf, chan, IPMI_LANP_MAC_ADDR, data, 6); + } + } + /* default gateway settings */ + else if (strncmp(argv[1], "defgw", 5) == 0) { + if (argc < 4) { + lprintf(LOG_NOTICE, "LAN set default gateway Commands: ipaddr, macaddr"); + return (-1); + } + else if (strncmp(argv[2], "help", 4) == 0) { + lprintf(LOG_NOTICE, "LAN set default gateway Commands: ipaddr, macaddr"); + return 0; + } + else if ((strncmp(argv[2], "ipaddr", 5) == 0) && + (get_cmdline_ipaddr(argv[3], data) == 0)) { + printf("Setting LAN %s to %d.%d.%d.%d\n", + ipmi_lan_params[IPMI_LANP_DEF_GATEWAY_IP].desc, + data[0], data[1], data[2], data[3]); + rc = set_lan_param(intf, chan, IPMI_LANP_DEF_GATEWAY_IP, data, 4); + } + else if ((strncmp(argv[2], "macaddr", 7) == 0) && + (get_cmdline_macaddr(argv[3], data) == 0)) { + printf("Setting LAN %s to %02x:%02x:%02x:%02x:%02x:%02x\n", + ipmi_lan_params[IPMI_LANP_DEF_GATEWAY_MAC].desc, + data[0], data[1], data[2], data[3], data[4], data[5]); + rc = set_lan_param(intf, chan, IPMI_LANP_DEF_GATEWAY_MAC, data, 6); + } + else { + ipmi_lan_set_usage(); + return -1; + } + } + /* backup gateway settings */ + else if (strncmp(argv[1], "bakgw", 5) == 0) { + if (argc < 4) { + lprintf(LOG_NOTICE, "LAN set backup gateway commands: ipaddr, macaddr"); + return (-1); + } + else if (strncmp(argv[2], "help", 4) == 0) { + lprintf(LOG_NOTICE, "LAN set backup gateway commands: ipaddr, macaddr"); + return 0; + } + else if ((strncmp(argv[2], "ipaddr", 5) == 0) && + (get_cmdline_ipaddr(argv[3], data) == 0)) { + printf("Setting LAN %s to %d.%d.%d.%d\n", + ipmi_lan_params[IPMI_LANP_BAK_GATEWAY_IP].desc, + data[0], data[1], data[2], data[3]); + rc = set_lan_param(intf, chan, IPMI_LANP_BAK_GATEWAY_IP, data, 4); + } + else if ((strncmp(argv[2], "macaddr", 7) == 0) && + (get_cmdline_macaddr(argv[3], data) == 0)) { + printf("Setting LAN %s to %02x:%02x:%02x:%02x:%02x:%02x\n", + ipmi_lan_params[IPMI_LANP_BAK_GATEWAY_MAC].desc, + data[0], data[1], data[2], data[3], data[4], data[5]); + rc = set_lan_param(intf, chan, IPMI_LANP_BAK_GATEWAY_MAC, data, 6); + } + else { + ipmi_lan_set_usage(); + return -1; + } + } + else if (strncasecmp(argv[1], "vlan", 4) == 0) { + if (argc < 4) { + ipmi_lan_set_vlan_usage(); + return (-1); + } + else if (strncmp(argv[2], "help", 4) == 0) { + ipmi_lan_set_vlan_usage(); + return 0; + } + else if (strncasecmp(argv[2], "id", 2) == 0) { + if (strncasecmp(argv[3], "off", 3) == 0) { + ipmi_lan_set_vlan_id(intf, chan, NULL); + } + else { + ipmi_lan_set_vlan_id(intf, chan, argv[3]); + } + } + else if (strncasecmp(argv[2], "priority", 8) == 0) { + ipmi_lan_set_vlan_priority(intf, chan, argv[3]); + } + else { + ipmi_lan_set_vlan_usage(); + return (-1); + } + } + /* set PEF alerting on or off */ + else if (strncasecmp(argv[1], "alert", 5) == 0) { + if (argc < 3) { + lprintf(LOG_NOTICE, "LAN set alert must be 'on' or 'off'"); + return (-1); + } + else if (strncasecmp(argv[2], "on", 2) == 0 || + strncasecmp(argv[2], "enable", 6) == 0) { + printf("Enabling PEF alerts for LAN channel %d\n", chan); + rc = ipmi_set_alert_enable(intf, chan, 1); + } + else if (strncasecmp(argv[2], "off", 3) == 0 || + strncasecmp(argv[2], "disable", 7) == 0) { + printf("Disabling PEF alerts for LAN channel %d\n", chan); + rc = ipmi_set_alert_enable(intf, chan, 0); + } + else { + lprintf(LOG_NOTICE, "LAN set alert must be 'on' or 'off'"); + return 0; + } + } + /* RMCP+ cipher suite privilege levels */ + else if (strncmp(argv[1], "cipher_privs", 12) == 0) + { + if (argc != 3) { + lprintf(LOG_NOTICE, "lan set <channel> cipher_privs XXXXXXXXXXXXXXX"); + lprintf(LOG_NOTICE, " X = Cipher Suite Unused"); + lprintf(LOG_NOTICE, " c = CALLBACK"); + lprintf(LOG_NOTICE, " u = USER"); + lprintf(LOG_NOTICE, " o = OPERATOR"); + lprintf(LOG_NOTICE, " a = ADMIN"); + lprintf(LOG_NOTICE, " O = OEM\n"); + return (-1); + } + else if ((strncmp(argv[2], "help", 4) == 0) || + get_cmdline_cipher_suite_priv_data(argv[2], data)) + { + lprintf(LOG_NOTICE, "lan set <channel> cipher_privs XXXXXXXXXXXXXXX"); + lprintf(LOG_NOTICE, " X = Cipher Suite Unused"); + lprintf(LOG_NOTICE, " c = CALLBACK"); + lprintf(LOG_NOTICE, " u = USER"); + lprintf(LOG_NOTICE, " o = OPERATOR"); + lprintf(LOG_NOTICE, " a = ADMIN"); + lprintf(LOG_NOTICE, " O = OEM\n"); + return 0; + } + else + { + rc = set_lan_param(intf, chan, IPMI_LANP_RMCP_PRIV_LEVELS, data, 9); + } + } + else { + ipmi_lan_set_usage(); + return (-1); + } + + return rc; +} + + +static int +is_alert_destination(struct ipmi_intf * intf, uint8_t channel, uint8_t alert) +{ + struct lan_param * p; + + p = get_lan_param(intf, channel, IPMI_LANP_NUM_DEST); + if (p == NULL) + return 0; + if (p->data == NULL) + return 0; + + if (alert <= (p->data[0] & 0xf)) + return 1; + else + return 0; +} + +static int +ipmi_lan_alert_print(struct ipmi_intf * intf, uint8_t channel, uint8_t alert) +{ +# define PTYPE_LEN 4 +# define PADDR_LEN 13 + struct lan_param *lp_ptr = NULL; + int isack = 0; + uint8_t ptype[PTYPE_LEN]; + uint8_t paddr[PADDR_LEN]; + + lp_ptr = get_lan_param_select(intf, channel, IPMI_LANP_DEST_TYPE, alert); + if (lp_ptr == NULL || lp_ptr->data == NULL + || lp_ptr->data_len < PTYPE_LEN) { + return (-1); + } + memcpy(ptype, lp_ptr->data, PTYPE_LEN); + + lp_ptr = get_lan_param_select(intf, channel, IPMI_LANP_DEST_ADDR, alert); + if (lp_ptr == NULL || lp_ptr->data == NULL + || lp_ptr->data_len < PADDR_LEN) { + return (-1); + } + memcpy(paddr, lp_ptr->data, PADDR_LEN); + + printf("%-24s: %d\n", "Alert Destination", + ptype[0]); + + if (ptype[1] & 0x80) { + isack = 1; + } + printf("%-24s: %s\n", "Alert Acknowledge", + isack ? "Acknowledged" : "Unacknowledged"); + + printf("%-24s: ", "Destination Type"); + switch (ptype[1] & 0x7) { + case 0: + printf("PET Trap\n"); + break; + case 6: + printf("OEM 1\n"); + break; + case 7: + printf("OEM 2\n"); + break; + default: + printf("Unknown\n"); + break; + } + + printf("%-24s: %d\n", + isack ? "Acknowledge Timeout" : "Retry Interval", + ptype[2]); + + printf("%-24s: %d\n", "Number of Retries", + ptype[3] & 0x7); + + if ((paddr[1] & 0xf0) != 0) { + /* unknown address format */ + printf("\n"); + return 0; + } + + printf("%-24s: %s\n", "Alert Gateway", + (paddr[2] & 1) ? "Backup" : "Default"); + + printf("%-24s: %d.%d.%d.%d\n", "Alert IP Address", + paddr[3], paddr[4], paddr[5], paddr[6]); + + printf("%-24s: %02x:%02x:%02x:%02x:%02x:%02x\n", "Alert MAC Address", + paddr[7], paddr[8], paddr[9], + paddr[10], paddr[11], paddr[12]); + + printf("\n"); + return 0; +} + +static int +ipmi_lan_alert_print_all(struct ipmi_intf * intf, uint8_t channel) +{ + int j, ndest; + struct lan_param * p; + + p = get_lan_param(intf, channel, IPMI_LANP_NUM_DEST); + if (p == NULL) + return -1; + if (p->data == NULL) + return -1; + ndest = p->data[0] & 0xf; + + for (j=0; j<=ndest; j++) { + ipmi_lan_alert_print(intf, channel, j); + } + + return 0; +} + +static void +ipmi_lan_alert_print_usage(void) +{ + lprintf(LOG_NOTICE, "\nusage: lan alert print [channel number] [alert destination]\n"); + lprintf(LOG_NOTICE, "Default will print all alerts for the first found LAN channel"); +} + +static void +ipmi_lan_alert_set_usage(void) +{ + lprintf(LOG_NOTICE, "\nusage: lan alert set <channel number> <alert destination> <command> <parameter>\n"); + lprintf(LOG_NOTICE, " Command/parameter options:\n"); + lprintf(LOG_NOTICE, " ipaddr <x.x.x.x> Set alert IP address"); + lprintf(LOG_NOTICE, " macaddr <x:x:x:x:x:x> Set alert MAC address"); + lprintf(LOG_NOTICE, " gateway <default|backup> Set channel gateway to use for alerts"); + lprintf(LOG_NOTICE, " ack <on|off> Set Alert Acknowledge on or off"); + lprintf(LOG_NOTICE, " type <pet|oem1|oem2> Set destination type as PET or OEM"); + lprintf(LOG_NOTICE, " time <seconds> Set ack timeout or unack retry interval"); + lprintf(LOG_NOTICE, " retry <number> Set number of alert retries"); + lprintf(LOG_NOTICE, ""); +} + +static int +ipmi_lan_alert_set(struct ipmi_intf * intf, uint8_t chan, uint8_t alert, + int argc, char ** argv) +{ + struct lan_param * p; + uint8_t data[32], temp[32]; + int rc = 0; + + if (argc < 2) { + ipmi_lan_alert_set_usage(); + return (-1); + } + + if (strncmp(argv[0], "help", 4) == 0 || + strncmp(argv[1], "help", 4) == 0) { + ipmi_lan_alert_set_usage(); + return 0; + } + + memset(data, 0, sizeof(data)); + memset(temp, 0, sizeof(temp)); + + /* alert destination ip address */ + if (strncasecmp(argv[0], "ipaddr", 6) == 0 && + (get_cmdline_ipaddr(argv[1], temp) == 0)) { + /* get current parameter */ + p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_ADDR, alert); + if (p == NULL) { + return (-1); + } + memcpy(data, p->data, p->data_len); + /* set new ipaddr */ + memcpy(data+3, temp, 4); + printf("Setting LAN Alert %d IP Address to %d.%d.%d.%d\n", alert, + data[3], data[4], data[5], data[6]); + rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_ADDR, data, p->data_len); + } + /* alert destination mac address */ + else if (strncasecmp(argv[0], "macaddr", 7) == 0 && + (get_cmdline_macaddr(argv[1], temp) == 0)) { + /* get current parameter */ + p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_ADDR, alert); + if (p == NULL) { + return (-1); + } + memcpy(data, p->data, p->data_len); + /* set new macaddr */ + memcpy(data+7, temp, 6); + printf("Setting LAN Alert %d MAC Address to " + "%02x:%02x:%02x:%02x:%02x:%02x\n", alert, + data[7], data[8], data[9], data[10], data[11], data[12]); + rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_ADDR, data, p->data_len); + } + /* alert destination gateway selector */ + else if (strncasecmp(argv[0], "gateway", 7) == 0) { + /* get current parameter */ + p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_ADDR, alert); + if (p == NULL) { + return (-1); + } + memcpy(data, p->data, p->data_len); + + if (strncasecmp(argv[1], "def", 3) == 0 || + strncasecmp(argv[1], "default", 7) == 0) { + printf("Setting LAN Alert %d to use Default Gateway\n", alert); + data[2] = 0; + } + else if (strncasecmp(argv[1], "bak", 3) == 0 || + strncasecmp(argv[1], "backup", 6) == 0) { + printf("Setting LAN Alert %d to use Backup Gateway\n", alert); + data[2] = 1; + } + else { + ipmi_lan_alert_set_usage(); + return -1; + } + + rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_ADDR, data, p->data_len); + } + /* alert acknowledgement */ + else if (strncasecmp(argv[0], "ack", 3) == 0) { + /* get current parameter */ + p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_TYPE, alert); + if (p == NULL) { + return (-1); + } + memcpy(data, p->data, p->data_len); + + if (strncasecmp(argv[1], "on", 2) == 0 || + strncasecmp(argv[1], "yes", 3) == 0) { + printf("Setting LAN Alert %d to Acknowledged\n", alert); + data[1] |= 0x80; + } + else if (strncasecmp(argv[1], "off", 3) == 0 || + strncasecmp(argv[1], "no", 2) == 0) { + printf("Setting LAN Alert %d to Unacknowledged\n", alert); + data[1] &= ~0x80; + } + else { + ipmi_lan_alert_set_usage(); + return -1; + } + rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_TYPE, data, p->data_len); + } + /* alert destination type */ + else if (strncasecmp(argv[0], "type", 4) == 0) { + /* get current parameter */ + p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_TYPE, alert); + if (p == NULL) { + return (-1); + } + memcpy(data, p->data, p->data_len); + + if (strncasecmp(argv[1], "pet", 3) == 0) { + printf("Setting LAN Alert %d destination to PET Trap\n", alert); + data[1] &= ~0x07; + } + else if (strncasecmp(argv[1], "oem1", 4) == 0) { + printf("Setting LAN Alert %d destination to OEM 1\n", alert); + data[1] &= ~0x07; + data[1] |= 0x06; + } + else if (strncasecmp(argv[1], "oem2", 4) == 0) { + printf("Setting LAN Alert %d destination to OEM 2\n", alert); + data[1] |= 0x07; + } + else { + ipmi_lan_alert_set_usage(); + return -1; + } + rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_TYPE, data, p->data_len); + } + /* alert acknowledge timeout or retry interval */ + else if (strncasecmp(argv[0], "time", 4) == 0) { + /* get current parameter */ + p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_TYPE, alert); + if (p == NULL) { + return (-1); + } + memcpy(data, p->data, p->data_len); + + if (str2uchar(argv[1], &data[2]) != 0) { + lprintf(LOG_ERR, "Invalid time: %s", argv[1]); + return (-1); + } + printf("Setting LAN Alert %d timeout/retry to %d seconds\n", alert, data[2]); + rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_TYPE, data, p->data_len); + } + /* number of retries */ + else if (strncasecmp(argv[0], "retry", 5) == 0) { + /* get current parameter */ + p = get_lan_param_select(intf, chan, IPMI_LANP_DEST_TYPE, alert); + if (p == NULL) { + return (-1); + } + memcpy(data, p->data, p->data_len); + + if (str2uchar(argv[1], &data[3]) != 0) { + lprintf(LOG_ERR, "Invalid retry: %s", argv[1]); + return (-1); + } + data[3] = data[3] & 0x7; + printf("Setting LAN Alert %d number of retries to %d\n", alert, data[3]); + rc = set_lan_param_nowait(intf, chan, IPMI_LANP_DEST_TYPE, data, p->data_len); + } + else { + ipmi_lan_alert_set_usage(); + return -1; + } + + return rc; +} + +static int +ipmi_lan_alert(struct ipmi_intf * intf, int argc, char ** argv) +{ + uint8_t alert; + uint8_t channel = 1; + + if (argc < 1) { + ipmi_lan_alert_print_usage(); + ipmi_lan_alert_set_usage(); + return (-1); + } + else if (strncasecmp(argv[0], "help", 4) == 0) { + ipmi_lan_alert_print_usage(); + ipmi_lan_alert_set_usage(); + return 0; + } + + /* alert print [channel] [alert] */ + if (strncasecmp(argv[0], "print", 5) == 0) { + if (argc < 2) { + channel = find_lan_channel(intf, 1); + if (!is_lan_channel(intf, channel)) { + lprintf(LOG_ERR, "Channel %d is not a LAN channel", channel); + return -1; + } + return ipmi_lan_alert_print_all(intf, channel); + } + + if (strncasecmp(argv[1], "help", 4) == 0) { + ipmi_lan_alert_print_usage(); + return 0; + } + + if (str2uchar(argv[1], &channel) != 0) { + lprintf(LOG_ERR, "Invalid channel: %s", argv[1]); + return (-1); + } + if (!is_lan_channel(intf, channel)) { + lprintf(LOG_ERR, "Channel %d is not a LAN channel", channel); + return -1; + } + + if (argc < 3) + return ipmi_lan_alert_print_all(intf, channel); + + if (str2uchar(argv[2], &alert) != 0) { + lprintf(LOG_ERR, "Invalid alert: %s", argv[2]); + return (-1); + } + if (is_alert_destination(intf, channel, alert) == 0) { + lprintf(LOG_ERR, "Alert %d is not a valid destination", alert); + return -1; + } + return ipmi_lan_alert_print(intf, channel, alert); + } + + /* alert set <channel> <alert> [option] */ + if (strncasecmp(argv[0], "set", 3) == 0) { + if (argc < 5) { + ipmi_lan_alert_set_usage(); + return (-1); + } + else if (strncasecmp(argv[1], "help", 4) == 0) { + ipmi_lan_alert_set_usage(); + return 0; + } + + if (str2uchar(argv[1], &channel) != 0) { + lprintf(LOG_ERR, "Invalid channel: %s", argv[1]); + return (-1); + } + if (!is_lan_channel(intf, channel)) { + lprintf(LOG_ERR, "Channel %d is not a LAN channel", channel); + return -1; + } + + if (str2uchar(argv[2], &alert) != 0) { + lprintf(LOG_ERR, "Invalid alert: %s", argv[2]); + return (-1); + } + if (is_alert_destination(intf, channel, alert) == 0) { + lprintf(LOG_ERR, "Alert %d is not a valid destination", alert); + return -1; + } + + return ipmi_lan_alert_set(intf, channel, alert, argc-3, &(argv[3])); + } + + return 0; +} + + +static int +ipmi_lan_stats_get(struct ipmi_intf * intf, uint8_t chan) +{ + int rc = 0; + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t msg_data[2]; + uint16_t statsTemp; + + if (!is_lan_channel(intf, chan)) { + lprintf(LOG_ERR, "Channel %d is not a LAN channel", chan); + return -1; + } + + /* From here, we are ready to get the stats */ + + msg_data[0] = chan; + msg_data[1] = 0; /* Don't clear */ + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_TRANSPORT; + req.msg.cmd = IPMI_LAN_GET_STAT; + req.msg.data = msg_data; + req.msg.data_len = 2; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Get LAN Stats command failed"); + return (-1); + } + + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Get LAN Stats command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return (-1); + } + + if (verbose > 1) { + uint8_t counter; + printf("--- Rx Stats ---\n"); + for (counter=0; counter<18; counter+=2) { + printf("%02X", *(rsp->data + counter)); + printf(" %02X - ", *(rsp->data + counter+1)); + } + printf("\n"); + } + + statsTemp = ((*(rsp->data + 0)) << 8) | (*(rsp->data + 1)); + printf("IP Rx Packet : %d\n", statsTemp); + + statsTemp = ((*(rsp->data + 2)) << 8) | (*(rsp->data + 3)); + printf("IP Rx Header Errors : %u\n", statsTemp); + + statsTemp = ((*(rsp->data + 4)) << 8) | (*(rsp->data + 5)); + printf("IP Rx Address Errors : %u\n", statsTemp); + + statsTemp = ((*(rsp->data + 6)) << 8) | (*(rsp->data + 7)); + printf("IP Rx Fragmented : %u\n", statsTemp); + + statsTemp = ((*(rsp->data + 8)) << 8) | (*(rsp->data + 9)); + printf("IP Tx Packet : %u\n", statsTemp); + + statsTemp = ((*(rsp->data +10)) << 8) | (*(rsp->data +11)); + printf("UDP Rx Packet : %u\n", statsTemp); + + statsTemp = ((*(rsp->data + 12)) << 8) | (*(rsp->data + 13)); + printf("RMCP Rx Valid : %u\n", statsTemp); + + statsTemp = ((*(rsp->data + 14)) << 8) | (*(rsp->data + 15)); + printf("UDP Proxy Packet Received : %u\n", statsTemp); + + statsTemp = ((*(rsp->data + 16)) << 8) | (*(rsp->data + 17)); + printf("UDP Proxy Packet Dropped : %u\n", statsTemp); + + return rc; +} + + +static int +ipmi_lan_stats_clear(struct ipmi_intf * intf, uint8_t chan) +{ + int rc = 0; + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t msg_data[2]; + + if (!is_lan_channel(intf, chan)) { + lprintf(LOG_ERR, "Channel %d is not a LAN channel", chan); + return -1; + } + + /* From here, we are ready to get the stats */ + msg_data[0] = chan; + msg_data[1] = 1; /* Clear */ + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_TRANSPORT; + req.msg.cmd = IPMI_LAN_GET_STAT; + req.msg.data = msg_data; + req.msg.data_len = 2; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_INFO, "Get LAN Stats command failed"); + return (-1); + } + + if (rsp->ccode > 0) { + lprintf(LOG_INFO, "Get LAN Stats command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return (-1); + } + + return rc; +} + + +/* + * print_lan_usage + */ +static void +print_lan_usage(void) +{ + lprintf(LOG_NOTICE, "LAN Commands:"); + lprintf(LOG_NOTICE, " print [<channel number>]"); + lprintf(LOG_NOTICE, " set <channel number> <command> <parameter>"); + lprintf(LOG_NOTICE, " alert print <channel number> <alert destination>"); + lprintf(LOG_NOTICE, " alert set <channel number> <alert destination> <command> <parameter>"); + lprintf(LOG_NOTICE, " stats get [<channel number>]"); + lprintf(LOG_NOTICE, " stats clear [<channel number>]"); +} + + +int +ipmi_lanp_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + int rc = 0; + uint8_t chan = 0; + + if (argc == 0) { + print_lan_usage(); + return (-1); + } else if (strncmp(argv[0], "help", 4) == 0) { + print_lan_usage(); + return 0; + } + + chan = find_lan_channel(intf, 1); + + if (strncmp(argv[0], "printconf", 9) == 0 || + strncmp(argv[0], "print", 5) == 0) + { + if (argc > 2) { + print_lan_usage(); + return (-1); + } else if (argc == 2) { + if (str2uchar(argv[1], &chan) != 0) { + lprintf(LOG_ERR, "Invalid channel: %s", argv[1]); + return (-1); + } + } + if (!is_lan_channel(intf, chan)) { + lprintf(LOG_ERR, "Invalid channel: %d", chan); + return (-1); + } + rc = ipmi_lan_print(intf, chan); + } else if (strncmp(argv[0], "set", 3) == 0) { + rc = ipmi_lan_set(intf, argc-1, &(argv[1])); + } else if (strncmp(argv[0], "alert", 5) == 0) { + rc = ipmi_lan_alert(intf, argc-1, &(argv[1])); + } else if (strncmp(argv[0], "stats", 5) == 0) { + if (argc < 2) { + print_lan_usage(); + return (-1); + } else if (argc == 3) { + if (str2uchar(argv[2], &chan) != 0) { + lprintf(LOG_ERR, "Invalid channel: %s", argv[2]); + return (-1); + } + } + if (!is_lan_channel(intf, chan)) { + lprintf(LOG_ERR, "Invalid channel: %d", chan); + return (-1); + } + if (strncmp(argv[1], "get", 3) == 0) { + rc = ipmi_lan_stats_get(intf, chan); + } else if (strncmp(argv[1], "clear", 5) == 0) { + rc = ipmi_lan_stats_clear(intf, chan); + } else { + print_lan_usage(); + return (-1); + } + } else { + lprintf(LOG_NOTICE, "Invalid LAN command: %s", argv[0]); + return (-1); + } + return rc; +} |