diff --git a/.ipmitool.metadata b/.ipmitool.metadata new file mode 100644 index 0000000..b930d40 --- /dev/null +++ b/.ipmitool.metadata @@ -0,0 +1 @@ +22254a2b814c8cd323866a4dd835e390521c1dfa SOURCES/ipmitool-1.8.13.tar.bz2 diff --git a/README.md b/README.md deleted file mode 100644 index 0e7897f..0000000 --- a/README.md +++ /dev/null @@ -1,5 +0,0 @@ -The master branch has no content - -Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6 - -If you find this file in a distro specific branch, it means that no content has been checked in yet diff --git a/SOURCES/cxoem-jb-cx6.patch b/SOURCES/cxoem-jb-cx6.patch new file mode 100644 index 0000000..12c6e6b --- /dev/null +++ b/SOURCES/cxoem-jb-cx6.patch @@ -0,0 +1,4759 @@ +commit 194d20c909c93874583db20fbf1e0739a8f8c7e0 +Author: Ales Ledvinka <aledvink@redhat.com> +Date: Thu Jul 25 12:29:08 2013 +0200 + + Jeff's bugzilla cx6 patch + +diff --git a/include/ipmitool/Makefile.am b/include/ipmitool/Makefile.am +index fb6f6bf..83bc76f 100644 +--- a/include/ipmitool/Makefile.am ++++ b/include/ipmitool/Makefile.am +@@ -38,5 +38,5 @@ noinst_HEADERS = log.h bswap.h helper.h ipmi.h ipmi_cc.h ipmi_intf.h \ + ipmi_oem.h ipmi_sdradd.h ipmi_isol.h ipmi_sunoem.h ipmi_picmg.h \ + ipmi_fwum.h ipmi_main.h ipmi_tsol.h ipmi_firewall.h \ + ipmi_kontronoem.h ipmi_ekanalyzer.h ipmi_gendev.h ipmi_ime.h \ +- ipmi_delloem.h ipmi_dcmi.h ++ ipmi_delloem.h ipmi_dcmi.h ipmi_cxoem.h + +diff --git a/include/ipmitool/ipmi.h b/include/ipmitool/ipmi.h +index e74c252..759417c 100644 +--- a/include/ipmitool/ipmi.h ++++ b/include/ipmitool/ipmi.h +@@ -245,6 +245,7 @@ struct ipmi_rs { + #define IPMI_NETFN_OEM 0x2E + #define IPMI_NETFN_ISOL 0x34 + #define IPMI_NETFN_TSOL 0x30 ++#define IPMI_NETFN_CX_OEM 0x3e + + #define IPMI_BMC_SLAVE_ADDR 0x20 + #define IPMI_REMOTE_SWID 0x81 +diff --git a/include/ipmitool/ipmi_constants.h b/include/ipmitool/ipmi_constants.h +index 2aad2cf..d316c61 100644 +--- a/include/ipmitool/ipmi_constants.h ++++ b/include/ipmitool/ipmi_constants.h +@@ -114,6 +114,8 @@ + #define IPMI_CHASSIS_BOOTPARAM_INIT_INFO 6 + #define IPMI_CHASSIS_BOOTPARAM_INIT_MBOX 7 + ++#define IPMI_CHASSIS_BOOTPARAM_OEM_BOOT_POLICY 96 // Calxeda OEM boot param ++ + /* From table 13-17 of the IPMI v2 specification */ + #define IPMI_AUTH_RAKP_NONE 0x00 + #define IPMI_AUTH_RAKP_HMAC_SHA1 0x01 +diff --git a/include/ipmitool/ipmi_cxoem.h b/include/ipmitool/ipmi_cxoem.h +new file mode 100644 +index 0000000..9a01f85 +--- /dev/null ++++ b/include/ipmitool/ipmi_cxoem.h +@@ -0,0 +1,209 @@ ++/* ++ * Copyright (c) 2011 Calxeda, 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 Calxeda, 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. ++ */ ++ ++#ifndef IPMI_CXOEM_H ++#define IPMI_CXOEM_H ++ ++#if HAVE_CONFIG_H ++#include <config.h> ++#endif ++#include <ipmitool/ipmi.h> ++#include <ipmitool/ipmi_sdr.h> ++ ++#define CX_VERSION "-cx6" ++#define IPMI_NETFN_OEM_SS 0x3e ++ ++/* ++ * CX IPMI OEM command ids ++ */ ++#define MSG_ELEMENT_TERMINATOR 0xff ++#define MSG_PARAM_VAL_START_SCALAR 0xf0 ++#define MSG_PARAM_VAL_START_STRING 0xf1 ++#define MSG_PARAM_VAL_START_IPV4_ADDR 0xf2 ++#define MSG_PARAM_VAL_START_MAC_ADDR 0xf3 ++#define MSG_PARAM_VAL_START_BITMAP 0xf4 ++ ++#define IPMI_CMD_OEM_GET_DEVICE_INFO 0x01 ++#define IPMI_CMD_OEM_FEATURES_ENABLE 0xD0 ++#define IPMI_CMD_OEM_FW_DOWNLOAD 0xE0 ++#define IPMI_CMD_OEM_FW_GET_STATUS 0xE1 ++#define IPMI_CMD_OEM_FW_SET_STATUS 0xE2 ++#define IPMI_CMD_OEM_FW_RAW 0xE3 ++#define IPMI_CMD_OEM_FABRIC_GET 0xE4 ++#define IPMI_CMD_OEM_FABRIC_SET 0xE5 ++#define IPMI_CMD_OEM_FABRIC_CONFIG_GET 0xE6 ++#define IPMI_CMD_OEM_FABRIC_CONFIG_SET 0xE7 ++#define IPMI_CMD_OEM_FABRIC_UPDATE_CONFIG 0xE8 ++#define IPMI_CMD_OEM_FW_RESET 0xE9 ++#define IPMI_CMD_OEM_DATA_ACCESS 0xEA ++#define IPMI_CMD_OEM_FABRIC_ADD 0xEB ++#define IPMI_CMD_OEM_FABRIC_RM 0xEC ++#define IPMI_CMD_OEM_TEST 0xED ++#define IPMI_CMD_OEM_FABRIC_INFO 0xEE ++#define IPMI_CMD_OEM_FABRIC_SET_WATCH 0xEF ++#define IPMI_CMD_OEM_FABRIC_CLEAR_WATCH 0xF0 ++#define IPMI_CMD_OEM_FABRIC_FACTORY_DEFAULT 0xF1 ++#define IPMI_CMD_OEM_FABRIC_CREATE 0xF2 ++#define IPMI_CMD_OEM_FABRIC_DELETE 0xF3 ++#define IPMI_CMD_OEM_FABRIC_TRACE 0xF4 ++ ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR 0x01 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_NETMASK 0x02 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_DEFGW 0x03 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_IPSRC 0x04 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_MACADDR 0x05 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_IPINFO 0x06 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_MTU 0x07 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_MODE 0x08 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_MACADDRS 0x09 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_NODEID 0x0A ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED 0x0B ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK 0x0C ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_LINKMAP 0x0D ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_DEPTH_CHART 0x0E ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_ROUTING_TABLE 0x0F ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_STATS 0x10 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_STATS 0x11 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_STATS 0x12 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_CHANNEL_STATS 0x13 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_GLOBAL_WATCH 0x14 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_WATCH 0x15 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_CHANNEL_WATCH 0x16 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_WATCH 0x17 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_WATCH 0x18 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_SERVER 0x19 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_PORT 0x1A ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_RESILIENCE 0x1B ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_NODENUM_OFFSET 0x1C ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED_POLICY 0x1D ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_USERS 0x1E ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_CONFIGURATIONID 0x1F ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITIONID 0x20 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITION_NODES 0x21 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITION_RANGE 0x22 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_PROFILEID 0x23 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR_BASE 0x24 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR_NUM 0x25 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_CUSTOMER_MACADDR 0x26 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_USERS_FACTOR 0x27 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_INFO 0x28 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_START 0x29 ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_STOP 0x2a ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_STATUS 0x2b ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_DUMP 0x2c ++#define IPMI_CMD_OEM_FABRIC_PARAMETER_LACP_STATUS 0x2d ++ ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_NODE 0x40 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_INTERFACE 0x41 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_TFTP 0x42 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_PORT 0x43 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_FILENAME 0x44 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_LINK 0x45 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_OVERRIDE 0x46 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_MAC 0x47 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_HOST 0x48 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_FREQUENCY 0x49 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_ACTUAL 0x50 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_AVERAGING_FREQUENCY 0x51 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_CONFIGURATION 0x52 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_PARTITION 0x53 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_PROFILE 0x54 ++#define IPMI_CMD_OEM_FABRIC_SPECIFIER_SIZE 0x55 ++ ++/* ++ * CX-defined constants ++ */ ++#define CXOEM_FW_DOWNLOAD 1 ++#define CXOEM_FW_STOP 2 ++#define CXOEM_FW_UPLOAD 3 ++#define CXOEM_FW_REGISTER_READ 4 ++#define CXOEM_FW_REGISTER_WRITE 5 ++ ++ ++static const int CXOEM_SUCCESS = 0; ++static const int CXOEM_ERROR = -1; ++ ++ ++/* ++ * OEM FW rq/rs structs ++ */ ++ ++typedef struct img_info_s { ++ unsigned char id; ++ unsigned char type; ++ uint32_t img_addr; ++ uint32_t img_size; ++ uint32_t in_use; ++} __attribute__ ((packed)) img_info_t; ++ ++typedef struct simg_header_s { ++ unsigned char magic[4]; ++ uint16_t hdrfmt; ++ uint16_t priority; ++ uint32_t imgoff; ++ uint32_t imglen; ++ uint32_t daddr; ++ uint32_t flags; ++ uint32_t crc32; ++ unsigned char version[32]; ++} __attribute__ ((packed)) simg_header_t; ++ ++struct cx_fw_info_rs { ++ unsigned char ver; /* param version */ ++ unsigned char count; /* number of bytes */ ++ img_info_t img_info; ++} __attribute__ ((packed)); ++ ++ ++/* ++ * OEM info rs structs ++ */ ++ ++typedef union cx_info_basic_u { ++ /* Revision 1 */ ++ struct { ++ uint32_t iana; ++ uint8_t parameter_revision; ++ uint8_t ecme_major_version; ++ uint8_t ecme_minor_version; ++ uint8_t ecme_revision; ++ uint32_t ecme_build_number; ++ uint32_t ecme_timestamp; ++ char firmware_version[32]; ++ } __attribute__ ((packed)) rev1; ++ ++ /* Revision 2 -- replaced ECME version with a string */ ++ struct { ++ uint32_t iana; ++ uint8_t parameter_revision; ++ char ecme_version[32]; ++ uint32_t ecme_timestamp; ++ char firmware_version[32]; ++ } __attribute__ ((packed)) rev2; ++} cx_info_basic_t; ++ ++ ++/* ++ * Prototypes ++ */ ++int ipmi_cxoem_main(struct ipmi_intf *, int, char **); ++ ++#endif /*IPMI_CXOEM_H */ +diff --git a/include/ipmitool/ipmi_lanp.h b/include/ipmitool/ipmi_lanp.h +index 1aaae5e..0e457f7 100644 +--- a/include/ipmitool/ipmi_lanp.h ++++ b/include/ipmitool/ipmi_lanp.h +@@ -79,10 +79,17 @@ enum { + IPMI_LANP_OEM_ALERT_STRING=96, + IPMI_LANP_ALERT_RETRY=97, + IPMI_LANP_UTC_OFFSET=98, +- IPMI_LANP_DHCP_SERVER_IP=192, +- IPMI_LANP_DHCP_SERVER_MAC=193, +- IPMI_LANP_DHCP_ENABLE=194, +- IPMI_LANP_CHAN_ACCESS_MODE=201, ++ IPMI_LANP_TFTP_SERVER_IP=193, ++ IPMI_LANP_TFTP_UDP_PORT=194, ++ IPMI_LANP_NTP_SERVER_IP=195, ++ IPMI_LANP_NTP_UDP_PORT=196, ++ IPMI_LANP_OEM_OUID=197, ++ IPMI_LANP_OEM_MAC0=198, ++ IPMI_LANP_OEM_MAC1=199, ++ IPMI_LANP_OEM_MAC2=200, ++ IPMI_LANP_SC_OUID=201, ++ IPMI_LANP_SC_MODE=202, ++ IPMI_LANP_SC_FID=203 + }; + + static struct lan_param { +@@ -120,10 +127,17 @@ static struct lan_param { + { IPMI_LANP_OEM_ALERT_STRING, 28, "OEM Alert String" }, /* 25 */ + { IPMI_LANP_ALERT_RETRY, 1, "Alert Retry Algorithm" }, + { IPMI_LANP_UTC_OFFSET, 3, "UTC Offset" }, +- { IPMI_LANP_DHCP_SERVER_IP, 4, "DHCP Server IP" }, +- { IPMI_LANP_DHCP_SERVER_MAC, 6, "DHDP Server MAC" }, +- { IPMI_LANP_DHCP_ENABLE, 1, "DHCP Enable" }, /* 30 */ +- { IPMI_LANP_CHAN_ACCESS_MODE, 2, "Channel Access Mode" }, ++ { IPMI_LANP_TFTP_SERVER_IP, 4, "TFTP Server IP" }, /* 28 */ ++ { IPMI_LANP_TFTP_UDP_PORT, 2, "TFTP UDP port" }, ++ { IPMI_LANP_NTP_SERVER_IP, 4, "NTP Server IP" }, ++ { IPMI_LANP_NTP_UDP_PORT, 2, "NTP UDP port" }, ++ { IPMI_LANP_OEM_OUID, 3, "OEM OUID" }, ++ { IPMI_LANP_OEM_MAC0, 6, "OEM MAC0" }, ++ { IPMI_LANP_OEM_MAC1, 6, "OEM MAC1" }, ++ { IPMI_LANP_OEM_MAC2, 6, "OEM MAC2" }, ++ { IPMI_LANP_SC_OUID, 3, "Supercluster OUID" }, ++ { IPMI_LANP_SC_MODE, 1, "Supercluster mode" }, ++ { IPMI_LANP_SC_FID, 1, "Supercluster FID" }, + { -1 } + }; + +diff --git a/lib/Makefile.am b/lib/Makefile.am +index 3422521..f304502 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -39,7 +39,7 @@ libipmitool_la_SOURCES = helper.c ipmi_sdr.c ipmi_sel.c ipmi_sol.c ipmi_pef.c \ + ipmi_oem.c ipmi_isol.c ipmi_sunoem.c ipmi_fwum.c ipmi_picmg.c \ + ipmi_main.c ipmi_tsol.c ipmi_firewall.c ipmi_kontronoem.c \ + ipmi_hpmfwupg.c ipmi_sdradd.c ipmi_ekanalyzer.c ipmi_gendev.c \ +- ipmi_ime.c ipmi_delloem.c ipmi_dcmi.c \ ++ ipmi_ime.c ipmi_delloem.c ipmi_dcmi.c ipmi_cxoem.c \ + ../src/plugins/lan/md5.c ../src/plugins/lan/md5.h + + libipmitool_la_LDFLAGS = -export-dynamic +diff --git a/lib/ipmi_chassis.c b/lib/ipmi_chassis.c +index 2d47974..445b34d 100644 +--- a/lib/ipmi_chassis.c ++++ b/lib/ipmi_chassis.c +@@ -746,6 +746,12 @@ ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg) + printf(" Block Data : %s\n", buf2str(rsp->data+3, rsp->data_len - 2)); + } + break; ++ case 96: ++ { ++ printf(" Selector : %d\n", rsp->data[1] ); ++ printf(" Boot Policy : %d\n", rsp->data[2] ); ++ } ++ break; + default: + printf(" Undefined byte\n"); + break; +@@ -860,6 +866,86 @@ ipmi_chassis_set_bootdev(struct ipmi_intf * intf, char * arg, uint8_t *iflags) + } + + static int ++ipmi_chassis_set_boot_policy(struct ipmi_intf * intf, char * arg) ++{ ++ uint8_t flags[5]; ++ int rc = 0; ++ int use_progress = 1; ++ ++ if (use_progress) { ++ /* set set-in-progress flag */ ++ memset(flags, 0, 5); ++ flags[0] = 0x01; ++ rc = ipmi_chassis_set_bootparam(intf, ++ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS, flags, 1); ++ if (rc < 0) ++ use_progress = 0; ++ } ++ ++ memset(flags, 0, 5); ++ flags[0] = 0x01; ++ flags[1] = 0x01; ++ rc = ipmi_chassis_set_bootparam(intf, IPMI_CHASSIS_BOOTPARAM_INFO_ACK, ++ flags, 2); ++ ++ if (rc < 0) { ++ if (use_progress) { ++ /* set-in-progress = set-complete */ ++ memset(flags, 0, 5); ++ ipmi_chassis_set_bootparam(intf, ++ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS, ++ flags, 1); ++ } ++ return -1; ++ } ++ ++ memset(flags, 0, 5); ++ ++ if (strncmp(arg, "0", 1) == 0) ++ flags[0] = 0; ++ else if (strncmp(arg, "1", 1) == 0) ++ flags[0] = 1; ++ else if (strncmp(arg, "2", 1) == 0) ++ flags[0] = 2; ++ else { ++ lprintf(LOG_ERR, "Invalid argument: %s", arg); ++ if (use_progress) { ++ /* set-in-progress = set-complete */ ++ memset(flags, 0, 5); ++ ipmi_chassis_set_bootparam(intf, ++ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS, ++ flags, 1); ++ } ++ return -1; ++ } ++ ++ rc = ipmi_chassis_set_bootparam(intf, IPMI_CHASSIS_BOOTPARAM_OEM_BOOT_POLICY, ++ flags, 1); ++ if (rc == 0) { ++ if (use_progress) { ++ /* set-in-progress = commit-write */ ++ memset(flags, 0, 5); ++ flags[0] = 0x02; ++ ipmi_chassis_set_bootparam(intf, ++ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS, ++ flags, 1); ++ } ++ ++ printf("Set Boot Policy to %s\n", arg); ++ } ++ ++ if (use_progress) { ++ /* set-in-progress = set-complete */ ++ memset(flags, 0, 5); ++ ipmi_chassis_set_bootparam(intf, ++ IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS, ++ flags, 1); ++ } ++ ++ return rc; ++} ++ ++static int + ipmi_chassis_power_policy(struct ipmi_intf * intf, uint8_t policy) + { + struct ipmi_rs * rsp; +@@ -1043,6 +1129,10 @@ ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv) + lprintf(LOG_NOTICE, " force_diag : Force boot from Diagnostic Partition"); + lprintf(LOG_NOTICE, " force_cdrom : Force boot from CD/DVD"); + lprintf(LOG_NOTICE, " force_bios : Force boot into BIOS Setup"); ++ lprintf(LOG_NOTICE, "bootparam set policy <value>"); ++ lprintf(LOG_NOTICE, " 0 : Boot ASAP"); ++ lprintf(LOG_NOTICE, " 1 : Boot when Fabric is ready"); ++ lprintf(LOG_NOTICE, " 2 : Boot after a fixed delay"); + } + else { + if (strncmp(argv[1], "get", 3) == 0) { +@@ -1054,6 +1144,8 @@ ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv) + } else { + if (strncmp(argv[2], "bootflag", 8) == 0) + rc = ipmi_chassis_set_bootdev(intf, argv[3], NULL); ++ else if (strncmp(argv[2], "policy", 6) == 0) ++ rc = ipmi_chassis_set_boot_policy(intf, argv[3]); + else + lprintf(LOG_NOTICE, "bootparam set <option> [value ...]"); + } +diff --git a/lib/ipmi_cxoem.c b/lib/ipmi_cxoem.c +new file mode 100644 +index 0000000..fbc008e +--- /dev/null ++++ b/lib/ipmi_cxoem.c +@@ -0,0 +1,3928 @@ ++/* ++ * Copyright (c) 2011 Calxeda, 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 Calxeda, 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. ++ */ ++ ++#include <stdlib.h> ++#include <stdio.h> ++#include <string.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 <ctype.h> ++#include <time.h> ++ ++#include <ipmitool/ipmi.h> ++#include <ipmitool/ipmi_intf.h> ++#include <ipmitool/helper.h> ++#include <ipmitool/log.h> ++#include <ipmitool/ipmi_sel.h> ++#include <ipmitool/ipmi_sdr.h> ++#include <ipmitool/ipmi_strings.h> ++#include <ipmitool/ipmi_channel.h> ++#include <ipmitool/ipmi_cxoem.h> ++#include <ipmitool/ipmi_raw.h> ++ ++/* cxoem data targets -- i.e. the kinds of data we can read and write ++ */ ++#define CX_DATA_TARGET_MEM 1 ++#define CX_DATA_TARGET_CDB 2 ++#define CX_DATA_TARGET_UNKNOWN 0 ++/* Maximum amount of data that can be read from or written to the configuration ++ data base ++*/ ++#define MAX_RETURNABLE_CDB_LEN 64 ++/* Kinds of access to cxoem data supported ++ */ ++#define CX_DATA_ACCESS_READ 1 ++#define CX_DATA_ACCESS_WRITE 2 ++#define CX_DATA_ACCESS_UNKNOWN 0 ++/* Supported cxoem data formatting hints ++ */ ++#define CX_DATA_FMT_DEFAULT 0 ++#define CX_DATA_FMT_INT 1 ++#define CX_DATA_FMT_UINT 2 ++#define CX_DATA_FMT_XINT 3 ++#define CX_DATA_FMT_ASCII 4 ++#define CX_DATA_FMT_XSTR 5 ++#define CX_DATA_INT_TYPE 1 ++#define CX_DATA_BYTE_TYPE 2 ++/* cxoem internal return codes ++ */ ++#define CX_DATA_BAD_VALUE -1 ++#define CX_DATA_BAD_LENGTH -2 ++#define CX_DATA_OK 0 ++ ++const struct valstr cx_ptypes[] = { ++ {0x00, "DEL"}, ++ {0x01, "DEL1"}, ++ {0x02, "S2_ELF"}, ++ {0x03, "SOC_ELF"}, ++ {0x04, "A9_UEFI"}, ++ {0x05, "A9_UBOOT"}, ++ {0x06, "A9_EXEC"}, ++ {0x07, "A9_ELF"}, ++ {0x08, "SOCDATA"}, ++ {0x09, "DTB"}, ++ {0x0a, "CDB"}, ++ {0x0b, "UBOOTENV"}, ++ {0x0c, "SEL"}, ++ {0x0d, "BOOT_LOG"}, ++ {0x0e, "UEFI_ENV"}, ++ {0x0f, "DIAG_ELF"}, ++}; ++ ++const struct valstr cx_tftp_status[] = { ++ {0x00, "Invalid"}, ++ {0x01, "In progress"}, ++ {0x02, "Failed"}, ++ {0x03, "Complete"}, ++ {0x04, "Canceled"}, ++}; ++ ++const char *tps_table[] = { ++ "(Init)", ++ "(Cold)", ++ "(Warm)", ++ "(Hot)", ++ "(Critical)", ++ "(Shutdown)", ++}; ++ ++static void ipmi_cxoem_usage(void) ++{ ++ lprintf(LOG_NOTICE, ++ "Usage: ipmitool cxoem <command> [option...]\n" ++ "\n" ++ "Commands: \n" "\n" " fw fabric mac log data info feature\n"); ++} ++ ++static void cx_fw_usage(void) ++{ ++ lprintf(LOG_NOTICE, ++ "\n" ++ "Usage: ipmitool cxoem fw <command> [option...]\n" ++ "\n" ++ "Firmware Commands: \n" ++ "\n" ++ " download <filename> <partition> <type> tftp <ip[:port]>\n" ++ " upload <partition> <filename> <type> tftp <ip[:port]>\n" ++ " register read <partition> <filename> <type>\n" ++ " register write <partition> <filename> <type>\n" ++ " activate <partition>\n" ++ " invalidate <partition>\n" ++ " makenext <partition>\n" ++ " flags <partition> <flags> \n" ++ " status <job id> - returns status of the transfer by <job id>\n" ++ " check <partition> - force a crc check\n" ++ " cancel <job id>\n" ++ " info\n" ++ " get <filename> <offset> <size> tftp <ip[:port]>\n" ++ " put <filename> <offset> <size> tftp <ip[:port]>\n" ++ " reset Reset to factory default\n" ++ " version <version_str> - set the firmware version\n" ++ "\n"); ++} ++ ++static void cx_fabric_usage(void) ++{ ++ lprintf(LOG_NOTICE, ++ "\n" ++ "Usage: ipmitool cxoem fabric <command> [option...]\n" ++ "\n" ++ "Fabric Commands: \n" ++ "\n" ++ " set|get <parameter> <value> [node <node_id>]\n" ++ " where parameter = node_id, ipaddr, netmask, defgw, ipsrc, macaddr, ntp_server, ntp_port, link_resilience\n" ++ " factory_default node <node_id>\n" ++ " update_config node <node_id>\n" ++ "\n" ++ "Ex: ipmitool cxoem fabric get ipaddr node 1\n" ++ "\n" ++ "\n" ++ "Fabric Config commands affect all nodes in the fabric\n" ++ "Usage: ipmitool cxoem fabric config <command> [option...]\n" ++ "\n" ++ "Fabric Config Commands: \n" ++ "\n" ++ " set|get ipinfo tftp <tftp_server_addr> port <tftp_server_port> file <filename>\n" ++ " set|get ipsrc\n" ++ " set|get ntp_server <ntp_server_ipaddr>\n" ++ " set|get ntp_port <ntp_port>\n" ++ " set|get nodenum_offset <offset>\n" ++ " set|get macaddrs tftp <tftp_server_addr> port <tftp_server_port> file <filename>\n" ++ " set|get mtu <standard|jumbo>\n" ++ " set|get uplink <uplink_id> node <node_id> interface <interface_id>\n" ++ " where mode is:\n" ++ " 0 - all interfaces go to Uplink0\n" ++ " 1 - managment interfaces go to Uplink0, server interfaces go to Uplink1\n" ++ " 2 - managment and eth0 interfaces go to Uplink0, eth1 interfaces go to Uplink1\n" ++ " set|get link_resilience <setting>\n" ++ " where setting is:\n" ++ " 0 - Resilient: All redundant links are left enabled\n" ++ " 1 - Link Minimal: All redundant links are disabled\n" ++ " factory_default\n" ++ " update_config\n" ++ "\n" ++ "Ex: ipmitool cxoem fabric config get ipinfo tftp 10.1.1.1 port 69 file ipinfo.out\n" ++ "\n"); ++} ++ ++static void cx_feature_usage(void) ++{ ++ lprintf(LOG_NOTICE, ++ "\n" ++ "Usage: ipmitool cxoem feature <status|enable|disable> <feature> \n" ++ "\n" ++ "Feature to Enable/Disable/Query are:\n" ++ " selaging : SEL Aging or Circular SEL buffer\n" ++ " hwwd : Hardware Watchdog\n" ++ " tps : Thermal Protection System (Status Only)\n" ++ " mansen : Override for manual sensors monitoring\n" ++ "\n" ++ "Ex: ipmitool cxoem feature status selaging\n" ++ "Ex: ipmitool cxoem feature enable hwwd\n" "\n"); ++} ++ ++int cx_fw_download(struct ipmi_intf *intf, char *filename, int partition, ++ int type, int ip1, int ip2, int ip3, int ip4, int port) ++{ ++ int rc = CXOEM_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[64]; ++ ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, 64); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_FW_DOWNLOAD; ++ msg_data[0] = type; ++ msg_data[1] = partition; ++ msg_data[2] = CXOEM_FW_DOWNLOAD; ++ msg_data[3] = 0; ++ msg_data[4] = 0; ++ msg_data[5] = 6; // ipv4 addresses by default (for now) ++ msg_data[6] = ip1; ++ msg_data[7] = ip2; ++ msg_data[8] = ip3; ++ msg_data[9] = ip4; ++ msg_data[10] = (port & 0xff); ++ msg_data[11] = (port >> 8) & 0xff; ++ msg_data[12] = strlen(filename) + 1; ++ memcpy(&msg_data[13], filename, msg_data[12]); ++ req.msg.data = msg_data; ++ req.msg.data_len = msg_data[12] + 13; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error starting fw download"); ++ return -1; ++ } ++ ++ if (rsp->ccode == 0) { ++ uint16_t handle; ++ handle = (unsigned int)rsp->data[0]; ++ handle |= (unsigned int)(rsp->data[1] << 8); ++ printf("TFTP Handle ID: %d\n", handle); ++ } else if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "Start FW download failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ return rc; ++} ++ ++int cx_fw_upload(struct ipmi_intf *intf, char *filename, int partition, ++ int type, int ip1, int ip2, int ip3, int ip4, int port) ++{ ++ int rc = CXOEM_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[64]; ++ ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, 64); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_FW_DOWNLOAD; ++ msg_data[0] = type; ++ msg_data[1] = partition; ++ msg_data[2] = CXOEM_FW_UPLOAD; ++ msg_data[3] = 0; ++ msg_data[4] = 0; ++ msg_data[5] = 6; // ipv4 addresses by default (for now) ++ msg_data[6] = ip1; ++ msg_data[7] = ip2; ++ msg_data[8] = ip3; ++ msg_data[9] = ip4; ++ msg_data[10] = (port & 0xff); ++ msg_data[11] = (port >> 8) & 0xff; ++ msg_data[12] = fmin(strlen(filename) + 1, 51); ++ memcpy(&msg_data[13], filename, msg_data[12] - 1); ++ req.msg.data = msg_data; ++ req.msg.data_len = msg_data[12] + 13; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error starting fw upload"); ++ return -1; ++ } ++ if (rsp->ccode == 0) { ++ uint16_t handle; ++ handle = (unsigned int)rsp->data[0]; ++ handle |= (unsigned int)(rsp->data[1] << 8); ++ printf("TFTP Handle ID: %d\n", handle); ++ } else if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "Start FW upload failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ return rc; ++} ++ ++int cx_fw_register_read(struct ipmi_intf *intf, char *filename, int partition, ++ int type) ++{ ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[64]; ++ ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, 64); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_FW_DOWNLOAD; ++ msg_data[0] = type; ++ msg_data[1] = partition; ++ msg_data[2] = CXOEM_FW_REGISTER_READ; ++ msg_data[12] = fmin(strlen(filename) + 1, 51); ++ memcpy(&msg_data[13], filename, msg_data[12] - 1); ++ req.msg.data = msg_data; ++ req.msg.data_len = msg_data[12] + 13; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error : No response"); ++ return -1; ++ } ++ if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "Error : %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ if (rsp->data_len != 0) { ++ lprintf(LOG_ERR, "Error : Invalid response size"); ++ return -1; ++ } ++ ++ return CXOEM_SUCCESS; ++} ++ ++int cx_fw_register_write(struct ipmi_intf *intf, char *filename, int partition, ++ int type) ++{ ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[64]; ++ ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, 64); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_FW_DOWNLOAD; ++ msg_data[0] = type; ++ msg_data[1] = partition; ++ msg_data[2] = CXOEM_FW_REGISTER_WRITE; ++ msg_data[12] = fmin(strlen(filename) + 1, 51); ++ memcpy(&msg_data[13], filename, msg_data[12] - 1); ++ req.msg.data = msg_data; ++ req.msg.data_len = msg_data[12] + 13; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error : No response"); ++ return -1; ++ } ++ if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "Error : %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ if (rsp->data_len != 0) { ++ lprintf(LOG_ERR, "Error : Invalid response size"); ++ return -1; ++ } ++ ++ return CXOEM_SUCCESS; ++} ++ ++int cx_fw_raw(struct ipmi_intf *intf, char *filename, unsigned int address, ++ unsigned int size, int dir, ++ int ip1, int ip2, int ip3, int ip4, int port) ++{ ++ int rc = CXOEM_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[64]; ++ ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, 64); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_FW_RAW; ++ msg_data[0] = dir; ++ msg_data[1] = address & 0xff; ++ msg_data[2] = (address >> 8) & 0xff; ++ msg_data[3] = (address >> 16) & 0xff; ++ msg_data[4] = (address >> 24) & 0xff; ++ msg_data[5] = size & 0xff; ++ msg_data[6] = (size >> 8) & 0xff; ++ msg_data[7] = (size >> 16) & 0xff; ++ msg_data[8] = (size >> 24) & 0xff; ++ msg_data[9] = ip1; ++ msg_data[10] = ip2; ++ msg_data[11] = ip3; ++ msg_data[12] = ip4; ++ msg_data[13] = (port & 0xff); ++ msg_data[14] = (port >> 8) & 0xff; ++ msg_data[15] = strlen(filename) + 1; ++ memcpy(&msg_data[16], filename, msg_data[15]); ++ req.msg.data = msg_data; ++ req.msg.data_len = msg_data[15] + 16; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error starting raw transfer"); ++ return -1; ++ } ++ ++ if (rsp->ccode == 0) { ++ uint16_t handle; ++ handle = (unsigned int)rsp->data[0]; ++ handle |= (unsigned int)(rsp->data[1] << 8); ++ ++ printf("TFTP Handle ID: %d\n", handle); ++ } else if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "Start raw transfer failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ return rc; ++} ++ ++int cx_fw_status(struct ipmi_intf *intf, uint16_t handle) ++{ ++ int rc = CXOEM_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[16]; ++ int status = -1; ++ ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_FW_GET_STATUS; ++ msg_data[0] = 0; ++ msg_data[1] = 1; // param 1 = download status ++ ++ msg_data[2] = handle & 0x00ff; ++ msg_data[3] = (handle >> 8) & 0x00ff; ++ req.msg.data = msg_data; ++ req.msg.data_len = 4; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error checking fw status"); ++ return -1; ++ } ++ if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "Check FW status failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ status = rsp->data[1]; ++ ++ printf("Status : %s\n", val2str(status, cx_tftp_status)); ++ ++ return rc; ++} ++ ++int cx_fw_check(struct ipmi_intf *intf, int partition) ++{ ++ int rc = CXOEM_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[64]; ++ ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, 64); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_FW_GET_STATUS; ++ msg_data[0] = 0; ++ msg_data[1] = 4; // param 4 = check image ++ msg_data[2] = partition; ++ req.msg.data = msg_data; ++ req.msg.data_len = 3; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error during firmware check\n"); ++ return -1; ++ } ++ ++ if (rsp->ccode == 0) { ++ unsigned int crc32; ++ crc32 = (unsigned int)rsp->data[5]; ++ crc32 |= (unsigned int)(rsp->data[4] << 8); ++ crc32 |= (unsigned int)(rsp->data[3] << 16); ++ crc32 |= (unsigned int)(rsp->data[2] << 24); ++ if (rsp->data[1] == 0) { ++ printf("CRC32 : %08x\n", crc32); ++ } else { ++ printf("Error : %02x\n", rsp->data[0]); ++ return -1; ++ } ++ } else if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "Firmware check failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ return rc; ++} ++ ++int cx_fw_info(struct ipmi_intf *intf, int partition) ++{ ++ int rc = CXOEM_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[64]; ++ int i; ++ struct cx_fw_info_rs *s; ++ int count; ++ img_info_t ii[20]; ++ simg_header_t header; ++ ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, 64); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_FW_GET_STATUS; ++ msg_data[0] = 0; ++ msg_data[1] = 2; // param 2 = info ++ msg_data[2] = partition; ++ req.msg.data = msg_data; ++ req.msg.data_len = 2; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error starting fw download"); ++ return -1; ++ } ++ if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "Start FW download failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ if (rsp->data_len < sizeof(struct cx_fw_info_rs)) ++ return -1; ++ ++ s = (struct cx_fw_info_rs *)&rsp->data[0]; ++ count = s->count / sizeof(img_info_t); ++ memcpy(ii, &s->img_info, count * sizeof(img_info_t)); ++ ++ printf("\n"); ++ for (i = 0; i < count; i++) { ++ if (cx_fw_get_simg_header(intf, i, &header)) { ++ return -1; ++ } ++ ++ printf("%-18s : %02d\n", "Partition", ii[i].id); ++ printf("%-18s : %02x (%s)\n", "Type", ii[i].type, ++ val2str(ii[i].type, cx_ptypes)); ++ printf("%-18s : %08x\n", "Offset", ii[i].img_addr); ++ printf("%-18s : %08x\n", "Size", ii[i].img_size); ++ printf("%-18s : %08x\n", "Priority", header.priority); ++ printf("%-18s : %08x\n", "Daddr", header.daddr); ++ printf("%-18s : %08x\n", "Flags", header.flags); ++ if (header.hdrfmt >= 2) ++ printf("%-18s : %s\n", "Version", header.version); ++ else ++ printf("%-18s : Unknown\n", "Version"); ++ if (ii[i].in_use <= 1) ++ printf("%-18s : %u\n\n", "In Use", ii[i].in_use); ++ else ++ printf("%-18s : Unknown\n\n", "In Use"); ++ } ++ ++ return rc; ++} ++ ++ ++int ++cx_fw_get_simg_header(struct ipmi_intf *intf, int partition, ++ simg_header_t * header) ++{ ++ int rc = CXOEM_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[64]; ++ ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, 64); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_FW_GET_STATUS; ++ msg_data[0] = 0; ++ msg_data[1] = 3; // param 3 = get SIMG header ++ msg_data[2] = partition; ++ req.msg.data = msg_data; ++ req.msg.data_len = 3; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error reading SIMG info\n"); ++ return -1; ++ } ++ ++ if (rsp->ccode == 0) { ++ memcpy(header, &rsp->data[1], sizeof(*header)); ++ } else if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "SIMG read failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ return rc; ++} ++ ++ ++int cx_fw_flags(struct ipmi_intf *intf, int partition, uint32_t flags) ++{ ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[16]; ++ int i; ++ ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, sizeof(msg_data)); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_FW_SET_STATUS; ++ msg_data[0] = 0; // resvd ++ msg_data[1] = 1; // param = 1 = "set flags" ++ msg_data[2] = partition; ++ msg_data[3] = (uint8_t) ((flags >> 24) & 0xff); ++ msg_data[4] = (uint8_t) ((flags >> 16) & 0xff); ++ msg_data[5] = (uint8_t) ((flags >> 8) & 0xff); ++ msg_data[6] = (uint8_t) (flags & 0xff); ++ req.msg.data = msg_data; ++ req.msg.data_len = 7; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error starting fw download"); ++ return -1; ++ } ++ if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "FW set flags failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++int cx_fw_get_flags(struct ipmi_intf *intf, int partition, unsigned int *flags) ++{ ++ int rc = CXOEM_SUCCESS; ++ simg_header_t header; ++ ++ if (cx_fw_get_simg_header(intf, partition, &header)) { ++ return -1; ++ } ++ ++ *flags = header.flags; ++ ++ return rc; ++} ++ ++ ++int cx_fw_makenext(struct ipmi_intf *intf, int partition) ++{ ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[4]; ++ int i; ++ ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, sizeof(msg_data)); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_FW_SET_STATUS; ++ msg_data[0] = 0; // resvd ++ msg_data[1] = 3; // param = 3 = "make next" ++ msg_data[2] = partition; ++ req.msg.data = msg_data; ++ req.msg.data_len = 3; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error setting firmware image to 'next'"); ++ return -1; ++ } ++ if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "FW set next failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int cx_fw_activate(struct ipmi_intf *intf, int partition) ++{ ++ unsigned int flags; ++ ++ if (cx_fw_get_flags(intf, partition, &flags)) { ++ return -1; ++ } ++ //printf("activate: read flags <%08x>\n", flags); ++ flags &= (~0x02); // bit 1 = SIMG_FLAG_ACTIVE ++ printf("activate: write flags <%08x>\n", flags); ++ ++ cx_fw_flags(intf, partition, flags); ++ ++ return 0; ++} ++ ++ ++int cx_fw_invalidate(struct ipmi_intf *intf, int partition) ++{ ++ unsigned int flags; ++ ++ if (cx_fw_get_flags(intf, partition, &flags)) { ++ return -1; ++ } ++ //printf("invalidate: read flags <%08x>\n", flags); ++ flags &= (~0x04); // bit 2 = SIMG_FLAG_INVALID ++ printf("invalidate: write flags <%08x>\n", flags); ++ ++ cx_fw_flags(intf, partition, flags); ++ ++ return 0; ++} ++ ++ ++int cx_fw_reset(struct ipmi_intf *intf) ++{ ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ ++ memset(&req, 0, sizeof(req)); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_FW_RESET; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, ++ "Error resetting firmware to factory default\n"); ++ return -1; ++ } ++ ++ if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "Firmware reset failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++int cx_fw_version(struct ipmi_intf *intf, char *version) ++{ ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[64]; ++ int i; ++ ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, sizeof(msg_data)); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_FW_SET_STATUS; ++ msg_data[0] = 0; // resvd ++ msg_data[1] = 4; // param = 4 = "set version" ++ strncpy(&msg_data[2], version, 32); ++ req.msg.data = msg_data; ++ req.msg.data_len = 34; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error starting fw download"); ++ return -1; ++ } ++ if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "FW set version failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++int cx_fw_main(struct ipmi_intf *intf, int argc, char **argv) ++{ ++ char filename[65]; ++ int rv = 0; ++ int partition, type; ++ int ip1 = 0, ip2 = 0, ip3 = 0, ip4 = 0; ++ int port = 0; ++ ++ errno = 0; ++ ++ if (argc < 1 || strncmp(argv[0], "help", 4) == 0) { ++ cx_fw_usage(); ++ return 0; ++ } ++ ++ if (strncmp(argv[0], "download", 8) == 0) { ++ if ((argc > 3) && (argc < 7) && (strlen(argv[1]) > 0)) { ++ /* There is a file name in the parameters */ ++ if (strlen(argv[1]) < 32) { ++ strcpy((char *)filename, argv[1]); ++ printf("File Name : %s\n", filename); ++ } else { ++ lprintf(LOG_ERR, ++ "File name must be smaller than 32 bytes\n"); ++ } ++ ++ partition = strtol(argv[2], (char **)NULL, 10); ++ if (!errno) { ++ printf("Partition : %d\n", partition); ++ } else { ++ lprintf(LOG_ERR, ++ "<partition> doesn't look like a valid value\n"); ++ return -1; ++ } ++ ++ if (isdigit(argv[3][0])) { ++ type = strtol(argv[3], (char **)NULL, 10); ++ } else { ++ type = str2val(argv[3], cx_ptypes); ++ if (type < 1 || type > 14) ++ errno = -1; ++ } ++ if (!errno) { ++ printf("Type : %d\n", type); ++ } else { ++ lprintf(LOG_ERR, ++ "<type> doesn't look like a valid value\n"); ++ return -1; ++ } ++ ++ if (argc > 5 && strncmp(argv[4], "tftp", 4) == 0) { ++ if (strchr(argv[5], ':')) { ++ if (sscanf(argv[5], "%d.%d.%d.%d:%d", ++ &ip1, &ip2, &ip3, &ip4, ++ &port) != 5) { ++ lprintf(LOG_ERR, ++ "Invalid IP address: %s", ++ argv[5]); ++ return -1; ++ } ++ printf("IP = %d.%d.%d.%d:%d\n", ip1, ++ ip2, ip3, ip4, port); ++ } else { ++ if (sscanf(argv[5], "%d.%d.%d.%d", ++ &ip1, &ip2, &ip3, ++ &ip4) != 4) { ++ lprintf(LOG_ERR, ++ "Invalid IP address: %s", ++ argv[5]); ++ return -1; ++ } ++ printf("IP = %d.%d.%d.%d\n", ip1, ip2, ++ ip3, ip4); ++ } ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ cx_fw_download(intf, filename, partition, type, ++ ip1, ip2, ip3, ip4, port); ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ } else if (strncmp(argv[0], "upload", 8) == 0) { ++ if ((argc > 3) && (argc < 7) && (strlen(argv[1]) > 0)) { ++ /* There is a file name in the parameters */ ++ if (strlen(argv[2]) < 32) { ++ strcpy((char *)filename, argv[2]); ++ printf("File Name : %s\n", filename); ++ } else { ++ lprintf(LOG_ERR, ++ "File name must be smaller than 32 bytes\n"); ++ } ++ ++ partition = strtol(argv[1], (char **)NULL, 10); ++ if (!errno) { ++ printf("Partition : %d\n", partition); ++ } else { ++ lprintf(LOG_ERR, ++ "<partition> doesn't look like a valid value\n"); ++ return -1; ++ } ++ ++ if (isdigit(argv[3][0])) { ++ type = strtol(argv[3], (char **)NULL, 10); ++ } else { ++ type = str2val(argv[3], cx_ptypes); ++ if (type < 1 || type > 14) ++ errno = -1; ++ } ++ if (!errno) { ++ printf("Type : %d\n", type); ++ } else { ++ lprintf(LOG_ERR, ++ "<type> doesn't look like a valid value\n"); ++ return -1; ++ } ++ ++ if (argc > 5 && strncmp(argv[4], "tftp", 4) == 0) { ++ if (strchr(argv[5], ':')) { ++ if (sscanf(argv[5], "%d.%d.%d.%d:%d", ++ &ip1, &ip2, &ip3, &ip4, ++ &port) != 5) { ++ lprintf(LOG_ERR, ++ "Invalid IP address: %s", ++ argv[5]); ++ return -1; ++ } ++ printf("IP = %d.%d.%d.%d:%d\n", ip1, ++ ip2, ip3, ip4, port); ++ } else { ++ if (sscanf(argv[5], "%d.%d.%d.%d", ++ &ip1, &ip2, &ip3, ++ &ip4) != 4) { ++ lprintf(LOG_ERR, ++ "Invalid IP address: %s", ++ argv[5]); ++ return -1; ++ } ++ printf("IP = %d.%d.%d.%d\n", ip1, ip2, ++ ip3, ip4); ++ } ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ cx_fw_upload(intf, filename, partition, type, ++ ip1, ip2, ip3, ip4, port); ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ } else if (strncmp(argv[0], "register", 8) == 0) { ++ if (argc == 5) { ++ partition = strtol(argv[2], (char **)NULL, 10); ++ if (!errno) { ++ printf("Partition : %d\n", partition); ++ } else { ++ lprintf(LOG_ERR, ++ "<partition> doesn't look like a valid value\n"); ++ return -1; ++ } ++ ++ if (strlen(argv[3]) < 32) { ++ strcpy((char *)filename, argv[3]); ++ printf("File Name : %s\n", filename); ++ } else { ++ lprintf(LOG_ERR, ++ "File name must be smaller than 32 bytes\n"); ++ } ++ ++ if (isdigit(argv[4][0])) { ++ type = strtol(argv[4], (char **)NULL, 10); ++ } else { ++ type = str2val(argv[4], cx_ptypes); ++ if (type < 1 || type > 14) ++ errno = -1; ++ } ++ if (!errno) { ++ printf("Type : %d\n", type); ++ } else { ++ lprintf(LOG_ERR, ++ "<type> doesn't look like a valid value\n"); ++ return -1; ++ } ++ ++ if (strncmp(argv[1], "read", 4) == 0) { ++ cx_fw_register_read(intf, filename, partition, ++ type); ++ } else if(strncmp(argv[1], "write", 5) == 0) { ++ cx_fw_register_write(intf, filename, partition, ++ type); ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ } else if (strncmp(argv[0], "put", 3) == 0) { ++ unsigned int addr = 0; ++ unsigned int size = 0; ++ int dir = 0; // 0 = download, 1 = upload ++ if ((argc > 3) && (argc < 7) && (strlen(argv[1]) > 0)) { ++ /* There is a file name in the parameters */ ++ if (strlen(argv[1]) < 32) { ++ strcpy((char *)filename, argv[1]); ++ printf("File Name : %s\n", filename); ++ } else { ++ lprintf(LOG_ERR, ++ "File name must be smaller than 32 bytes\n"); ++ } ++ ++ addr = strtoul(argv[2], (char **)NULL, 0); ++ if (!errno) { ++ printf("Address : %08x\n", addr); ++ } else { ++ lprintf(LOG_ERR, ++ "<address> doesn't look like a valid value\n"); ++ return -1; ++ } ++ ++ size = strtoul(argv[3], (char **)NULL, 0); ++ if (!errno) { ++ printf("Size : %08x\n", size); ++ } else { ++ lprintf(LOG_ERR, ++ "<size> doesn't look like a valid value\n"); ++ return -1; ++ } ++ ++ if (argc > 5 && strncmp(argv[4], "tftp", 4) == 0) { ++ if (strchr(argv[5], ':')) { ++ if (sscanf(argv[5], "%d.%d.%d.%d:%d", ++ &ip1, &ip2, &ip3, &ip4, ++ &port) != 5) { ++ lprintf(LOG_ERR, ++ "Invalid IP address: %s", ++ argv[5]); ++ return -1; ++ } ++ printf("IP = %d.%d.%d.%d:%d\n", ip1, ++ ip2, ip3, ip4, port); ++ } else { ++ if (sscanf(argv[5], "%d.%d.%d.%d", ++ &ip1, &ip2, &ip3, ++ &ip4) != 4) { ++ lprintf(LOG_ERR, ++ "Invalid IP address: %s", ++ argv[5]); ++ return -1; ++ } ++ printf("IP = %d.%d.%d.%d\n", ip1, ip2, ++ ip3, ip4); ++ } ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ cx_fw_raw(intf, filename, addr, size, dir, ++ ip1, ip2, ip3, ip4, port); ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ } else if (strncmp(argv[0], "get", 3) == 0) { ++ unsigned int addr = 0; ++ unsigned int size = 0; ++ int dir = 1; // 0 = download, 1 = upload ++ if ((argc > 3) && (argc < 7) && (strlen(argv[1]) > 0)) { ++ /* There is a file name in the parameters */ ++ if (strlen(argv[1]) < 32) { ++ strcpy((char *)filename, argv[1]); ++ printf("File Name : %s\n", filename); ++ } else { ++ lprintf(LOG_ERR, ++ "File name must be smaller than 32 bytes\n"); ++ } ++ ++ addr = strtoul(argv[2], (char **)NULL, 0); ++ if (!errno) { ++ printf("Address : %08x\n", addr); ++ } else { ++ lprintf(LOG_ERR, ++ "<address> doesn't look like a valid value\n"); ++ return -1; ++ } ++ ++ size = strtoul(argv[3], (char **)NULL, 0); ++ if (!errno) { ++ printf("Size : %08x\n", size); ++ } else { ++ lprintf(LOG_ERR, ++ "<size> doesn't look like a valid value\n"); ++ return -1; ++ } ++ ++ if (argc > 5 && strncmp(argv[4], "tftp", 4) == 0) { ++ if (strchr(argv[5], ':')) { ++ if (sscanf(argv[5], "%d.%d.%d.%d:%d", ++ &ip1, &ip2, &ip3, &ip4, ++ &port) != 5) { ++ lprintf(LOG_ERR, ++ "Invalid IP address: %s", ++ argv[5]); ++ return -1; ++ } ++ printf("IP = %d.%d.%d.%d:%d\n", ip1, ++ ip2, ip3, ip4, port); ++ } else { ++ if (sscanf(argv[5], "%d.%d.%d.%d", ++ &ip1, &ip2, &ip3, ++ &ip4) != 4) { ++ lprintf(LOG_ERR, ++ "Invalid IP address: %s", ++ argv[5]); ++ return -1; ++ } ++ printf("IP = %d.%d.%d.%d\n", ip1, ip2, ++ ip3, ip4); ++ } ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ cx_fw_raw(intf, filename, addr, size, dir, ++ ip1, ip2, ip3, ip4, port); ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ } else if (strncmp(argv[0], "status", 6) == 0) { ++ uint16_t handle = 0; ++ ++ if (argc == 2) { ++ handle = strtol(argv[1], (char **)NULL, 10); ++ if (!errno) { ++ printf("Handle : %d\n", handle); ++ } else { ++ lprintf(LOG_ERR, ++ "<handle> doesn't look like a valid value\n"); ++ return -1; ++ } ++ } ++ cx_fw_status(intf, handle); ++ rv = 0; ++ } else if (strncmp(argv[0], "info", 4) == 0) { ++ int partition = -1; ++ ++ if (argc > 3) { ++ partition = strtol(argv[1], (char **)NULL, 10); ++ if (!errno) { ++ printf("Partition : %d\n", partition); ++ } else { ++ lprintf(LOG_ERR, ++ "<partition> doesn't look like a valid value\n"); ++ return -1; ++ } ++ } ++ cx_fw_info(intf, partition); ++ } else if (strncmp(argv[0], "makenext", 8) == 0) { ++ if (argc == 2) { ++ partition = strtol(argv[1], (char **)NULL, 10); ++ if (!errno) { ++ printf("Partition : %d\n", partition); ++ } else { ++ fprintf(stderr, ++ "<partition> doesn't look like a valid value\n"); ++ return -1; ++ } ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ cx_fw_makenext(intf, partition); ++ } else if (strncmp(argv[0], "activate", 8) == 0) { ++ int partition = -1; ++ ++ if (argc == 2) { ++ partition = strtol(argv[1], (char **)NULL, 10); ++ if (!errno) { ++ printf("Partition : %d\n", partition); ++ } else { ++ lprintf(LOG_ERR, ++ "<partition> doesn't look like a valid value\n"); ++ return -1; ++ } ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ cx_fw_activate(intf, partition); ++ } else if (strncmp(argv[0], "invalidate", 10) == 0) { ++ int partition = -1; ++ ++ if (argc == 2) { ++ partition = strtol(argv[1], (char **)NULL, 10); ++ if (!errno) { ++ printf("Partition : %d\n", partition); ++ } else { ++ lprintf(LOG_ERR, ++ "<partition> doesn't look like a valid value\n"); ++ return -1; ++ } ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ cx_fw_invalidate(intf, partition); ++ } else if (strncmp(argv[0], "flags", 5) == 0) { ++ int partition = -1; ++ uint32_t flags = 0xffffffff; ++ ++ if (argc == 3) { ++ partition = strtol(argv[1], (char **)NULL, 10); ++ if (!errno) { ++ printf("Partition : %d\n", partition); ++ } else { ++ lprintf(LOG_ERR, ++ "<partition> doesn't look like a valid value\n"); ++ return -1; ++ } ++ flags = strtoul(argv[2], (char **)NULL, 16); ++ if (!errno) { ++ printf("Flags : %08x\n", flags); ++ } else { ++ lprintf(LOG_ERR, ++ "<flags> doesn't look like a valid value\n"); ++ return -1; ++ } ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ cx_fw_flags(intf, partition, flags); ++ } else if (strncmp(argv[0], "check", 5) == 0) { ++ int partition = -1; ++ ++ if (argc == 2) { ++ partition = strtol(argv[1], (char **)NULL, 10); ++ if (!errno) { ++ printf("Partition : %d\n", partition); ++ } else { ++ lprintf(LOG_ERR, ++ "<partition> doesn't look like a valid value\n"); ++ return -1; ++ } ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ cx_fw_check(intf, partition); ++ rv = 0; ++ } else if (strncmp(argv[0], "reset", 5) == 0) { ++ cx_fw_reset(intf); ++ rv = 0; ++ } else if (strncmp(argv[0], "version", 7) == 0) { ++ cx_fw_version(intf, argv[1]); ++ rv = 0; ++ } else { ++ cx_fw_usage(); ++ return -1; ++ } ++ ++ ++ return rv; ++} ++ ++typedef enum { ++ Cx_Fabric_Arg_Invalid, ++ Cx_Fabric_Arg_Command, ++ Cx_Fabric_Arg_Parameter, ++ Cx_Fabric_Arg_Specifier, ++ Cx_Fabric_Arg_Value_Scalar, ++ Cx_Fabric_Arg_Value_String, ++ Cx_Fabric_Arg_Value_IPV4_Address, ++ Cx_Fabric_Arg_Value_MAC_Address, ++ Cx_Fabric_Arg_Value_Bitmap, ++} cx_fabric_arg_type_t; ++ ++typedef struct { ++ char *keyword; ++ cx_fabric_arg_type_t arg_type; ++ void *data; ++} cx_fabric_arg_t; ++ ++#define MAX_PERMITTED_PARAMS 20 ++#define MAX_PERMITTED_SPECIFIERS 20 ++#define MAX_REQUIRED_SPECIFIERS 20 ++ ++#define IPMI_CMD_OEM_PARAMETER_UNDEF 0 ++#define IPMI_CMD_OEM_SPECIFIER_UNDEF 0 ++ ++typedef struct { ++ char *keyword; ++ uint8_t ipmi_cmd; ++ uint8_t parameter_required; ++ uint8_t parameter_value_expected; ++ uint8_t permitted_params[MAX_PERMITTED_PARAMS]; ++ uint8_t permitted_specifiers[MAX_PERMITTED_SPECIFIERS]; ++ uint8_t required_specifiers[MAX_REQUIRED_SPECIFIERS]; ++} cx_fabric_cmd_t; ++ ++cx_fabric_cmd_t update_cmd = { ++ "update_config", ++ IPMI_CMD_OEM_FABRIC_UPDATE_CONFIG, ++ 0, 0, ++ {0, 0, 0, 0, 0}, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_NODE, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PARTITION, 0, 0, 0}, ++ {0, 0, 0, 0, 0} ++}; ++ ++cx_fabric_cmd_t factory_default_node_cmd = { ++ "factory_default", ++ IPMI_CMD_OEM_FABRIC_FACTORY_DEFAULT, ++ 0, 0, ++ {0, 0, 0, 0, 0}, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_PARTITION, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_CONFIGURATION, 0, 0, 0}, ++ {0, 0, 0, 0, 0} ++}; ++ ++cx_fabric_cmd_t get_cmd = { ++ "get", ++ IPMI_CMD_OEM_FABRIC_GET, ++ 1, 0, ++ {IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NETMASK, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_DEFGW, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPSRC, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MACADDR, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NODEID, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_RESILIENCE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_SERVER, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_PORT, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_CONFIGURATIONID, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PROFILEID, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITION_NODES, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITION_RANGE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR_BASE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR_NUM, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED_POLICY, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_CUSTOMER_MACADDR, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_USERS_FACTOR}, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_NODE, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_INTERFACE, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_LINK, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_OVERRIDE, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_ACTUAL, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_CONFIGURATION, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PARTITION, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PROFILE}, ++ {0, 0, 0, 0, 0} ++}; ++ ++cx_fabric_cmd_t set_cmd = { ++ "set", ++ IPMI_CMD_OEM_FABRIC_SET, ++ 1, 1, ++ {IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NETMASK, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_DEFGW, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPSRC, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_RESILIENCE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_SERVER, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_PORT, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_CUSTOMER_MACADDR, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_CONFIGURATIONID, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITIONID, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PROFILEID, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR_BASE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR_NUM, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED_POLICY, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_USERS_FACTOR}, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_NODE, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_INTERFACE, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_LINK, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_OVERRIDE, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_CONFIGURATION, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PARTITION, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PROFILE}, ++ {0, 0, 0, 0, 0} ++}; ++ ++cx_fabric_cmd_t add_cmd = { ++ "add", ++ IPMI_CMD_OEM_FABRIC_ADD, ++ 1, 1, ++ {IPMI_CMD_OEM_FABRIC_PARAMETER_MACADDR, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_CONFIGURATIONID, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITION_NODES, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITION_RANGE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITIONID, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PROFILEID}, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_NODE, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_INTERFACE, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PARTITION, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_CONFIGURATION, 0, 0}, ++ {0, 0, 0, 0, 0} ++}; ++ ++cx_fabric_cmd_t rm_cmd = { ++ "rm", ++ IPMI_CMD_OEM_FABRIC_RM, ++ 1, 1, ++ {IPMI_CMD_OEM_FABRIC_PARAMETER_MACADDR, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_CONFIGURATIONID, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITION_RANGE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITIONID, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PROFILEID}, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_NODE, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_INTERFACE, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PARTITION, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_CONFIGURATION, 0}, ++ {0, 0, 0, 0, 0} ++}; ++ ++cx_fabric_cmd_t info_cmd = { ++ "info", ++ IPMI_CMD_OEM_FABRIC_INFO, ++ 1, 0, ++ {IPMI_CMD_OEM_FABRIC_PARAMETER_LINKMAP, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_DEPTH_CHART, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_ROUTING_TABLE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_STATS, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_STATS, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_CHANNEL_STATS, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_STATS, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_USERS}, ++ { IPMI_CMD_OEM_FABRIC_SPECIFIER_MAC, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_LINK, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_TFTP, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PORT, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_FILENAME}, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_FILENAME, 0, 0, 0, 0} ++}; ++ ++cx_fabric_cmd_t set_watch_cmd = { ++ "set_watch", ++ IPMI_CMD_OEM_FABRIC_SET_WATCH, ++ 1, 0, ++ {IPMI_CMD_OEM_FABRIC_PARAMETER_GLOBAL_WATCH, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_WATCH, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_CHANNEL_WATCH, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_WATCH, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_WATCH, 0}, ++ { IPMI_CMD_OEM_FABRIC_SPECIFIER_MAC, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_LINK, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_HOST, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PORT, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_FREQUENCY, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_AVERAGING_FREQUENCY}, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_HOST, 0, 0, 0, 0, 0} ++}; ++ ++cx_fabric_cmd_t clear_watch_cmd = { ++ "clear_watch", ++ IPMI_CMD_OEM_FABRIC_CLEAR_WATCH, ++ 1, 0, ++ {IPMI_CMD_OEM_FABRIC_PARAMETER_GLOBAL_WATCH, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_WATCH, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_CHANNEL_WATCH, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_WATCH, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_WATCH, 0}, ++ { IPMI_CMD_OEM_FABRIC_SPECIFIER_MAC, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_LINK, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_HOST, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PORT, 0}, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_HOST, 0, 0, 0, 0} ++}; ++ ++cx_fabric_cmd_t trace_cmd = { ++ "trace", ++ IPMI_CMD_OEM_FABRIC_TRACE, ++ 1, 0, ++ {IPMI_CMD_OEM_FABRIC_PARAMETER_START, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_STOP, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_STATUS, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_DUMP, 0}, ++ { IPMI_CMD_OEM_FABRIC_SPECIFIER_TFTP, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_FILENAME, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_SIZE, 0}, ++ {0, 0, 0, 0, 0} ++}; ++ ++#define MAC_ADDRESS_SIZE 6 ++typedef uint8_t mac_address_t[MAC_ADDRESS_SIZE]; ++ ++#define IPV4_ADDRESS_SIZE 4 ++typedef uint8_t ipv4_address_t[IPV4_ADDRESS_SIZE]; ++ ++#define MAX_VAL_STRING 20 ++#define MAX_VAL_BITMAP 25 ++typedef union { ++ uint8_t scalar[4]; ++ mac_address_t mac_addr; ++ ipv4_address_t ipv4_addr; ++ char string[MAX_VAL_STRING]; ++ uint8_t bitmap[MAX_VAL_BITMAP]; ++} cx_fabric_value_u; ++ ++typedef struct { ++ cx_fabric_arg_type_t val_type; ++ cx_fabric_value_u val; ++ uint8_t val_len; ++} cx_fabric_value_t; ++ ++typedef struct { ++ char *keyword; ++ uint8_t param; ++ uint8_t required_specifiers[MAX_REQUIRED_SPECIFIERS]; ++ cx_fabric_arg_type_t val_type; ++ int val_len; ++ void (*printer) (void *data, int len); ++} cx_fabric_param_t; ++ ++typedef struct { ++ char *keyword; ++ uint8_t spec; ++ cx_fabric_arg_type_t val_type; ++ int val_len; ++ void (*printer) (void *data, int len); ++} cx_fabric_spec_t; ++ ++void cx_fabric_string_printer(void *data, int len) ++{ ++ int i; ++ cx_fabric_value_t *val = (cx_fabric_value_t *) data; ++ int value = 0; ++ ++ printf("%s\n", val->val.string); ++ return; ++} ++ ++void cx_fabric_bitmap_printer(void *data, int len) ++{ ++ int i, in_range = 0, range_start = 0; ++ int first = 1; ++ cx_fabric_value_t *val = (cx_fabric_value_t *) data; ++ ++ for (i = 0; i < MAX_VAL_BITMAP * 8; i++) { ++ if (val->val.bitmap[i/8] & (1 << (i%8))) { ++ if (in_range) { ++ continue; ++ } else { ++ if (first) { ++ printf("%d", i); ++ first = 0; ++ } else { ++ printf(",%d", i); ++ } ++ range_start = i; ++ in_range = 1; ++ } ++ } else if (in_range) { ++ if (range_start != (i-1)) { ++ printf("-%d", i-1); ++ } ++ in_range = 0; ++ } ++ } ++ ++ if (in_range) { ++ if (range_start != (i-1)) { ++ printf("-%d", i-1); ++ } ++ } else if (first) { ++ printf("No nodes in partition"); ++ } ++ ++ printf("\n"); ++ return; ++} ++ ++void cx_fabric_scalar_printer(void *data, int len) ++{ ++ int i; ++ cx_fabric_value_t *val = (cx_fabric_value_t *) data; ++ int value = 0; ++ ++ for (i = 0; i < len; i++) { ++ value |= (val->val.scalar[i] << (8 * i)); ++ } ++ printf("%d\n", value); ++ return; ++} ++ ++void cx_fabric_hex_printer(void *data, int len) ++{ ++ int i; ++ cx_fabric_value_t *val = (cx_fabric_value_t *) data; ++ int value = 0; ++ ++ for (i = 0; i < len; i++) { ++ value |= (val->val.scalar[i] << (8 * i)); ++ } ++ printf("0x%0x\n", (unsigned int)value); ++ return; ++} ++ ++void cx_fabric_ipv4_printer(void *data, int len) ++{ ++ cx_fabric_value_t *val = (cx_fabric_value_t *) data; ++ printf("%d.%d.%d.%d\n", val->val.ipv4_addr[0], ++ val->val.ipv4_addr[1], val->val.ipv4_addr[2], ++ val->val.ipv4_addr[3]); ++ return; ++} ++ ++void cx_fabric_mac_printer(void *data, int len) ++{ ++ cx_fabric_value_t *val = (cx_fabric_value_t *) data; ++ printf("%02x:%02x:%02x:%02x:%02x:%02x\n", ++ val->val.mac_addr[0], val->val.mac_addr[1], val->val.mac_addr[2], ++ val->val.mac_addr[3], val->val.mac_addr[4], ++ val->val.mac_addr[5]); ++ return; ++} ++ ++cx_fabric_param_t ipaddr_param = { ++ "ipaddr", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR, ++ {0, 0, 0, 0, 0} ++ , ++ Cx_Fabric_Arg_Value_IPV4_Address, 4, ++ cx_fabric_ipv4_printer ++}; ++ ++cx_fabric_param_t ntp_server_param = { ++ "ntp_server", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_SERVER, ++ {0, 0, 0, 0, 0} ++ , ++ Cx_Fabric_Arg_Value_IPV4_Address, 4, ++ cx_fabric_ipv4_printer ++}; ++ ++cx_fabric_param_t ntp_port_param = { ++ "ntp_port", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_PORT, ++ {0, 0, 0, 0, 0} ++ , ++ Cx_Fabric_Arg_Value_Scalar, 2, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t ipsrc_param = { ++ "ipsrc", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPSRC, ++ {0, 0, 0, 0, 0} ++ , ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t netmask_param = { ++ "netmask", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NETMASK, ++ {0, 0, 0, 0, 0} ++ , ++ Cx_Fabric_Arg_Value_IPV4_Address, 4, ++ cx_fabric_ipv4_printer ++}; ++ ++cx_fabric_param_t defgw_param = { ++ "defgw", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_DEFGW, ++ {0, 0, 0, 0, 0} ++ , ++ Cx_Fabric_Arg_Value_IPV4_Address, 4, ++ cx_fabric_ipv4_printer ++}; ++ ++cx_fabric_param_t nodeid_param = { ++ "nodeid", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NODEID, ++ {0, 0, 0, 0, 0} ++ , ++ Cx_Fabric_Arg_Value_Scalar, 2, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t linkspeed_param = { ++ "linkspeed", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED, ++ {0, 0, 0, 0, 0} ++ , ++ Cx_Fabric_Arg_Value_Scalar, 4, ++ cx_fabric_string_printer ++}; ++ ++cx_fabric_param_t link_resilience_param = { ++ "link_resilience", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_RESILIENCE, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t linkspeed_policy_param = { ++ "ls_policy", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED_POLICY, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t link_users_factor_param = { ++ "lu_factor", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_USERS_FACTOR, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t uplink_param = { ++ "uplink", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_INTERFACE, ++ 0, 0, 0, 0} ++ , ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t cust_macaddr_param = { ++ "customer_macaddr", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_CUSTOMER_MACADDR, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_INTERFACE, 0, 0, 0, 0} ++ , ++ Cx_Fabric_Arg_Value_MAC_Address, 6, ++ cx_fabric_mac_printer ++}; ++ ++cx_fabric_param_t macaddr_param = { ++ "macaddr", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MACADDR, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_INTERFACE, 0, 0, 0, 0} ++ , ++ Cx_Fabric_Arg_Value_MAC_Address, 6, ++ cx_fabric_mac_printer ++}; ++ ++cx_fabric_param_t linkmap_param = { ++ "linkmap", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINKMAP, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t depth_chart_param = { ++ "depth_chart", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_DEPTH_CHART, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t routing_table_param = { ++ "routing_table", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_ROUTING_TABLE, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t link_users_param = { ++ "link_users", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_USERS, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t global_watch_param = { ++ "global_watch", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_GLOBAL_WATCH, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t link_stats_param = { ++ "link_stats", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_STATS, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_LINK, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t link_watch_param = { ++ "link_watch_stats", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_WATCH, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_LINK, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t mac_stats_param = { ++ "mac_stats", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_STATS, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_MAC, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t mac_watch_param = { ++ "mac_watch", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_WATCH, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_MAC, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t mac_channel_stats_param = { ++ "mac_channel_stats", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_CHANNEL_STATS, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_MAC, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t mac_channel_watch_param = { ++ "mac_channel_watch", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MAC_CHANNEL_WATCH, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_MAC, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t uplink_stats_param = { ++ "uplink_stats", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_STATS, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t uplink_watch_param = { ++ "uplink_watch", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_WATCH, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t configurationid_param = { ++ "configid", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_CONFIGURATIONID, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t partitionid_param = { ++ "partid", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITIONID, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t profileid_param = { ++ "profileid", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PROFILEID, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t partition_nodes_param = { ++ "part_nodes", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITION_NODES, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_PARTITION, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_CONFIGURATION, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t partition_range_param = { ++ "part_range", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_PARTITION_RANGE, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_PARTITION, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_CONFIGURATION, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Bitmap, MAX_VAL_BITMAP, ++ cx_fabric_bitmap_printer ++}; ++ ++cx_fabric_param_t ipaddr_base_param = { ++ "ipaddr_base", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR_BASE, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_IPV4_Address, 4, ++ cx_fabric_ipv4_printer ++}; ++ ++cx_fabric_param_t ipaddr_num_param = { ++ "ipaddr_num", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR_NUM, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 2, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t start_param = { ++ "start", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_START, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t stop_param = { ++ "stop", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_STOP, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t status_param = { ++ "status", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_STATUS, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t dump_param = { ++ "dump", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_DUMP, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_TFTP, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_FILENAME, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_spec_t node_spec = { ++ "node", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_NODE, ++ Cx_Fabric_Arg_Value_Scalar, 2, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_spec_t interface_spec = { ++ "interface", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_INTERFACE, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_spec_t link_spec = { ++ "link", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_LINK, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_spec_t override_spec = { ++ "override", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_OVERRIDE, ++ Cx_Fabric_Arg_Invalid, 0, ++ NULL ++}; ++ ++cx_fabric_spec_t actual_spec = { ++ "actual", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_ACTUAL, ++ Cx_Fabric_Arg_Invalid, 0, ++ NULL ++}; ++ ++cx_fabric_spec_t mac_spec = { ++ "mac", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_MAC, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_spec_t tftp_spec = { ++ "tftp", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_TFTP, ++ Cx_Fabric_Arg_Value_IPV4_Address, 4, ++ cx_fabric_ipv4_printer ++}; ++ ++cx_fabric_spec_t host_spec = { ++ "host", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_HOST, ++ Cx_Fabric_Arg_Value_IPV4_Address, 4, ++ cx_fabric_ipv4_printer ++}; ++ ++cx_fabric_spec_t port_spec = { ++ "port", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PORT, ++ Cx_Fabric_Arg_Value_Scalar, 2, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_spec_t frequency_spec = { ++ "frequency", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_FREQUENCY, ++ Cx_Fabric_Arg_Value_Scalar, 2, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_spec_t averaging_frequency_spec = { ++ "averaging_frequency", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_AVERAGING_FREQUENCY, ++ Cx_Fabric_Arg_Value_Scalar, 2, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_spec_t file_spec = { ++ "file", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_FILENAME, ++ Cx_Fabric_Arg_Value_String, 20, ++ cx_fabric_string_printer ++}; ++ ++cx_fabric_spec_t configuration_spec = { ++ "config", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_CONFIGURATION, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_spec_t partition_spec = { ++ "part", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PARTITION, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_spec_t profile_spec = { ++ "profile", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PROFILE, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_spec_t size_spec = { ++ "size", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_SIZE, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_arg_t cx_fabric_main_arg[] = { ++ {"set_watch", Cx_Fabric_Arg_Command, (void *)&set_watch_cmd}, ++ {"clear_watch", Cx_Fabric_Arg_Command, (void *)&clear_watch_cmd}, ++ {"get", Cx_Fabric_Arg_Command, (void *)&get_cmd}, ++ {"set", Cx_Fabric_Arg_Command, (void *)&set_cmd}, ++ {"add", Cx_Fabric_Arg_Command, (void *)&add_cmd}, ++ {"rm", Cx_Fabric_Arg_Command, (void *)&rm_cmd}, ++ {"info", Cx_Fabric_Arg_Command, (void *)&info_cmd}, ++ {"update_config", Cx_Fabric_Arg_Command, (void *)&update_cmd}, ++ {"factory_default", Cx_Fabric_Arg_Command, (void *)&factory_default_node_cmd}, ++ {"trace", Cx_Fabric_Arg_Command, (void *)&trace_cmd}, ++ {"ipaddr_base", Cx_Fabric_Arg_Parameter, (void *)&ipaddr_base_param}, ++ {"ipaddr_num", Cx_Fabric_Arg_Parameter, (void *)&ipaddr_num_param}, ++ {"ipaddr", Cx_Fabric_Arg_Parameter, (void *)&ipaddr_param}, ++ {"ipsrc", Cx_Fabric_Arg_Parameter, (void *)&ipsrc_param}, ++ {"netmask", Cx_Fabric_Arg_Parameter, (void *)&netmask_param}, ++ {"ntp_server", Cx_Fabric_Arg_Parameter, (void *)&ntp_server_param}, ++ {"ntp_port", Cx_Fabric_Arg_Parameter, (void *)&ntp_port_param}, ++ {"defgw", Cx_Fabric_Arg_Parameter, (void *)&defgw_param}, ++ {"customer_macaddr", Cx_Fabric_Arg_Parameter, (void *)&cust_macaddr_param}, ++ {"macaddr", Cx_Fabric_Arg_Parameter, (void *)&macaddr_param}, ++ {"nodeid", Cx_Fabric_Arg_Parameter, (void *)&nodeid_param}, ++ {"linkspeed", Cx_Fabric_Arg_Parameter, (void *)&linkspeed_param}, ++ {"link_resilience", Cx_Fabric_Arg_Parameter, (void *)&link_resilience_param}, ++ {"ls_policy", Cx_Fabric_Arg_Parameter, (void *)&linkspeed_policy_param}, ++ {"lu_factor", Cx_Fabric_Arg_Parameter, ++ (void *)&link_users_factor_param}, ++ {"linkmap", Cx_Fabric_Arg_Parameter, (void *)&linkmap_param}, ++ {"depth_chart", Cx_Fabric_Arg_Parameter, (void *)&depth_chart_param}, ++ {"routing_table", Cx_Fabric_Arg_Parameter, (void *)&routing_table_param}, ++ {"link_users", Cx_Fabric_Arg_Parameter, (void *)&link_users_param}, ++ {"global_watch", Cx_Fabric_Arg_Parameter, (void *)&global_watch_param}, ++ {"link_stats", Cx_Fabric_Arg_Parameter, (void *)&link_stats_param}, ++ {"link_watch", Cx_Fabric_Arg_Parameter, (void *)&link_watch_param}, ++ {"mac_channel_stats", Cx_Fabric_Arg_Parameter, ++ (void *)&mac_channel_stats_param}, ++ {"mac_channel_watch", Cx_Fabric_Arg_Parameter, ++ (void *)&mac_channel_watch_param}, ++ {"mac_stats", Cx_Fabric_Arg_Parameter, (void *)&mac_stats_param}, ++ {"mac_watch", Cx_Fabric_Arg_Parameter, (void *)&mac_watch_param}, ++ {"uplink_stats", Cx_Fabric_Arg_Parameter, (void *)&uplink_stats_param}, ++ {"uplink_watch", Cx_Fabric_Arg_Parameter, (void *)&uplink_watch_param}, ++ {"uplink", Cx_Fabric_Arg_Parameter, (void *)&uplink_param}, ++ {"configid", Cx_Fabric_Arg_Parameter, (void *)&configurationid_param}, ++ {"partid", Cx_Fabric_Arg_Parameter, (void *)&partitionid_param}, ++ {"profileid", Cx_Fabric_Arg_Parameter, (void *)&profileid_param}, ++ {"part_nodes", Cx_Fabric_Arg_Parameter, (void *)&partition_nodes_param}, ++ {"part_range", Cx_Fabric_Arg_Parameter, (void *)&partition_range_param}, ++ {"start", Cx_Fabric_Arg_Parameter, (void *)&start_param}, ++ {"stop", Cx_Fabric_Arg_Parameter, (void *)&stop_param}, ++ {"status", Cx_Fabric_Arg_Parameter, (void *)&status_param}, ++ {"dump", Cx_Fabric_Arg_Parameter, (void *)&dump_param}, ++ {"node", Cx_Fabric_Arg_Specifier, (void *)&node_spec}, ++ {"interface", Cx_Fabric_Arg_Specifier, (void *)&interface_spec}, ++ {"link", Cx_Fabric_Arg_Specifier, (void *)&link_spec}, ++ {"override", Cx_Fabric_Arg_Specifier, (void *)&override_spec}, ++ {"actual", Cx_Fabric_Arg_Specifier, (void *)&actual_spec}, ++ {"mac", Cx_Fabric_Arg_Specifier, (void *)&mac_spec}, ++ {"tftp", Cx_Fabric_Arg_Specifier, (void *)&tftp_spec}, ++ {"host", Cx_Fabric_Arg_Specifier, (void *)&host_spec}, ++ {"port", Cx_Fabric_Arg_Specifier, (void *)&port_spec}, ++ {"size", Cx_Fabric_Arg_Specifier, (void *)&size_spec}, ++ {"frequency", Cx_Fabric_Arg_Specifier, (void *)&frequency_spec}, ++ {"averaging_frequency", Cx_Fabric_Arg_Specifier, (void *)&averaging_frequency_spec}, ++ {"file", Cx_Fabric_Arg_Specifier, (void *)&file_spec}, ++ {"config", Cx_Fabric_Arg_Specifier, (void *)&configuration_spec}, ++ {"part", Cx_Fabric_Arg_Specifier, (void *)&partition_spec}, ++ {"profile", Cx_Fabric_Arg_Specifier, (void *)&profile_spec}, ++ {NULL, Cx_Fabric_Arg_Invalid, (void *)NULL}, ++}; ++ ++cx_fabric_cmd_t config_get_cmd = { ++ "get", ++ IPMI_CMD_OEM_FABRIC_CONFIG_GET, ++ 1, 0, ++ {IPMI_CMD_OEM_FABRIC_PARAMETER_IPINFO, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPSRC, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MTU, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_MODE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MACADDRS, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_SERVER, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_PORT, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_RESILIENCE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NODENUM_OFFSET, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR_BASE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR_NUM, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NETMASK, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_DEFGW, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED_POLICY, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_USERS_FACTOR, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_INFO, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LACP_STATUS, ++ }, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_TFTP, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PORT, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_FILENAME, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_OVERRIDE, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_ACTUAL, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_INTERFACE, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ }, ++ { ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ } ++}; ++ ++cx_fabric_cmd_t config_set_cmd = { ++ "set", ++ IPMI_CMD_OEM_FABRIC_CONFIG_SET, ++ 1, 1, ++ {IPMI_CMD_OEM_FABRIC_PARAMETER_IPINFO, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPSRC, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MTU, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_MODE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MACADDRS, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_SERVER, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_PORT, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_RESILIENCE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NODENUM_OFFSET, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR_BASE, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPADDR_NUM, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NETMASK, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_DEFGW, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED_POLICY, ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_USERS_FACTOR, ++ }, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_TFTP, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PORT, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_FILENAME, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_OVERRIDE, ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_INTERFACE, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ }, ++ {IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ IPMI_CMD_OEM_SPECIFIER_UNDEF, ++ } ++}; ++ ++cx_fabric_cmd_t update_config_cmd = { ++ "update_config", ++ IPMI_CMD_OEM_FABRIC_UPDATE_CONFIG, ++ 0, 0, ++ {0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0} ++}; ++ ++cx_fabric_cmd_t factory_default_cmd = { ++ "factory_default", ++ IPMI_CMD_OEM_FABRIC_FACTORY_DEFAULT, ++ 0, 0, ++ {0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0}, ++ {0, 0, 0, 0, 0} ++}; ++ ++cx_fabric_param_t ipinfo_config_param = { ++ "ipinfo", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPINFO, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_FILENAME, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Invalid, 0, ++ NULL ++}; ++ ++cx_fabric_param_t uplink_info_config_param = { ++ "uplink_info", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_INFO, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_FILENAME, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Invalid, 0, ++ NULL ++}; ++ ++cx_fabric_param_t lacp_status_config_param = { ++ "lacp_status", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LACP_STATUS, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 4, ++ cx_fabric_hex_printer ++}; ++ ++cx_fabric_param_t ntp_server_config_param = { ++ "ntp_server", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_SERVER, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_IPV4_Address, 4, ++ cx_fabric_ipv4_printer ++}; ++ ++cx_fabric_param_t ntp_port_config_param = { ++ "ntp_port", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NTP_PORT, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 2, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t nodenum_offset_config_param = { ++ "nodenum_offset", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_NODENUM_OFFSET, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 2, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t ipsrc_config_param = { ++ "ipsrc", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_IPSRC, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t mtu_config_param = { ++ "mtu", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MTU, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 2, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t uplink_mode_config_param = { ++ "uplink_mode", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_UPLINK_MODE, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t macaddrs_config_param = { ++ "macaddrs", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_MACADDRS, ++ {IPMI_CMD_OEM_FABRIC_SPECIFIER_FILENAME, 0, 0, 0}, ++ Cx_Fabric_Arg_Invalid, 0, ++ NULL ++}; ++ ++cx_fabric_param_t linkspeed_config_param = { ++ "linkspeed", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 4, ++ cx_fabric_string_printer ++}; ++ ++cx_fabric_param_t link_resilience_config_param = { ++ "link_resilience", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINK_RESILIENCE, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_param_t linkspeed_policy_config_param = { ++ "ls_policy", ++ IPMI_CMD_OEM_FABRIC_PARAMETER_LINKSPEED_POLICY, ++ {0, 0, 0, 0, 0}, ++ Cx_Fabric_Arg_Value_Scalar, 1, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_spec_t tftp_config_spec = { ++ "tftp", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_TFTP, ++ Cx_Fabric_Arg_Value_IPV4_Address, 4, ++ cx_fabric_ipv4_printer ++}; ++ ++cx_fabric_spec_t port_config_spec = { ++ "port", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_PORT, ++ Cx_Fabric_Arg_Value_Scalar, 2, ++ cx_fabric_scalar_printer ++}; ++ ++cx_fabric_spec_t file_config_spec = { ++ "file", ++ IPMI_CMD_OEM_FABRIC_SPECIFIER_FILENAME, ++ Cx_Fabric_Arg_Value_String, 20, ++ cx_fabric_string_printer ++}; ++ ++cx_fabric_arg_t cx_fabric_config_arg[] = { ++ {"get", Cx_Fabric_Arg_Command, (void *)&config_get_cmd}, ++ {"set", Cx_Fabric_Arg_Command, (void *)&config_set_cmd}, ++ {"update_config", Cx_Fabric_Arg_Command, (void *)&update_config_cmd}, ++ {"factory_default", Cx_Fabric_Arg_Command, (void *)&factory_default_cmd}, ++ {"ipinfo", Cx_Fabric_Arg_Parameter, (void *)&ipinfo_config_param}, ++ {"uplink_info", Cx_Fabric_Arg_Parameter, (void *)&uplink_info_config_param}, ++ {"lacp_status", Cx_Fabric_Arg_Parameter, (void *)&lacp_status_config_param}, ++ {"ntp_server", Cx_Fabric_Arg_Parameter, (void *)&ntp_server_config_param}, ++ {"ntp_port", Cx_Fabric_Arg_Parameter, (void *)&ntp_port_config_param}, ++ {"nodenum_offset", Cx_Fabric_Arg_Parameter, (void *)&nodenum_offset_config_param}, ++ {"ipsrc", Cx_Fabric_Arg_Parameter, (void *)&ipsrc_config_param}, ++ {"mtu", Cx_Fabric_Arg_Parameter, (void *)&mtu_config_param}, ++ {"uplink_mode", Cx_Fabric_Arg_Parameter, ++ (void *)&uplink_mode_config_param}, ++ {"uplink", Cx_Fabric_Arg_Parameter, (void *)&uplink_param}, ++ {"macaddrs", Cx_Fabric_Arg_Parameter, (void *)&macaddrs_config_param}, ++ {"linkspeed", Cx_Fabric_Arg_Parameter, (void *)&linkspeed_config_param}, ++ {"link_resilience", Cx_Fabric_Arg_Parameter, ++ (void *)&link_resilience_config_param}, ++ {"ls_policy", Cx_Fabric_Arg_Parameter, ++ (void *)&linkspeed_policy_config_param}, ++ {"lu_factor", Cx_Fabric_Arg_Parameter, ++ (void *)&link_users_factor_param}, ++ {"ipaddr_base", Cx_Fabric_Arg_Parameter, (void *)&ipaddr_base_param}, ++ {"ipaddr_num", Cx_Fabric_Arg_Parameter, (void *)&ipaddr_num_param}, ++ {"netmask", Cx_Fabric_Arg_Parameter, (void *)&netmask_param}, ++ {"defgw", Cx_Fabric_Arg_Parameter, (void *)&defgw_param}, ++ {"tftp", Cx_Fabric_Arg_Specifier, (void *)&tftp_config_spec}, ++ {"port", Cx_Fabric_Arg_Specifier, (void *)&port_config_spec}, ++ {"file", Cx_Fabric_Arg_Specifier, (void *)&file_config_spec}, ++ {"override", Cx_Fabric_Arg_Specifier, (void *)&override_spec}, ++ {"interface", Cx_Fabric_Arg_Specifier, (void *)&interface_spec}, ++ {NULL, Cx_Fabric_Arg_Invalid, (void *)NULL}, ++}; ++ ++cx_fabric_arg_type_t ++cx_fabric_find_arg_type(cx_fabric_arg_t * arg_type_list, char *arg) ++{ ++ int i, ip0, ip1, ip2, ip3; ++ int mac0, mac1, mac2, mac3, mac4, mac5; ++ int ls0, ls1; ++ int val; ++ int ret; ++ ++ errno = 0; ++ ++ // First see if it is a standard type (Command, Parameter, Specifier) ++ i = 0; ++ while (arg_type_list[i].keyword != NULL) { ++ if ((strlen(arg) == strlen(arg_type_list[i].keyword)) && ++ !strncasecmp(arg, arg_type_list[i].keyword, ++ strlen(arg_type_list[i].keyword))) { ++ return arg_type_list[i].arg_type; ++ } ++ i++; ++ } ++ ++ // If not, is it an expected value type (Scalar, String, ++ // IPV4 address, MAC address ++ ++ // Is it a MAC Address? ++ if ((sscanf(arg, "%02x:%02x:%02x:%02x:%02x:%02x", ++ &mac0, &mac1, &mac2, &mac3, &mac4, &mac5)) == 6) { ++ return Cx_Fabric_Arg_Value_MAC_Address; ++ } ++ // Is it an IPV4 Address? ++ if ((sscanf(arg, "%d.%d.%d.%d", &ip0, &ip1, &ip2, &ip3)) == 4) { ++ return Cx_Fabric_Arg_Value_IPV4_Address; ++ } ++ ++ if ((sscanf(arg, "%d.%d", &ls0, &ls1)) == 2) { ++ return Cx_Fabric_Arg_Value_Scalar; ++ } ++ ++ // Is it a string? ++ if (isalpha(arg[0])) { ++ // Probably... ++ return Cx_Fabric_Arg_Value_String; ++ } ++ ++ // Is it a node range? ++ if (strchr(arg, '-') || strchr(arg, ',')) { ++ return Cx_Fabric_Arg_Value_Bitmap; ++ } ++ ++ // Is it scalar? ++ val = strtol(arg, NULL, 10); ++ if (errno == 0) { ++ return Cx_Fabric_Arg_Value_Scalar; ++ } ++ ++ return Cx_Fabric_Arg_Invalid; ++} ++ ++cx_fabric_cmd_t *cx_fabric_get_cmd(cx_fabric_arg_t * arg_type_list, char *arg) ++{ ++ int i; ++ ++ errno = 0; ++ ++ i = 0; ++ while (arg_type_list[i].keyword != NULL) { ++ if (!strncasecmp(arg, arg_type_list[i].keyword, ++ strlen(arg_type_list[i].keyword))) { ++ return ((cx_fabric_cmd_t *) arg_type_list[i].data); ++ } ++ i++; ++ } ++ return NULL; ++} ++ ++cx_fabric_param_t *cx_fabric_get_param(cx_fabric_arg_t * arg_type_list, ++ char *arg) ++{ ++ int i; ++ ++ errno = 0; ++ ++ i = 0; ++ while (arg_type_list[i].keyword != NULL) { ++ if (!strncasecmp(arg, arg_type_list[i].keyword, ++ strlen(arg_type_list[i].keyword))) { ++ return ((cx_fabric_param_t *) arg_type_list[i].data); ++ } ++ i++; ++ } ++ return NULL; ++} ++ ++cx_fabric_spec_t *cx_fabric_get_spec(cx_fabric_arg_t * arg_type_list, char *arg) ++{ ++ int i; ++ ++ errno = 0; ++ ++ i = 0; ++ while (arg_type_list[i].keyword != NULL) { ++ if (!strncasecmp(arg, arg_type_list[i].keyword, ++ strlen(arg_type_list[i].keyword))) { ++ return ((cx_fabric_spec_t *) arg_type_list[i].data); ++ } ++ i++; ++ } ++ return NULL; ++} ++ ++int ranges_to_bitmap(char *arg, uint8_t *bitmap) ++{ ++ int start, end, i = 0; ++ char *ptr = arg; ++ while(*ptr) { ++ //printf("ptr = %s\n", ptr); ++ start = strtol(ptr, &ptr, 10); ++ if (*ptr == '-') { ++ ptr++; ++ end = strtol(ptr, &ptr, 10); ++ for (i = start; i <= end; i++) { ++ bitmap[i/8] |= (1 << (i%8)); ++ } ++ } else { ++ bitmap[start/8] |= (1 << (start%8)); ++ } ++ ++ if (*ptr == ',') { ++ ptr++; ++ } ++ } ++} ++ ++int ++cx_fabric_get_value(cx_fabric_arg_type_t val_type, char *arg, ++ cx_fabric_value_t * value) ++{ ++ int val; ++ int i; ++ ++ value->val_type = val_type; ++ switch (val_type) { ++ case Cx_Fabric_Arg_Value_Scalar: ++ val = strtol(arg, NULL, 10); ++ value->val.scalar[0] = val & 0xff; ++ value->val.scalar[1] = ((val >> 8) & 0xff); ++ value->val.scalar[2] = ((val >> 16) & 0xff); ++ value->val.scalar[3] = ((val >> 24) & 0xff); ++ value->val_len = 4; ++ break; ++ case Cx_Fabric_Arg_Value_String: ++ strncpy(value->val.string, arg, MAX_VAL_STRING); ++ value->val_len = strlen(value->val.string); ++ break; ++ case Cx_Fabric_Arg_Value_IPV4_Address: ++ sscanf(arg, "%d.%d.%d.%d", ++ (int *)&value->val.ipv4_addr[0], ++ (int *)&value->val.ipv4_addr[1], ++ (int *)&value->val.ipv4_addr[2], ++ (int *)&value->val.ipv4_addr[3]); ++ value->val_len = 4; ++ break; ++ case Cx_Fabric_Arg_Value_MAC_Address: ++ sscanf(arg, "%02x:%02x:%02x:%02x:%02x:%02x", ++ (int *)&value->val.mac_addr[0], ++ (int *)&value->val.mac_addr[1], ++ (int *)&value->val.mac_addr[2], ++ (int *)&value->val.mac_addr[3], ++ (int *)&value->val.mac_addr[4], ++ (int *)&value->val.mac_addr[5]); ++ value->val_len = 6; ++ fprintf(stdout, "ADDR = %02x:%02x:%02x:%02x:%02x:%02x\n", ++ value->val.mac_addr[0], value->val.mac_addr[1], ++ value->val.mac_addr[2], value->val.mac_addr[3], ++ value->val.mac_addr[4], value->val.mac_addr[5]); ++ ++ break; ++ case Cx_Fabric_Arg_Value_Bitmap: ++ memset(value->val.bitmap, 0, MAX_VAL_BITMAP); ++ ranges_to_bitmap(arg, value->val.bitmap); ++ value->val_len = MAX_VAL_BITMAP; ++ break; ++ default: ++ return -1; ++ break; ++ }; ++ return 0; ++} ++ ++#define MAX_SPECS 8 ++int ++cx_fabric_cmd_parser(struct ipmi_intf *intf, ++ cx_fabric_arg_t * args, int argc, char **argv) ++{ ++ int ret, i, j, cur_arg = 0; ++ cx_fabric_arg_type_t arg_type; ++ struct ipmi_rq req; ++ struct ipmi_rs *rsp; ++ uint8_t msg_data[128]; ++ cx_fabric_cmd_t *cmd = NULL; ++ cx_fabric_param_t *param = NULL; ++ cx_fabric_value_t param_value; ++ cx_fabric_spec_t *spec[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; ++ cx_fabric_value_t spec_value[MAX_SPECS]; ++ uint8_t spec_count = 0, req_specs = 0, req_specs_found = 0; ++ int data_pos = 0; ++ ++ ++ if (argc < 1 || strncmp(argv[0], "help", 4) == 0) { ++ cx_fabric_usage(); ++ return 0; ++ } ++ ++ param_value.val_type = Cx_Fabric_Arg_Invalid; ++ memset(&spec_value[0], 0, MAX_SPECS * sizeof(cx_fabric_value_t)); ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, 128); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ ++ // Each argument is either a command, a parameter, a value, or a specifier ++ // Commands are config, get, set, update ++ // Parameters are ipaddr, ipsrc, netmask, defgw, macaddr, ++ // linkspeed, uplink ++ // Specifiers are node, interface ++ // Values can be a decimal number, ipv4 address, mac address, or ++ // the strings "static" or "dynamic" ++ ++ while (cur_arg < argc) { ++ //printf("argv[%d] = .%s.\n", cur_arg, argv[cur_arg]); ++ arg_type = cx_fabric_find_arg_type(args, argv[cur_arg]); ++ ++ if (arg_type == Cx_Fabric_Arg_Command) { ++ cmd = cx_fabric_get_cmd(args, argv[cur_arg]); ++ if (cmd == NULL) { ++ lprintf(LOG_NOTICE, ++ "No defined activity for cmd %s\n", ++ argv[cur_arg]); ++ cur_arg++; ++ continue; ++ } ++ req.msg.cmd = cmd->ipmi_cmd; ++ } else if (arg_type == Cx_Fabric_Arg_Parameter) { ++ param = cx_fabric_get_param(args, argv[cur_arg]); ++ ++ if ((cmd && cmd->parameter_value_expected) && ++ (param->val_type != Cx_Fabric_Arg_Invalid)) { ++ ++ if ((cur_arg + 1) >= argc) { ++ lprintf(LOG_ERR, ++ "No value specified for parameter %s\n", ++ param->keyword); ++ return -1; ++ ++ } ++ // Now we need to look at its value ++ cur_arg++; ++ ++ arg_type = cx_fabric_find_arg_type(args, ++ argv ++ [cur_arg]); ++ if ((arg_type == Cx_Fabric_Arg_Value_Scalar) && (param->val_type == Cx_Fabric_Arg_Value_Bitmap)) { ++ arg_type = Cx_Fabric_Arg_Value_Bitmap; ++ } ++ if (arg_type != param->val_type) { ++ lprintf(LOG_ERR, ++ "Invalid value type for parameter %s\n", ++ param->keyword); ++ return -1; ++ } ++ ++ ret = ++ cx_fabric_get_value(arg_type, argv[cur_arg], ++ ¶m_value); ++ } else if (!cmd) { ++ lprintf(LOG_ERR, ++ "No valid command specified\n"); ++ goto cx_fabric_main_error_out; ++ } ++ } else if (arg_type == Cx_Fabric_Arg_Specifier) { ++ spec[spec_count] = ++ cx_fabric_get_spec(args, argv[cur_arg]); ++ ++ if (spec[spec_count]->val_type != Cx_Fabric_Arg_Invalid) { ++ ++ cur_arg++; ++ ++ if ((cur_arg) >= argc) { ++ lprintf(LOG_ERR, ++ "No value specified for specifier %s\n", ++ spec[spec_count]->keyword); ++ return -1; ++ ++ } ++ // Now we need to look at its value ++ arg_type = cx_fabric_find_arg_type(args, ++ argv ++ [cur_arg]); ++ if (arg_type != spec[spec_count]->val_type) { ++ lprintf(LOG_ERR, ++ "Invalid value type for specifier %s\n", ++ spec[spec_count]->keyword); ++ return -1; ++ } ++ ++ ret = ++ cx_fabric_get_value(arg_type, argv[cur_arg], ++ &spec_value ++ [spec_count]); ++ } else { ++ spec_value[spec_count].val_type = ++ Cx_Fabric_Arg_Invalid; ++ spec_value[spec_count].val.scalar[0] = 0; ++ spec_value[spec_count].val_len = 1; ++ ++ } ++ spec_count++; ++ } else { ++ lprintf(LOG_ERR, "Unexpected argument\n"); ++ goto cx_fabric_main_error_out; ++ } ++ ++ cur_arg++; ++ } ++ ++ if (cmd == NULL) { ++ goto cx_fabric_main_error_out; ++ } ++ // Now, sanity check everything before forming the message ++ // Does this command require a parameter, if so do we have one? ++ if (cmd->parameter_required) { ++ if (param == NULL) { ++ lprintf(LOG_ERR, ++ "Required parameter for cmd %s missing\n", ++ cmd->keyword); ++ goto cx_fabric_main_error_out; ++ ++ } ++ } ++ // Does this command accept the parameter being passed? ++ if (param) { ++ for (i = 0; i < MAX_PERMITTED_PARAMS; i++) { ++ if (param->param == cmd->permitted_params[i]) { ++ break; ++ } ++ } ++ if (i == MAX_PERMITTED_PARAMS) { ++ lprintf(LOG_ERR, ++ "Parameter %s not permitted for cmd %s\n", ++ param->keyword, cmd->keyword); ++ goto cx_fabric_main_error_out; ++ } ++ } ++ // Does this command accept the specifiers that are given ++ for (j = 0; j < MAX_SPECS; j++) { ++ if (spec[j]) { ++ for (i = 0; i < MAX_PERMITTED_SPECIFIERS; i++) { ++ if (spec[j]->spec == ++ cmd->permitted_specifiers[i]) { ++ break; ++ } ++ } ++ if (i == MAX_PERMITTED_SPECIFIERS) { ++ lprintf(LOG_ERR, ++ "Specifier %s not permitted for cmd %s\n", ++ spec[j]->keyword, cmd->keyword); ++ goto cx_fabric_main_error_out; ++ } ++ } ++ } ++ // Are all required specifiers for the command present? ++ for (j = 0; j < MAX_REQUIRED_SPECIFIERS; j++) { ++ if (cmd->required_specifiers[j] != 0) { ++ req_specs++; ++ for (i = 0; i < MAX_SPECS; i++) { ++ if (spec[i]) { ++ if (spec[i]->spec == ++ cmd->required_specifiers[j]) { ++ req_specs_found++; ++ } ++ } ++ } ++ } ++ } ++ if (req_specs != req_specs_found) { ++ lprintf(LOG_ERR, "Required specifiers for command %s missing\n", ++ cmd->keyword); ++ goto cx_fabric_main_error_out; ++ } ++ // Are all the required specifiers for the parameter present ++ if (param) { ++ for (j = 0; j < MAX_REQUIRED_SPECIFIERS; j++) { ++ if (param->required_specifiers[j] != 0) { ++ req_specs++; ++ for (i = 0; i < MAX_SPECS; i++) { ++ if (spec[i]) { ++ if (spec[i]->spec == ++ param-> ++ required_specifiers[j]) { ++ req_specs_found++; ++ } ++ } ++ } ++ } ++ } ++ } ++ if (req_specs != req_specs_found) { ++ lprintf(LOG_ERR, ++ "Required specifiers for parameter %s missing\n", ++ param->keyword); ++ goto cx_fabric_main_error_out; ++ } ++ // Start filling in msg_data ++ if (param) { ++ msg_data[data_pos++] = param->param; ++ ++ if (param_value.val_type != Cx_Fabric_Arg_Invalid) { ++ switch (param_value.val_type) { ++ case Cx_Fabric_Arg_Value_Scalar: ++ msg_data[data_pos++] = ++ MSG_PARAM_VAL_START_SCALAR; ++ for (i = 0; i < param_value.val_len; i++) { ++ msg_data[data_pos++] = ++ param_value.val.scalar[i]; ++ } ++ msg_data[data_pos++] = MSG_ELEMENT_TERMINATOR; ++ break; ++ case Cx_Fabric_Arg_Value_String: ++ msg_data[data_pos++] = ++ MSG_PARAM_VAL_START_STRING; ++ for (i = 0; i < param_value.val_len; i++) { ++ msg_data[data_pos++] = ++ param_value.val.string[i]; ++ } ++ msg_data[data_pos++] = MSG_ELEMENT_TERMINATOR; ++ break; ++ case Cx_Fabric_Arg_Value_IPV4_Address: ++ msg_data[data_pos++] = ++ MSG_PARAM_VAL_START_IPV4_ADDR; ++ for (i = 0; i < param_value.val_len; i++) { ++ msg_data[data_pos++] = ++ param_value.val.ipv4_addr[i]; ++ } ++ msg_data[data_pos++] = MSG_ELEMENT_TERMINATOR; ++ break; ++ case Cx_Fabric_Arg_Value_MAC_Address: ++ msg_data[data_pos++] = ++ MSG_PARAM_VAL_START_MAC_ADDR; ++ for (i = 0; i < param_value.val_len; i++) { ++ msg_data[data_pos++] = ++ param_value.val.mac_addr[i]; ++ } ++ msg_data[data_pos++] = MSG_ELEMENT_TERMINATOR; ++ break; ++ case Cx_Fabric_Arg_Value_Bitmap: ++ msg_data[data_pos++] = ++ MSG_PARAM_VAL_START_BITMAP; ++ for (i = 0; i < param_value.val_len; i++) { ++ msg_data[data_pos++] = ++ param_value.val.bitmap[i]; ++ } ++ msg_data[data_pos++] = MSG_ELEMENT_TERMINATOR; ++ break; ++ } ++ } ++ } ++ for (j = 0; j < spec_count; j++) { ++ msg_data[data_pos++] = spec[j]->spec; ++ switch (spec[j]->val_type) { ++ case Cx_Fabric_Arg_Value_Scalar: ++ for (i = 0; i < spec_value[j].val_len; i++) { ++ msg_data[data_pos++] = ++ spec_value[j].val.scalar[i]; ++ } ++ msg_data[data_pos++] = MSG_ELEMENT_TERMINATOR; ++ break; ++ case Cx_Fabric_Arg_Value_String: ++ for (i = 0; i < spec_value[j].val_len; i++) { ++ msg_data[data_pos++] = ++ spec_value[j].val.string[i]; ++ } ++ msg_data[data_pos++] = MSG_ELEMENT_TERMINATOR; ++ break; ++ case Cx_Fabric_Arg_Value_IPV4_Address: ++ for (i = 0; i < spec_value[j].val_len; i++) { ++ msg_data[data_pos++] = ++ spec_value[j].val.ipv4_addr[i]; ++ } ++ msg_data[data_pos++] = MSG_ELEMENT_TERMINATOR; ++ break; ++ case Cx_Fabric_Arg_Value_MAC_Address: ++ for (i = 0; i < spec_value[j].val_len; i++) { ++ msg_data[data_pos++] = ++ spec_value[j].val.mac_addr[i]; ++ } ++ msg_data[data_pos++] = MSG_ELEMENT_TERMINATOR; ++ break; ++ case Cx_Fabric_Arg_Value_Bitmap: ++ msg_data[data_pos++] = ++ MSG_PARAM_VAL_START_BITMAP; ++ for (i = 0; i < param_value.val_len; i++) { ++ msg_data[data_pos++] = ++ param_value.val.bitmap[i]; ++ } ++ msg_data[data_pos++] = MSG_ELEMENT_TERMINATOR; ++ break; ++ } ++ } ++ ++ req.msg.data = msg_data; ++ req.msg.data_len = data_pos; ++ ++ rsp = intf->sendrecv(intf, &req); ++// lprintf(LOG_ERR, "req: netfn: 0x%x, lun: 0x%x, \n" ++// "cmd: 0x%x, target_cmd: 0x%x, data_len: 0x%x\n" ++// "data: \n" ++// "%02x %02x %02x %02x %02x %02x %02x %02x \n" ++// "%02x %02x %02x %02x %02x %02x %02x %02x \n", ++// req.msg.netfn, req.msg.lun, req.msg.cmd, ++// req.msg.target_cmd, req.msg.data_len, ++// req.msg.data[0], req.msg.data[1], req.msg.data[2], req.msg.data[3], ++// req.msg.data[4], req.msg.data[5], req.msg.data[6], req.msg.data[7], ++// req.msg.data[8], req.msg.data[9], req.msg.data[10], req.msg.data[11], ++// req.msg.data[12], req.msg.data[13], req.msg.data[14], req.msg.data[15]); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error during fabric command\n"); ++ return -1; ++ } ++ ++ if (rsp->ccode == 0) { ++ if ((cmd->ipmi_cmd == IPMI_CMD_OEM_FABRIC_GET) || ++ ((cmd->ipmi_cmd == IPMI_CMD_OEM_FABRIC_CONFIG_GET) && ++ (param->val_len))) { ++ memcpy(param_value.val.scalar, rsp->data, ++ param->val_len); ++ param->printer(¶m_value, param->val_len); ++ } ++ } else { ++ lprintf(LOG_ERR, "Command failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ return 0; ++ ++cx_fabric_main_error_out: ++// cx_fabric_usage(); ++ return -1; ++} ++ ++int cx_fabric_main(struct ipmi_intf *intf, int argc, char **argv) ++{ ++ if ((argc > 1) && (!strcmp("config", argv[0]))) { ++ cx_fabric_cmd_parser(intf, cx_fabric_config_arg, argc - 1, ++ &argv[1]); ++ } else { ++ cx_fabric_cmd_parser(intf, cx_fabric_main_arg, argc, &argv[0]); ++ } ++} ++ ++static void cx_data_usage(void) ++{ ++ lprintf(LOG_NOTICE, ++ "\n" ++ "Usage: ipmitool cxoem data <type> <command> [option...]\n" ++ "\n" ++ "Data Commands: \n" ++ "\n" ++ " mem <read/write> <width> <address> [fmt] [data] \n" ++ " cdb <read/write> <length> <cid> [fmt] [data] \n" ++ "where fmt is an optional formatting hint, one of,\n" ++ " 'int' -- decimal integer\n" ++ " 'uint' -- unsigned decimal integer\n" ++ " 'xint' -- a hexadecimal integer\n" ++ " 'ascii' -- an ascii string\n" ++ " 'xstr' -- a byte string expressed in hex (i.e. 01ef23)\n" ++ "\n"); ++} ++ ++static void cx_info_usage(void) ++{ ++ lprintf(LOG_NOTICE, ++ "\n" ++ "Usage: ipmitool cxoem info <Type>\n" ++ "\n" ++ "Type Commands: \n" ++ "\n" ++ " basic \n" " partnum \n" " chassis \n" " card \n" " node \n" "\n"); ++} ++ ++/* Interpret the string pointed to by valrep according to the length contraint ++ and the claimed format. Put the result byte-by-byte into the out array. ++ Use the fmt parameter to decide whether to make integer values ++ little-endian (ints are encoded little-endian). ++*/ ++static int ++asc_to_bin(const char *valrep, int length, int fmt, unsigned char *out) ++{ ++ int i; ++ const char *p; ++ unsigned int intval = 0; ++ memset(out, 0, length); ++ // the string types (ascii and xstr) are easy: they just get stuffed ++ // into the output, byte-for-byte ++ if (fmt == CX_DATA_FMT_ASCII) { ++ for (i = 0; i < length && valrep[i]; i++) ++ out[i] = (unsigned int)valrep[i]; ++ } else if (fmt == CX_DATA_FMT_XSTR) { ++ int vallen = strlen(valrep); ++ if (vallen & 1) { // input can't have an odd number of chars ++ lprintf(LOG_ERR, ++ "<value> must have an even number of hex digits\n"); ++ return CX_DATA_BAD_VALUE; ++ } ++ if (vallen < (2 * length)) { ++ lprintf(LOG_ERR, "<value> must have enough characters " ++ "to encode <length> bytes.\n"); ++ return CX_DATA_BAD_VALUE; ++ } ++ p = valrep; ++ if (strncmp(valrep, "0x", 2) == 0 || ++ strncmp(valrep, "0X", 2) == 0) ++ p += 2; ++ for (i = 0; i < length && *p; i++) { ++ char byterep[3]; ++ int j = 2 * i; ++ byterep[0] = *p++; ++ byterep[1] = *p++; ++ byterep[2] = 0; ++ out[i] = strtoul(byterep, NULL, 16); ++ if (errno) { ++ lprintf(LOG_ERR, ++ "<value> is not a valid hex string\n"); ++ return CX_DATA_BAD_VALUE; ++ } ++ } ++ } ++ // For the integer types we have to get the value, then ++ // pack the out buffer little-endian. Fortunately, this is the ++ // same for memory locations and cdb values, so all we have to ++ // worry about is length, which is guaranteed to be 1 or 4. ++ else { ++ if (length < 1 || length > 4) { ++ lprintf(LOG_ERR, "<width> must be either 1 or 4\n"); ++ return CX_DATA_BAD_LENGTH; ++ } ++ if (fmt == CX_DATA_FMT_INT) { ++ intval = (unsigned int)strtol(valrep, NULL, 10); ++ } else if (fmt == CX_DATA_FMT_UINT) { ++ intval = strtoul(valrep, NULL, 10); ++ } else if (fmt == CX_DATA_FMT_XINT) { ++ intval = strtoul(valrep, NULL, 16); ++ } ++ if (errno) { ++ lprintf(LOG_ERR, ++ "<value> is not a valid integer value.\n"); ++ return CX_DATA_BAD_VALUE; ++ } ++ out[0] = intval & 0xff; ++ if (length == 4) { ++ out[1] = (intval >> 8) & 0xff; ++ out[2] = (intval >> 16) & 0xff; ++ out[3] = (intval >> 24) & 0xff; ++ } ++ } ++ return CX_DATA_OK; ++} ++ ++/* ++ Print a value or a series of values according to the specified format. ++ This function can present one or more ints or bytes. Ints are space- ++ separated. Bytes are not separated. ++*/ ++static int print_value(int length, int format, const unsigned char *value) ++{ ++ int rc = CX_DATA_OK; ++ int datatype = CX_DATA_INT_TYPE; ++ char *prntfmt = "0x%08x"; ++ printf("Value :"); ++ if (length > 0) { ++ switch (format) { ++ case CX_DATA_FMT_INT: ++ datatype = CX_DATA_INT_TYPE; ++ prntfmt = " %d"; ++ break; ++ case CX_DATA_FMT_UINT: ++ datatype = CX_DATA_INT_TYPE; ++ prntfmt = " %u"; ++ break; ++ case CX_DATA_FMT_XINT: ++ datatype = CX_DATA_INT_TYPE; ++ prntfmt = " 0x%08x"; ++ break; ++ case CX_DATA_FMT_ASCII: ++ datatype = CX_DATA_BYTE_TYPE; ++ prntfmt = "%c"; ++ break; ++ case CX_DATA_FMT_XSTR: ++ datatype = CX_DATA_BYTE_TYPE; ++ prntfmt = "%02x"; ++ break; ++ } // switch ++ if (datatype == CX_DATA_INT_TYPE) { // integer ++ int i; ++ if (length == 1) { ++ printf(prntfmt, value[0]); ++ } else { ++ for (i = 0; (4 * i) + 3 < length; i++) { ++ int n = i * 4; ++ unsigned int iv; ++ iv = ((unsigned int)value[n + 3] << 24) ++ + ++ ((unsigned int)value[n + 2] << 16) + ++ ((unsigned int)value[n + 1] << 8) + ++ (unsigned int)value[n]; ++ printf(prntfmt, iv); ++ } ++ } ++ } else { // string data ++ int i; ++ printf(" "); ++ for (i = 0; i < length; i++) { ++ printf(prntfmt, value[i]); ++ } ++ } ++ printf("\n"); ++ } else { ++ rc = CX_DATA_BAD_LENGTH; ++ } ++ return rc; ++} ++ ++/* Execute commands to access the configuration data base ++ Initialize the ipmi message ++ Send the message ++ On a read: ++ print the value returned. ++*/ ++int ++cx_data_cdb(struct ipmi_intf *intf, int access, int length, ++ unsigned int cid, unsigned int fmt, unsigned char *value) ++{ ++ int rc = CXOEM_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[8 + MAX_RETURNABLE_CDB_LEN]; ++ char out[5]; ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, sizeof(msg_data)); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_DATA_ACCESS; ++ msg_data[0] = 2; // 2 = cdb access ++ msg_data[1] = access; // direction, i.e. read/write ++ msg_data[2] = length & 0xff; ++ msg_data[3] = (length >> 8) & 0xff; ++ msg_data[4] = cid & 0xff; ++ msg_data[5] = (cid >> 8) & 0xff; ++ msg_data[6] = (cid >> 16) & 0xff; ++ msg_data[7] = (cid >> 24) & 0xff; ++ if (access == CX_DATA_ACCESS_WRITE) { ++ memcpy((void *)(msg_data + 8), (void *)value, length); ++ req.msg.data_len = length + 8; ++ } else { ++ req.msg.data_len = 8; ++ } ++ req.msg.data = msg_data; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error during cdb data command\n"); ++ return -1; ++ } ++ ++ if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "cxoem data cdb command failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ if ((rsp->ccode == 0) && (access == CX_DATA_ACCESS_READ)) { ++ unsigned int value; ++ unsigned int dlength = 0; ++ unsigned int actual_length = 0; ++ int n = 2; ++ int datatype = 1; ++ const char *prntfmt = " %d"; ++ ++ actual_length = rsp->data[0] & 0xff; ++ actual_length |= (rsp->data[1] << 8) & 0xff; ++ dlength = rsp->data[2] & 0xff; ++ dlength |= (rsp->data[3] << 8) & 0xff; ++ if (dlength > MAX_RETURNABLE_CDB_LEN) { ++ printf("CDB read length too lengthy\n"); ++ return -1; ++ } ++ printf("Data size: %d\n", dlength); ++ printf("CID size : %d\n", actual_length); ++ print_value(dlength, fmt, &rsp->data[4]); ++ } ++ return rc; ++} ++ ++ ++ ++ ++/* Execute commands to access cxoem memory mapped registers ++ Initialize the msg ++ Send the msg ++ On a read: ++ print the value returned. ++ */ ++int ++cx_data_mem(struct ipmi_intf *intf, int access, int width, ++ unsigned int address, int fmt, const char *value) ++{ ++ int rc = CXOEM_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[16]; ++ ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, sizeof(msg_data)); ++ req.msg.netfn = IPMI_NETFN_OEM_SS; ++ req.msg.cmd = IPMI_CMD_OEM_DATA_ACCESS; ++ msg_data[0] = 1; // 1 = memory access ++ msg_data[1] = (access == CX_DATA_ACCESS_READ) ? 1 : 2; ++ msg_data[2] = width; ++ msg_data[3] = address & 0xff; ++ msg_data[4] = (address >> 8) & 0xff; ++ msg_data[5] = (address >> 16) & 0xff; ++ msg_data[6] = (address >> 24) & 0xff; ++ if (access == CX_DATA_ACCESS_WRITE) { ++ msg_data[7] = value[0]; ++ if (width > 1) { ++ msg_data[8] = value[1]; ++ msg_data[9] = value[2]; ++ msg_data[10] = value[3]; ++ } ++ req.msg.data_len = 11; ++ } else { ++ req.msg.data_len = 7; ++ } ++ req.msg.data = msg_data; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, "Error during cxoem data mem command\n"); ++ return -1; ++ } ++ ++ if (rsp->ccode > 0) { ++ lprintf(LOG_ERR, "cxoem data mem command failed: %s", ++ val2str(rsp->ccode, completion_code_vals)); ++ return -1; ++ } ++ ++ if ((rsp->ccode == 0) && (access == CX_DATA_ACCESS_READ)) { ++ print_value(width, fmt, rsp->data); ++ } ++ ++ return rc; ++} ++ ++static int str_to_fmt(const char *fmtstr) ++{ ++ struct _sftbl { ++ const char *fmtstr; ++ unsigned int fmt; ++ }; ++ struct _sftbl sftbl[] = { ++ {"int", CX_DATA_FMT_INT}, ++ {"uint", CX_DATA_FMT_UINT}, ++ {"xint", CX_DATA_FMT_XINT}, ++ {"ascii", CX_DATA_FMT_ASCII}, ++ {"xstr", CX_DATA_FMT_XSTR}, ++ {0, 0} ++ }; ++ int i; ++ for (i = 0; sftbl[i].fmtstr; i++) ++ if (!strcmp(fmtstr, sftbl[i].fmtstr)) ++ return sftbl[i].fmt; ++ lprintf(LOG_ERR, ++ "<fmt> isn't a valid format\n" ++ "It sould be one of 'int', 'uint'," ++ "'xint', 'ascii or 'xstr', or omitted.\n"); ++ return CX_DATA_FMT_DEFAULT; ++} ++ ++/* For the cxoem data read/write mem n command, ++ edit the data length (n) -- we handle only byte and word access for mem ++ extract the address ++ for reads: ++ extract the optional formatting hint ++ for writes: ++ extract the optional formatting hint ++ extract the value to be written ++ access the memory ++ */ ++static int ++cx_data_mem_main(struct ipmi_intf *intf, int argc, char **argv, ++ int access, int length) ++{ ++ int ret = 0; ++ unsigned int addr; ++ int fmt = CX_DATA_FMT_DEFAULT; ++ const char *valptr = argv[4]; ++ ++ if (length < 1 || length > 64) { ++ lprintf(LOG_ERR, "<length> out of range. must be 1-64\n"); ++ return -1; ++ } ++ addr = strtoul(argv[3], (char **)NULL, 16); ++ unsigned char value[4]; ++ if (!errno) { ++ printf("Addr : %08x\n", addr); ++ } else { ++ lprintf(LOG_ERR, "<addr> doesn't look like a valid value\n"); ++ return -1; ++ } ++ ++ if (access == CX_DATA_ACCESS_READ && argc > 4) { ++ fmt = str_to_fmt(argv[4]); ++ if (fmt == CX_DATA_FMT_DEFAULT) { ++ return -1; ++ } ++ } ++ if (access == CX_DATA_ACCESS_WRITE) { ++ if (argc > 5) { ++ fmt = str_to_fmt(argv[4]); ++ valptr = argv[5]; ++ } else if (argc > 4) { ++ fmt = CX_DATA_FMT_XINT; ++ valptr = argv[4]; ++ } else { ++ lprintf(LOG_ERR, "<value> wasn't specified\n"); ++ return -1; ++ } ++ if (fmt != CX_DATA_FMT_INT) ++ fmt = CX_DATA_FMT_XINT; ++ if (asc_to_bin(valptr, length, fmt, value) == CX_DATA_OK) { ++ print_value(length, fmt, value); ++ } else { ++ return -1; ++ } ++ } ++ return cx_data_mem(intf, access, length, addr, fmt, value); ++ ++} ++ ++/* For the cxoem data read/write mem n command, ++ Extract the CID (configuration id) ++ On a read: ++ extract the optional format hint. ++ On a write: ++ extract the optional format hint. ++ extract the data to be written ++ Access the cdb ++ */ ++static int ++cx_data_cdb_main(struct ipmi_intf *intf, int argc, ++ char **argv, int access, int length) ++{ ++ int width = 4; // default to 4-bytes ++ unsigned int addr; ++ int fmt = CX_DATA_FMT_DEFAULT; ++ unsigned char value[MAX_RETURNABLE_CDB_LEN]; ++ unsigned int cid = 0; ++ char *valptr = argv[4]; ++ ++ cid = strtoul(argv[3], (char **)NULL, 16); ++ if (!errno) { ++ printf("Cid : %08x\n", cid); ++ } else { ++ lprintf(LOG_ERR, "<cid> doesn't look like a valid value\n"); ++ return -1; ++ } ++ ++ if (access == CX_DATA_ACCESS_READ && argc > 4) { ++ fmt = str_to_fmt(argv[4]); ++ if (fmt == CX_DATA_FMT_DEFAULT) { ++ return -1; ++ } ++ } ++ if (access == CX_DATA_ACCESS_WRITE) { ++ // at this point, we have either a value or a format and ++ // value left to parse from the cmdline. ++ if (argc > 5) { ++ fmt = str_to_fmt(argv[4]); ++ valptr = argv[5]; ++ } else if (argc > 4) { ++ fmt = CX_DATA_FMT_XSTR; ++ valptr = argv[4]; ++ } else { ++ lprintf(LOG_ERR, "<value> wasn't specified\n"); ++ return -1; ++ } ++ if (asc_to_bin(valptr, length, fmt, value) != CX_DATA_OK) { ++ return -1; ++ } else { ++ print_value(length, fmt, value); ++ } ++ } ++ if (fmt == CX_DATA_FMT_DEFAULT) ++ fmt = CX_DATA_FMT_XSTR; ++ return cx_data_cdb(intf, access, length, cid, fmt, value); ++} ++ ++static int get_access(int argc, char **argv) ++{ ++ int access = CX_DATA_ACCESS_UNKNOWN; ++ if (argc > 1) { ++ if (strncmp(argv[1], "read", 4) == 0) ++ access = CX_DATA_ACCESS_READ; ++ else if (strncmp(argv[1], "write", 4) == 0) ++ access = CX_DATA_ACCESS_WRITE; ++ } ++ return access; ++} ++ ++/* For the cxoem data command, extract the common fields: ++ target (cdb or memory) ++ access (read or write) ++ length of data ++ then call the appropriate handler for the target. ++*/ ++static int cx_data_main(struct ipmi_intf *intf, int argc, char **argv) ++{ ++ int rv = 0; ++ int target = CX_DATA_TARGET_UNKNOWN; ++ int length = 0; ++ int maxwidth = 64; ++ int access; ++ errno = 0; ++ ++ if (argc < 1 || strncmp(argv[0], "help", 4) == 0) { ++ cx_data_usage(); ++ return 0; ++ } ++ if (strncmp(argv[0], "mem", 3) == 0) { ++ target = CX_DATA_TARGET_MEM; ++ } else if (strncmp(argv[0], "cdb", 3) == 0) { ++ target = CX_DATA_TARGET_CDB; ++ maxwidth = MAX_RETURNABLE_CDB_LEN; ++ } else { ++ cx_data_usage(); ++ rv = -1; ++ } ++ access = get_access(argc, argv); ++ if ((access == CX_DATA_ACCESS_READ && argc < 4) || ++ (access == CX_DATA_ACCESS_WRITE && argc < 5) || ++ access == CX_DATA_ACCESS_UNKNOWN) { ++ cx_data_usage(); ++ return -1; ++ } ++ ++ length = strtol(argv[2], (char **)NULL, 10); ++ if (!errno) { ++ if (length < 1 || length > maxwidth) { ++ lprintf(LOG_ERR, "<length> out of range\n"); ++ return -1; ++ } else { ++ printf("Length : %d\n", length); ++ } ++ } else { ++ lprintf(LOG_ERR, "<length> doesn't look like a valid value\n"); ++ return -1; ++ } ++ ++ ++ switch (target) { ++ case CX_DATA_TARGET_MEM: ++ rv = cx_data_mem_main(intf, argc, argv, access, length); ++ break; ++ case CX_DATA_TARGET_CDB: ++ rv = cx_data_cdb_main(intf, argc, argv, access, length); ++ break; ++ default: ++ cx_data_usage(); ++ rv = -1; ++ } ++ ++ return rv; ++} ++ ++#define MAX_MSG_DATA_SIZE 256 ++/** ++ * Generic Execute IPMI command ++ * ++ * @param intf IPMI Interface ++ * ++ * @param net_fn Net Function ++ * @param command Command to be send ++ * @param input_buf Input Buffer that contains the data ++ * @param input_bufsize ++ * Input Buffer Size. Must be less than or equal to 256 ++ * @param output_buf IPMI Response will be stored here. ++ * @param output_bufsize ++ * Buffer size of the output_buffer, and on return it ++ * contains the actual number of bytes of data ++ * @param completion_code ++ * Command completion code ++ * ++ * @return 0 = successful ++ * -1 = failure ++ */ ++int ++cx_send_ipmi_cmd(struct ipmi_intf *intf, ++ uint8_t net_fn, uint8_t command, ++ uint8_t * input_buf, int input_bufsize, ++ uint8_t * output_buf, int *output_bufsize, ++ uint8_t * completion_code) ++{ ++ int rc = CXOEM_SUCCESS; ++ struct ipmi_rs *rsp; ++ struct ipmi_rq req; ++ uint8_t msg_data[MAX_MSG_DATA_SIZE]; ++ ++ memset(&req, 0, sizeof(req)); ++ memset(msg_data, 0, sizeof(msg_data)); ++ if (input_bufsize > MAX_MSG_DATA_SIZE) { ++ lprintf(LOG_ERR, ++ "[cx_send_ipmi_cmd] message length exceeded.\n"); ++ return -1; ++ } ++ req.msg.netfn = net_fn; ++ req.msg.cmd = command; ++ if (input_bufsize) { ++ if (input_buf) { ++ memcpy(msg_data, input_buf, input_bufsize); ++ } else { ++ lprintf(LOG_ERR, ++ "[cx_send_ipmi_cmd] Input buffer is null.\n"); ++ rc = CXOEM_ERROR; ++ } ++ } ++ ++ if (CXOEM_SUCCESS == rc) { ++ req.msg.data = msg_data; ++ req.msg.data_len = input_bufsize; ++ ++ rsp = intf->sendrecv(intf, &req); ++ if (rsp == NULL) { ++ lprintf(LOG_ERR, ++ "[cx_send_ipmi_cmd] sendrecv failed.\n"); ++ rc = CXOEM_ERROR; ++ } else { ++ *completion_code = rsp->ccode; ++ if (rsp->data_len > *output_bufsize) { ++ lprintf(LOG_ERR, ++ "[cx_send_ipmi_cmd] output buffer size is too small: (%d, %d).\n", ++ *output_bufsize, rsp->data_len); ++ rc = CXOEM_ERROR; ++ } else { ++ *output_bufsize = rsp->data_len; ++ if (rsp->data_len) { ++ if (output_buf) { ++ memcpy(output_buf, rsp->data, ++ rsp->data_len); ++ } else { ++ lprintf(LOG_ERR, ++ "[cx_send_ipmi_cmd] output buffer is null.\n"); ++ rc = CXOEM_ERROR; ++ } ++ } ++ } ++ ++ } ++ } ++ ++ return rc; ++} ++ ++/** ++ * Ping the "BMC" to see if this is Calxeda SoC ++ * ++ * @param intf IPMI interface ++ * @param to_print TRUE to print the result ++ * FALSE not to print the result ++ * ++ * @return TRUE if this is Calxeda SoC ++ * FALSE otherwise. ++ */ ++tboolean cx_is_CalxedaSoc(struct ipmi_intf * intf, tboolean to_print) ++{ ++ tboolean is_Calxeda_soc = 0; /* Assuming it's not Calxeda */ ++ int rv = 0; ++ uint8_t rs_data[MAX_MSG_DATA_SIZE] = {0}; ++ int rs_data_size = MAX_MSG_DATA_SIZE; ++ uint8_t completion_code = 0; ++ cx_info_basic_t *basic_rs = (void *)rs_data; ++ ++ rs_data[0] = 0x01; /* Basic Info */ ++ rv = cx_send_ipmi_cmd(intf, IPMI_NETFN_OEM_SS, ++ IPMI_CMD_OEM_GET_DEVICE_INFO, rs_data, 1, rs_data, ++ &rs_data_size, &completion_code); ++ if (rv == 0) { ++ if (completion_code) { ++ printf("command failed with 0x%X completion code\n", ++ completion_code & 0xFF); ++ } else { ++ time_t lt; ++ if (0x96CD == basic_rs->rev1.iana) { ++ is_Calxeda_soc = 1; ++ if (to_print) { ++ printf("Calxeda SoC (0x%6.6X)\n", ++ basic_rs->rev1.iana); ++ if (basic_rs->rev1.parameter_revision == 1) ++ { ++ /* Revision 1 */ ++ printf(" Firmware Version: %s\n", ++ basic_rs->rev1.firmware_version); ++ printf(" SoC Version: v%d.%d.%d\n", ++ basic_rs->rev1.ecme_major_version, ++ basic_rs->rev1.ecme_minor_version, ++ basic_rs->rev1.ecme_revision); ++ printf(" Build Number: %X %s\n", ++ basic_rs->rev1.ecme_build_number, ++ ((basic_rs->rev1. ++ ecme_build_number & 0x0F) == ++ 0x0D) ? "(Dirty)" : ""); ++ lt = basic_rs->rev1.ecme_timestamp; ++ printf(" Timestamp (%d): %s\n", ++ basic_rs->rev1.ecme_timestamp, ++ asctime(localtime(<))); ++ } ++ else if (basic_rs->rev1.parameter_revision == 2) ++ { ++ /* Revision 2 */ ++ printf(" Firmware Version: %s\n", ++ basic_rs->rev2.firmware_version); ++ printf(" SoC Version: %s\n", ++ basic_rs->rev2.ecme_version); ++ lt = basic_rs->rev2.ecme_timestamp; ++ printf(" Timestamp (%d): %s\n", ++ basic_rs->rev2.ecme_timestamp, ++ asctime(localtime(<))); ++ } ++ else ++ { ++ /* Don't know how to read it */ ++ printf(" Unknown parameter revision\n"); ++ } ++ } ++ } else { ++ printf("This is not Calxeda SoC\n"); ++ } ++ } ++ } ++ return is_Calxeda_soc; ++} ++ ++/* For the cxoem info command, extract the common fields: ++ then call the appropriate handler for the target. ++*/ ++static int cx_info_main(struct ipmi_intf *intf, int argc, char **argv) ++{ ++ ++ int rv = -1; // Assuming error ++ uint8_t rs_data[MAX_MSG_DATA_SIZE]; ++ int rs_data_size = MAX_MSG_DATA_SIZE; ++ uint8_t completion_code; ++ int i; ++ ++ if (argc < 1 || strncmp(argv[0], "help", 4) == 0) { ++ cx_info_usage(); ++ return 0; ++ } ++ if (strncmp(argv[0], "basic", 5) == 0) { ++ if (cx_is_CalxedaSoc(intf, TRUE)) { ++ rv = 0; ++ } ++ } else if (strncmp(argv[0], "partnum", 7) == 0) { ++ if (cx_is_CalxedaSoc(intf, FALSE)) { ++ } ++ } else if (strncmp(argv[0], "chassis", 7) == 0) { ++ if (cx_is_CalxedaSoc(intf, FALSE)) { ++ } ++ } else if (strncmp(argv[0], "card", 4) == 0) { ++ struct oem_device_info_card_s { ++ uint16_t card_id; ++ uint16_t card_rev; ++ } __attribute__ ((packed)); ++ typedef struct oem_device_info_card_s oem_device_info_card_t; ++ char board_type[32]; ++ ++ oem_device_info_card_t *card_rs; ++ card_rs = (void *) rs_data; ++ ++ if (cx_is_CalxedaSoc(intf, FALSE)) { ++ rs_data[0] = 0x06; /* Card Info */ ++ rv = cx_send_ipmi_cmd(intf, IPMI_NETFN_OEM_SS, ++ IPMI_CMD_OEM_GET_DEVICE_INFO, ++ rs_data, 1, rs_data, ++ &rs_data_size, &completion_code); ++ if (rv == 0) { ++ if (completion_code) { ++ printf ++ ("command failed with 0x%X completion code\n", ++ completion_code & 0xFF); ++ rv = -1; ++ } else { ++ switch (card_rs->card_id) { ++ /* Case 0 isn't really energycard, but ++ old versions will return that, so ++ we'll just go with it. */ ++ case 0: ++ case 1: ++ strcpy(board_type, "EnergyCard"); ++ break; ++ case 7: ++ strcpy(board_type, "Slingshot"); ++ break; ++ default: ++ sprintf(board_type, "Unknown (%X)", card_rs->card_id); ++ break; ++ } ++ printf(" Board Type: %s\n", board_type); ++ printf(" Board Revision: %d\n", card_rs->card_rev); ++ } ++ } ++ ++ } ++ } else if (strncmp(argv[0], "node", 4) == 0) { ++ struct oem_device_info_node_s { ++ uint8_t oui[3]; ++ uint16_t fabric_node_id; ++ uint8_t slot_number; ++ uint8_t local_node_id; ++ } __attribute__ ((packed)); ++ typedef struct oem_device_info_node_s oem_device_info_node_t; ++ ++ oem_device_info_node_t *node_rs; ++ node_rs = (void *)rs_data; ++ ++ if (cx_is_CalxedaSoc(intf, FALSE)) { ++ rs_data[0] = 0x04; /* Node Info */ ++ rv = cx_send_ipmi_cmd(intf, IPMI_NETFN_OEM_SS, ++ IPMI_CMD_OEM_GET_DEVICE_INFO, ++ rs_data, 1, rs_data, ++ &rs_data_size, &completion_code); ++ if (rv == 0) { ++ if (completion_code) { ++ printf("command failed with 0x%X completion code\n", ++ completion_code & 0xFF); ++ rv = -1; ++ } else { ++ printf("OUI = 0x%X%X%X\n", ++ node_rs->oui[2], node_rs->oui[1], ++ node_rs->oui[0]); ++ printf("Fabric Node ID = %d\n", ++ node_rs->fabric_node_id); ++ printf("Slot Number = %d\n", ++ node_rs->slot_number); ++ printf("Local Node ID = %d\n", ++ node_rs->local_node_id); ++ } ++ } ++ } ++ } else if (strncmp(argv[0], "wafer", 4) == 0) { ++ struct oem_device_info_wafer_s { ++ uint8_t wafer_info[16]; ++ } __attribute__ ((packed)); ++ typedef struct oem_device_info_wafer_s oem_device_info_wafer_t; ++ ++ oem_device_info_wafer_t *wafer_rs; ++ wafer_rs = (void *)rs_data; ++ ++ if (cx_is_CalxedaSoc(intf, FALSE)) { ++ rs_data[0] = 0x05; /* Wafer Info */ ++ rv = cx_send_ipmi_cmd(intf, IPMI_NETFN_OEM_SS, ++ IPMI_CMD_OEM_GET_DEVICE_INFO, ++ rs_data, 1, rs_data, ++ &rs_data_size, &completion_code); ++ if (rv == 0) { ++ if (completion_code) { ++ printf ++ ("command failed with 0x%X completion code\n", ++ completion_code & 0xFF); ++ rv = -1; ++ } else { ++ char wafer_string[16]; ++ printf("Wafer Info\n"); ++ printf(" Raw : "); ++ for (i = 0; ++ i < sizeof(wafer_rs->wafer_info); ++ i++) { ++ printf("%2.2X ", ++ wafer_rs-> ++ wafer_info[i] & 0xFF); ++ } ++ printf("\n"); ++ printf(" X-Coord : %d\n", ++ wafer_rs->wafer_info[0] & 0xFF); ++ printf(" Y-Coord : %d\n", ++ wafer_rs->wafer_info[1] & 0xFF); ++ printf(" Number : %d\n", ++ wafer_rs->wafer_info[2] & 0xFF); ++ memset(wafer_string, 0, 16); ++ /* ++ for (i = 0; i < 8; i++) { ++ wafer_string[i] = wafer_rs->wafer_info[10-i]; ++ } ++ */ ++ memcpy(wafer_string, ++ &(wafer_rs->wafer_info[3]), 8); ++ printf(" Lot Number: %s\n", ++ wafer_string); ++ } ++ } ++ } ++ } else { ++ cx_info_usage(); ++ } ++ return rv; ++} ++ ++static const char *tps_to_string(unsigned char state) ++{ ++ int num_elements; ++ ++ num_elements = sizeof(tps_table)/sizeof(*tps_table); ++ if (state < num_elements) { ++ return tps_table[state]; ++ } ++ return ""; ++} ++ ++static int cx_feature_main(struct ipmi_intf *intf, int argc, char **argv) ++{ ++ uint8_t rs_data[MAX_MSG_DATA_SIZE]; ++ int rs_data_size = MAX_MSG_DATA_SIZE; ++ int rq_data_size = 0; ++ uint8_t *rq_data; ++ uint8_t completion_code; ++ int get_op = 0; ++ const struct valstr oem_features[] = { ++ {0x01, "selaging"}, ++ {0x02, "hwwd"}, ++ {0x03, "tps"}, ++ {0x04, "mansen"}, ++ {0x00, "Invalid"}, // make sure this is the last entry ++ }; ++ int rv = 0; ++ int i; ++ int feature_index = 0; ++ ++ if (argc < 2 || strncmp(argv[0], "help", 4) == 0) { ++ cx_feature_usage(); ++ return 0; ++ } ++ ++ rq_data = rs_data; ++ if (strncmp(argv[0], "status", 6) == 0) { ++ rq_data_size = 2; ++ rq_data[0] = 2; // Get Operation ++ get_op = 1; ++ } else if (strncmp(argv[0], "enable", 6) == 0) { ++ rq_data[2] = 1; // Enable ++ rq_data_size = 3; ++ rq_data[0] = 1; // Set Operation ++ } else if (strncmp(argv[0], "disable", 7) == 0) { ++ rq_data[2] = 0; // Disable ++ rq_data_size = 3; ++ rq_data[0] = 1; // Set Operation ++ } else { ++ rv = -1; ++ } ++ ++ if (0 == rv) { ++ i = 0; ++ rv = -1; // Assuming the feature specified cannot be found ++ while (oem_features[i].val) { ++ if (strncmp ++ (argv[1], oem_features[i].str, ++ strlen(oem_features[i].str)) == 0) { ++ rq_data[1] = oem_features[i].val; ++ rv = 0; ++ feature_index = i; ++ break; ++ } ++ i++; ++ } ++ } ++ ++ ++ if (0 == rv) { ++ ++ rv = cx_send_ipmi_cmd(intf, IPMI_NETFN_OEM_SS, ++ IPMI_CMD_OEM_FEATURES_ENABLE, rq_data, ++ rq_data_size, rs_data, &rs_data_size, ++ &completion_code); ++ if (0 == rv) { ++ if (get_op) { ++ if (2 == feature_index) { ++ printf(" %s state is %d %s\n", oem_features[feature_index].str, ++ rs_data[0], tps_to_string(rs_data[0])); ++ } else { ++ printf(" %s is %s\n", ++ oem_features[feature_index].str, ++ rs_data[0] ? "enabled" : "disabled"); ++ } ++ } ++ } ++ } ++ ++ if (rv) { ++ cx_feature_usage(); ++ } ++ ++ return rv; ++} ++ ++int ipmi_cxoem_main(struct ipmi_intf *intf, int argc, char **argv) ++{ ++ int rc = 0; ++ ++ if (argc == 0 || strncmp(argv[0], "help", 4) == 0) { ++ ipmi_cxoem_usage(); ++ return 0; ++ } else if (!strncmp(argv[0], "fw", 2)) { ++ rc = cx_fw_main(intf, argc - 1, &argv[1]); ++ } else if (!strncmp(argv[0], "fabric", 6)) { ++ rc = cx_fabric_main(intf, argc - 1, &argv[1]); ++ } else if (!strncmp(argv[0], "data", 4)) { ++ rc = cx_data_main(intf, argc - 1, &argv[1]); ++ } else if (!strncmp(argv[0], "info", 4)) { ++ rc = cx_info_main(intf, argc - 1, &argv[1]); ++ } else if (!strncmp(argv[0], "feature", 7)) { ++ rc = cx_feature_main(intf, argc - 1, &argv[1]); ++ } ++ ++ return rc; ++} +diff --git a/lib/ipmi_lanp.c b/lib/ipmi_lanp.c +index 060cbf7..98ddbb8 100644 +--- a/lib/ipmi_lanp.c ++++ b/lib/ipmi_lanp.c +@@ -130,6 +130,7 @@ get_lan_param_select(struct ipmi_intf * intf, uint8_t chan, int param, int selec + break; + } + } ++ /* XXX: LEDVA iterate cxoem options too (rejected patch) */ + + if (p == NULL) { + lprintf(LOG_INFO, "Get LAN Parameter failed: Unknown parameter."); +@@ -747,6 +748,99 @@ ipmi_lan_print(struct ipmi_intf * intf, uint8_t chan) + 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_TFTP_SERVER_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_NTP_SERVER_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_TFTP_UDP_PORT); ++ if (p == NULL) ++ return -1; ++ if (p->data != NULL) { ++ int *port; ++ port = (int *)&p->data[0]; ++ printf("%-24s: %d\n", p->desc, *port); ++ } ++ ++ p = get_lan_param(intf, chan, IPMI_LANP_NTP_UDP_PORT); ++ if (p == NULL) ++ return -1; ++ if (p->data != NULL) { ++ int *port; ++ port = (int *)&p->data[0]; ++ printf("%-24s: %d\n", p->desc, *port); ++ } ++ ++ p = get_lan_param(intf, chan, IPMI_LANP_OEM_MAC0); ++ 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_OEM_MAC1); ++ 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_OEM_MAC2); ++ 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_OEM_OUID); ++ if (p == NULL) ++ return -1; ++ if (p->data != NULL) ++ printf("%-24s: %02x:%02x:%02x\n", p->desc, ++ p->data[0], p->data[1], p->data[2]); ++ ++ p = get_lan_param(intf, chan, IPMI_LANP_SC_OUID); ++ if (p == NULL) ++ return -1; ++ if (p->data != NULL) ++ printf("%-24s: %02x:%02x:%02x\n", p->desc, ++ p->data[0], p->data[1], p->data[2]); ++ ++ p = get_lan_param(intf, chan, IPMI_LANP_SC_MODE); ++ if (p == NULL) ++ return -1; ++ if (p->data != NULL) { ++ printf("%-24s: ", p->desc); ++ p->data[0] &= 0xf; ++ switch (p->data[0]) { ++ case 0: ++ printf("Zero\n"); ++ break; ++ case 1: ++ printf("One\n"); ++ break; ++ default: ++ printf("Other\n"); ++ break; ++ } ++ } ++ ++ p = get_lan_param(intf, chan, IPMI_LANP_SC_FID); ++ if (p == NULL) ++ return -1; ++ if (p->data != NULL) { ++ printf("%-24s: %02X\n", p->desc, p->data[0]); ++ } ++ + 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]; +@@ -1175,6 +1269,21 @@ get_cmdline_macaddr(char * arg, uint8_t * buf) + + + static int ++get_cmdline_ouiaddr(char * arg, uint8_t * buf) ++{ ++ uint32_t m1, m2, m3; ++ if (sscanf(arg, "%02x:%02x:%02x", ++ &m1, &m2, &m3) != 3) { ++ lprintf(LOG_ERR, "Invalid OUI address: %s", arg); ++ return -1; ++ } ++ buf[0] = (uint8_t)m1; ++ buf[1] = (uint8_t)m2; ++ buf[2] = (uint8_t)m3; ++ return 0; ++} ++ ++static int + get_cmdline_cipher_suite_priv_data(char * arg, uint8_t * buf) + { + int i, ret = 0; +@@ -1251,6 +1360,19 @@ get_cmdline_cipher_suite_priv_data(char * arg, uint8_t * buf) + return ret; + } + ++static int ++get_cmdline_int(char * arg, uint8_t * buf) ++{ ++ uint32_t port; ++ if (sscanf(arg, "%d", &port) != 1) { ++ lprintf(LOG_ERR, "Invalid port address: %s", arg); ++ return -1; ++ } ++ buf[1] = (port & 0xff00) >> 8; ++ buf[0] = (port & 0xff); ++ return 0; ++} ++ + + static int + get_cmdline_ipaddr(char * arg, uint8_t * buf) +@@ -1278,6 +1400,10 @@ static void ipmi_lan_set_usage(void) + 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, " tftp ipaddr <x.x.x.x> Set tftp server IP address"); ++ lprintf(LOG_NOTICE, " ntp ipaddr <x.x.x.x> Set ntp server IP address"); ++ lprintf(LOG_NOTICE, " tftp port <num> Set tftp server UDP port num "); ++ lprintf(LOG_NOTICE, " ntp port <num> Set ntp server UDP port num "); + 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"); +@@ -1743,6 +1869,158 @@ ipmi_lan_set(struct ipmi_intf * intf, int argc, char ** argv) + rc = set_lan_param(intf, chan, IPMI_LANP_RMCP_PRIV_LEVELS, data, 9); + } + } ++ else if (strncmp(argv[1], "tftp", 4) == 0) { ++ if (argc < 4 || (strncmp(argv[2], "help", 4) == 0)) { ++ lprintf(LOG_NOTICE, "LAN set tftp Commands: ipaddr, port"); ++ } ++ else if ((strncmp(argv[2], "ipaddr", 5) == 0) && ++ (get_cmdline_ipaddr(argv[3], data) == 0)) { ++ printf("Setting tftp ip %s to %d.%d.%d.%d\n", ++ ipmi_lan_params[28].desc, ++ data[0], data[1], data[2], data[3]); ++ rc = set_lan_param(intf, chan, IPMI_LANP_TFTP_SERVER_IP, data, 4); ++ } ++ else if ((strncmp(argv[2], "port", 4) == 0) && ++ (get_cmdline_int(argv[3], data) == 0)) { ++ printf("Setting tftp port %s to %02x%02x\n", ++ ipmi_lan_params[29].desc, ++ data[1], data[0]); ++ rc = set_lan_param(intf, chan, IPMI_LANP_TFTP_UDP_PORT, data, 2); ++ } ++ else { ++ ipmi_lan_set_usage(); ++ return -1; ++ } ++ } ++ else if (strncmp(argv[1], "ntp", 3) == 0) { ++ if (argc < 4 || (strncmp(argv[2], "help", 4) == 0)) { ++ lprintf(LOG_NOTICE, "LAN set ntp Commands: ipaddr, port"); ++ } ++ else if ((strncmp(argv[2], "ipaddr", 5) == 0) && ++ (get_cmdline_ipaddr(argv[3], data) == 0)) { ++ printf("Setting ntp ip %s to %d.%d.%d.%d\n", ++ ipmi_lan_params[30].desc, ++ data[0], data[1], data[2], data[3]); ++ rc = set_lan_param(intf, chan, IPMI_LANP_NTP_SERVER_IP, data, 4); ++ } ++ else if ((strncmp(argv[2], "port", 4) == 0) && ++ (get_cmdline_int(argv[3], data) == 0)) { ++ printf("Setting ntp port %s to %02x%02x\n", ++ ipmi_lan_params[31].desc, ++ data[1], data[0]); ++ rc = set_lan_param(intf, chan, IPMI_LANP_NTP_UDP_PORT, data, 2); ++ } ++ else { ++ ipmi_lan_set_usage(); ++ return -1; ++ } ++ } ++ else if (strncmp(argv[1], "oem_mac0", 8) == 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_OEM_MAC0].desc, ++ data[0], data[1], data[2], data[3], data[4], data[5]); ++ rc = set_lan_param(intf, chan, IPMI_LANP_OEM_MAC0, data, 6); ++ } ++ } ++ else if (strncmp(argv[1], "oem_mac1", 8) == 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_OEM_MAC1].desc, ++ data[0], data[1], data[2], data[3], data[4], data[5]); ++ rc = set_lan_param(intf, chan, IPMI_LANP_OEM_MAC1, data, 6); ++ } ++ } ++ else if (strncmp(argv[1], "oem_mac2", 8) == 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_OEM_MAC2].desc, ++ data[0], data[1], data[2], data[3], data[4], data[5]); ++ rc = set_lan_param(intf, chan, IPMI_LANP_OEM_MAC2, data, 6); ++ } ++ } ++ else if (strncmp(argv[1], "oem_ouid", 8) == 0) { ++ if(argc != 3) ++ { ++ ipmi_lan_set_usage(); ++ return -1; ++ } ++ rc = get_cmdline_ouiaddr(argv[2], data); ++ if (rc == 0) { ++ printf("Setting LAN %s to %02x:%02x:%02x\n", ++ ipmi_lan_params[IPMI_LANP_OEM_OUID].desc, ++ data[0], data[1], data[2]); ++ rc = set_lan_param(intf, chan, IPMI_LANP_OEM_OUID, data, 3); ++ } ++ } ++ else if (strncmp(argv[1], "sc_ouid", 7) == 0) { ++ if(argc != 3) ++ { ++ ipmi_lan_set_usage(); ++ return -1; ++ } ++ rc = get_cmdline_ouiaddr(argv[2], data); ++ if (rc == 0) { ++ printf("Setting LAN %s to %02x:%02x:%02x\n", ++ ipmi_lan_params[IPMI_LANP_SC_OUID].desc, ++ data[0], data[1], data[2]); ++ rc = set_lan_param(intf, chan, IPMI_LANP_SC_OUID, data, 3); ++ } ++ } ++ else if (strncmp(argv[1], "sc_mode", 7) == 0) { ++ if (argc < 3 || (strncmp(argv[2], "help", 4) == 0)) { ++ lprintf(LOG_NOTICE, ++ "lan set <channel> sc_mode <mode>\n" ++ " off = zero\n" ++ " on = one\n"); ++ return 0; ++ } ++ else if (strncmp(argv[2], "off", 3) == 0) ++ data[0] = 0; ++ else if (strncmp(argv[2], "on", 2) == 0) ++ data[0] = 1; ++ else { ++ lprintf(LOG_NOTICE, ++ "lan set <channel> sc_mode <mode>\n" ++ " off = zero\n" ++ " on = one\n"); ++ return -1; ++ } ++ printf("Setting LAN %s to %02x\n", ++ ipmi_lan_params[IPMI_LANP_SC_OUID].desc, ++ data[0]); ++ rc = set_lan_param(intf, chan, IPMI_LANP_SC_MODE, data, 1); ++ } ++ else if (strncasecmp(argv[1], "sc_fid", 6) == 0) { ++ if (argc < 3 || (strncmp(argv[2], "help", 4) == 0)) { ++ lprintf(LOG_NOTICE, ++ "lan set <channel> sc_fid <fid>\n"); ++ return 0; ++ } ++ data[0] = (uint8_t)strtol(argv[2], NULL, 0); ++ printf("Setting LAN %s to %02x\n", ++ ipmi_lan_params[IPMI_LANP_SC_OUID].desc, ++ data[0]); ++ rc = set_lan_param(intf, chan, IPMI_LANP_SC_FID, data, 1); ++ } + else { + ipmi_lan_set_usage(); + return (-1); +@@ -1872,6 +2150,13 @@ ipmi_lan_alert_set_usage(void) + 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, " oem_mac0 <x:x:x:x:x:x> Set OEM MAC address"); ++ lprintf(LOG_NOTICE, " oem_mac1 <x:x:x:x:x:x> Set OEM MAC address"); ++ lprintf(LOG_NOTICE, " oem_mac2 <x:x:x:x:x:x> Set OEM MAC address"); ++ lprintf(LOG_NOTICE, " oem_ouid <x:x:x> Set OEM OUID address"); ++ lprintf(LOG_NOTICE, " sc_ouid <x:x:x> Set Supercluster OUID address"); ++ lprintf(LOG_NOTICE, " sc_mode <on|off> Set Supercluster mode"); ++ lprintf(LOG_NOTICE, " sc_fid <fid> Set Supercluster FID"); + lprintf(LOG_NOTICE, ""); + } + +diff --git a/lib/ipmi_strings.c b/lib/ipmi_strings.c +index 277b82f..57e3609 100644 +--- a/lib/ipmi_strings.c ++++ b/lib/ipmi_strings.c +@@ -157,6 +157,7 @@ const struct valstr ipmi_netfn_vals[] = { + { IPMI_NETFN_FIRMWARE, "Firmware" }, + { IPMI_NETFN_STORAGE, "Storage" }, + { IPMI_NETFN_TRANSPORT, "Transport" }, ++ { IPMI_NETFN_CX_OEM, "cx_oem" }, + { 0xff, NULL }, + }; + +diff --git a/src/ipmitool.c b/src/ipmitool.c +index 6230e5c..51a7b67 100644 +--- a/src/ipmitool.c ++++ b/src/ipmitool.c +@@ -65,6 +65,7 @@ + #include <ipmitool/ipmi_ekanalyzer.h> + #include <ipmitool/ipmi_ime.h> + #include <ipmitool/ipmi_dcmi.h> ++#include <ipmitool/ipmi_cxoem.h> + + #ifdef HAVE_CONFIG_H + # include <config.h> +@@ -105,6 +106,7 @@ struct ipmi_cmd ipmitool_cmd_list[] = { + { ipmi_session_main, "session", "Print session information" }, + { ipmi_dcmi_main, "dcmi", "Data Center Management Interface"}, + { ipmi_sunoem_main, "sunoem", "OEM Commands for Sun servers" }, ++ { ipmi_cxoem_main, "cxoem", "OEM Commands for Calxeda servers" }, + { ipmi_kontronoem_main, "kontronoem", "OEM Commands for Kontron devices"}, + { ipmi_picmg_main, "picmg", "Run a PICMG/ATCA extended cmd"}, + { ipmi_fwum_main, "fwum", "Update IPMC using Kontron OEM Firmware Update Manager" }, +diff --git a/src/plugins/lan/lan.c b/src/plugins/lan/lan.c +index e088479..f35ee6c 100644 +--- a/src/plugins/lan/lan.c ++++ b/src/plugins/lan/lan.c +@@ -253,6 +253,8 @@ ipmi_lan_recv_packet(struct ipmi_intf * intf) + if (ret < 0 || FD_ISSET(intf->fd, &err_set) || !FD_ISSET(intf->fd, &read_set)) + return NULL; + ++ memset(&rsp, 0, sizeof(rsp)); ++ + /* the first read may return ECONNREFUSED because the rmcp ping + * packet--sent to UDP port 623--will be processed by both the + * BMC and the OS. diff --git a/SOURCES/exchange-bmc-os-info b/SOURCES/exchange-bmc-os-info new file mode 100644 index 0000000..c23b507 --- /dev/null +++ b/SOURCES/exchange-bmc-os-info @@ -0,0 +1,326 @@ +#!/bin/sh +############################################################################# +# +# exchange-bmc-os-info: Set OS and BMC (Baseboard Management Controller) +# parameters during system startup. +# +# version: 0.72 +# +# Authors: Charles Rose <charles_rose@dell.com> +# Jordan Hargrave <jordan_hargrave@dell.com> +# +# Description: Script to set OS information in the BMC; fetch BMC IP/URL +# and set in the OS for use by other scripts/user. +# +# BMC IP and URL are made available in /var/run/bmc-info +# +# Example to launch BMC web-interface: +# # . /var/run/bmc-info +# # xdg-open $BMC_URL +# +# See here for details: +# https://fedoraproject.org/wiki/Features/AgentFreeManagement +# +# OEM Specific: OEM specific ipmi commands go in: +# 'oem_set_os_version' and 'oem_get_bmc_url' +############################################################################# +# +# chkconfig: 345 99 00 +# description: Set OS name, hostname in BMC; make BMC IP/URL available in OS +# processname: exchange-bmc-os-info +# config: /etc/sysconfig/exchange-bmc-os-info +# +### BEGIN INIT INFO +# Provides: exchange-bmc-os-info +# Required-Start: ipmi +# Default-Start: 3 4 5 +# Default-Stop: 0 1 2 6 + + +############################################################################# +# GLOBALS +############################################################################# +CONFIGFILE=/etc/sysconfig/exchange-bmc-os-info +IPMI_TOOL=/usr/bin/ipmitool +BMC_INFO=/var/run/bmc-info + +# BMC Manufacturer ID used in 'oem_set_os_version' and 'oem_get_bmc_url' +DELL="674" +#OTHER_OEM="123" + +# Defaults for ${CONFIGFILE} +SET_OS_INFO="yes" +RESET_OS_INFO="no" +SET_BMC_INFO="yes" + +# getsysinfo and setsysinfo commands +IPMI_SET_SYSINFO="${IPMI_TOOL} mc setsysinfo" +IPMI_GET_SYSINFO="${IPMI_TOOL} mc getsysinfo" +############################################################################# +SCRIPT_NAME=$(basename $0) + +# source config +[ -r ${CONFIGFILE} ] && . ${CONFIGFILE} + +RETVAL=0 + +if [ -f /bin/gettext.sh ]; then + GETTEXT=1 + . /bin/gettext.sh + OUTPUT="eval_gettext" +else + GETTEXT=0 + OUTPUT="echo" +fi + +############################################################################# +# Get Vendor ID of BMC for use in 'oem_set_os_version' and 'oem_get_bmc_url' +# +get_bmc_vendor_id() +{ + BMC_VENDOR=$(${IPMI_TOOL} mc info 2>/dev/null | \ + sed -n "s#^Manufacturer ID.*: ##p") + [ -z "${BMC_VENDOR}" ] && RETVAL=4 +} + +# set/getsysinfo support was added to ipmitool post v1.8.12 via this patch +# http://sourceforge.net/mailarchive/message.php?msg_id=29647222 +check_ipmitool() +{ + if [ -x ${IPMI_TOOL} ]; then + [ ! ${IPMI_GET_SYSINFO} >/dev/null 2>&1 ] && \ + RETVAL=3 + else + RETVAL=2 + fi +} + +bmc_exists() +{ + check_ipmitool + [ $RETVAL -eq 0 ] && get_bmc_vendor_id + return $RETVAL +} +############################################################################# + +get_os_info() +{ + OS_HOSTNAME=$(hostname) + KERNEL_VERSION=$(uname -r -m) + + if [ -e /etc/lsb-release ] ; then + . /etc/lsb-release + NAME=${DISTRIB_ID} + VERSION="${DISTRIB_RELEASE} ${DISTRIB_CODENAME}" + fi + + # we prefer systemd's /etc/os-release over other sources + [ -e /etc/os-release ] && . /etc/os-release + + OS_NAME=${NAME} + OS_VERSION="${VERSION} kernel ${KERNEL_VERSION}" +} + +oem_set_os_version() +{ + # OS Version setting is not standard yet + # we need per vendor oem commands + case "${BMC_VENDOR}" in + $DELL) ${IPMI_SET_SYSINFO} delloem_os_version \ + "${OS_VERSION}" > /dev/null 2>&1 + return $? + ;; +# Add OEM specific commands. +# Example: +# $OTHER_OEM) ${IPMI_SET_SYSINFO} otheroem_os_version \ +# "${OS_VERSION}" > /dev/null 2>&1 +# return $? +# ;; + *) return 0 + ;; + esac +} + +set_os_info() +{ + # Set and reset OS info in the BMC + if [ "$1" = "reset" ]; then + OS_NAME="" + OS_HOSTNAME="" + OS_VERSION="" + fi + + ${IPMI_SET_SYSINFO} os_name "${OS_NAME}" >/dev/null 2>&1 \ + || RETVAL=6 + ${IPMI_SET_SYSINFO} primary_os_name "${OS_NAME}" >/dev/null 2>&1 \ + || RETVAL=6 + ${IPMI_SET_SYSINFO} system_name "${OS_HOSTNAME}" >/dev/null 2>&1 \ + || RETVAL=6 + oem_set_os_version || RETVAL=6 +} + +############################################################################# +valid_url() +{ + url="(https?|http)://[a-z0-9-]+(\.[a-z0-9-]+)+([/?].*)?" + printf -- "%s" "${TMP_URL}"| grep -Eq "^${url}" + return $? +} + +oem_get_bmc_url() +{ + # BMC URL is not standard yet + # we need per vendor oem commands + case "$BMC_VENDOR" in + $DELL) TMP_URL=$(${IPMI_GET_SYSINFO} delloem_url 2> /dev/null) + ;; +# Add OEM specific commands +# Example: +# $OTHER_OEM) +# TMP_URL=$(${IPMI_GET_SYSINFO} otheroem_url 2> /dev/null) +# ;; + *) TMP_URL="" ;; + esac + + valid_url && BMC_URL=${TMP_URL} || BMC_URL="" +} + +valid_ip() +{ + #Thanks to mkyong.com + octet="([01]?[[:digit:]][[:digit:]]?|2[0-4][[:digit:]]|25[0-5])" + + printf -- "%s" "${TMP_IPv4}"| grep -Eq "^${octet}\\.${octet}\\.${octet}\\.${octet}$" + return $? +} + +get_bmc_ip() +{ + #Thanks to http://ingvar.blog.redpill-linpro.com + for CHANNEL in `seq 1 14` + do + [ $(${IPMI_TOOL} lan print ${CHANNEL} 2>/dev/null \ + | grep -q "^Set") ] || break + done + + # Get BMC_IPv4 and BMC_URL from BMC + TMP_IPv4=$(${IPMI_TOOL} lan print ${CHANNEL} 2>/dev/null \ + | sed -n "s#^IP Address .*: ##p") + + valid_ip && BMC_IPv4=${TMP_IPv4} || BMC_IPv4="" +} + +get_bmc_info() +{ + get_bmc_ip + if [ -z "${BMC_IPv4}" ] || [ "${BMC_IPv4}" = "0.0.0.0" ]; then + BMC_IPv4="" + RETVAL=5 + else + # URL makes sense only if there is an IP + oem_get_bmc_url + fi +} + +set_bmc_info() +{ + if [ ! $(touch "${BMC_INFO}" && chmod 600 "${BMC_INFO}") ]; then + printf "BMC_IPv4=%s\n" "${BMC_IPv4}" > "${BMC_INFO}" + [ -n "${BMC_URL}" ] && \ + printf "BMC_URL=%s\n" "${BMC_URL}" >> "${BMC_INFO}" + else + RETVAL=5 + fi +} + +unset_bmc_info() +{ + [ -f ${BMC_INFO} ] && rm -f ${BMC_INFO} > /dev/null 2>&1 +} + +############################################################################# +start() +{ + if bmc_exists; then + [ "${SET_OS_INFO}" = "yes" ] && \ + get_os_info && set_os_info + + if [ "${SET_BMC_INFO}" = "yes" ]; then + get_bmc_info + if [ ${RETVAL} -eq 0 ]; then + set_bmc_info + fi + fi + fi +} + +############################################################################# +stop() +{ + if bmc_exists; then + # reset OS info while system reboots + # aids with debugging OS boot-up issues + if [ "${RESET_OS_INFO}" = "yes" ]; then + set_os_info reset + fi + unset_bmc_info + fi +} + +############################################################################# +restart() +{ + stop + [ $RETVAL -eq 0 ] && start +} + +############################################################################# +status() +{ + [ -r ${BMC_INFO} ] && \ + grep -q "BMC_IPv4" "${BMC_INFO}" >/dev/null 1>&2 && \ + BMC_STATUS="ok" || BMC_STATUS="inactive" + ${OUTPUT} "${SCRIPT_NAME}: ${BMC_STATUS}" 1>&2 + [ ${GETTEXT} -eq 1 ] && echo +} + +############################################################################# +usage() +{ + ${OUTPUT} "Usage: ${SCRIPT_NAME} {start|stop|restart|status}" 1>&2 + [ ${GETTEXT} -eq 1 ] && echo + RETVAL=1 +} + +############################################################################# +# MAIN +############################################################################# +case "$1" in + start) start ;; + stop) stop ;; + restart) restart ;; + status) status ;; + *) usage ;; +esac + +case "$RETVAL" in + 0|1) ;; + 2) ${OUTPUT} "${SCRIPT_NAME}: ipmitool(1) not found." 1>&2 ;; + 3) ${OUTPUT} "${SCRIPT_NAME}: this version of ipmitool does not support getsysinfo." 1>&2 ;; + 4) ${OUTPUT} "${SCRIPT_NAME}: failed to communicate with BMC." 1>&2 ;; + 5) ${OUTPUT} "${SCRIPT_NAME}: failed to set OS information in BMC." 1>&2 ;; + 6) ${OUTPUT} "${SCRIPT_NAME}: failed to get BMC information." 1>&2 ;; + *) ${OUTPUT} "${SCRIPT_NAME}: unexpected error." 1>&2 ;; +esac + +if [ ${RETVAL} -gt 1 ]; then + ${OUTPUT} " Return code: ${RETVAL}" 1>&2 + [ ${GETTEXT} -eq 1 ] && echo +fi + + +exit ${RETVAL} + +############################################################################# +# end of file +############################################################################# diff --git a/SOURCES/exchange-bmc-os-info.service b/SOURCES/exchange-bmc-os-info.service new file mode 100644 index 0000000..100493b --- /dev/null +++ b/SOURCES/exchange-bmc-os-info.service @@ -0,0 +1,13 @@ +[Unit] +Description=Exchange Information between BMC and OS +After=ipmi.service network.target +Requires=ipmi.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/libexec/exchange-bmc-os-info start +ExecStop=/usr/libexec/exchange-bmc-os-info stop + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/exchange-bmc-os-info.sysconf b/SOURCES/exchange-bmc-os-info.sysconf new file mode 100644 index 0000000..2f0e675 --- /dev/null +++ b/SOURCES/exchange-bmc-os-info.sysconf @@ -0,0 +1,26 @@ +# exchange-bmc-os-info +# +# Config file to control Exchange of information between +# the OS and Service Processor/Baseboard Management Controller (BMC) +# +# See here for details +# https://fedoraproject.org/wiki/Features/AgentFreeManagement + +### Set OS Info in BMC/Service Processor ### +# Name: SET_OS_INFO +# Description: Set OS Name, Version and Hostname in the Service Processor (BMC) +# Default: yes +SET_OS_INFO="yes" + +### Reset OS Info in BMC/Service Processor ### +# Name: RESET_OS_INFO +# Description: Reset OS Name, Version and Hostname in the Service Processor (BMC). +# Useful when the OS Name/Hostname should be empty on reboot +# Default: no +RESET_OS_INFO="no" + +### Set BMC/Service Processor Info in OS ### +# Name; SET_BMC_INFO +# Description: Set IP Address and URL of Service Processor/BMC in /run/bmc-info +# Default: yes +SET_BMC_INFO="yes" diff --git a/SOURCES/ipmievd.service b/SOURCES/ipmievd.service new file mode 100644 index 0000000..88c22c2 --- /dev/null +++ b/SOURCES/ipmievd.service @@ -0,0 +1,13 @@ +[Unit] +Description=Ipmievd Daemon +After=syslog.target +After=ipmi.service + +[Service] +EnvironmentFile=-/etc/sysconfig/ipmievd +ExecStart=/usr/sbin/ipmievd $IPMIEVD_OPTIONS +Type=forking +PIDFile=/var/run/ipmievd.pid + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/ipmitool-1.8.10-ipmievd-condrestart.patch b/SOURCES/ipmitool-1.8.10-ipmievd-condrestart.patch new file mode 100644 index 0000000..b9feb08 --- /dev/null +++ b/SOURCES/ipmitool-1.8.10-ipmievd-condrestart.patch @@ -0,0 +1,39 @@ +532188 - ipmievd init script's condrestart doesn't work + +Author: Ville Skyttä (ville.skytta@iki.fi) +Sent upstream as https://sourceforge.net/tracker/?func=detail&aid=2889888&group_id=95200&atid=610552 + +Index: contrib/ipmievd.init.redhat +=================================================================== +RCS file: /cvsroot/ipmitool/ipmitool/contrib/ipmievd.init.redhat,v +retrieving revision 1.1 +diff -u -r1.1 ipmievd.init.redhat +--- contrib/ipmievd.init.redhat 19 Mar 2006 23:05:48 -0000 1.1 ++++ contrib/ipmievd.init.redhat 31 Oct 2009 08:50:07 -0000 +@@ -62,6 +62,11 @@ + return $ret + } + ++restart() { ++ stop ++ start ++} ++ + case "$1" in + start) + start +@@ -72,11 +77,10 @@ + status) + status $IPMIEVD_BIN + ;; +- restart|reload) +- stop +- start ++ restart|reload|force-reload) ++ restart + ;; +- condrestart) ++ try-restart|condrestart) + [ -f /var/lock/subsys/ipmievd ] && restart || : + ;; + *) diff --git a/SOURCES/ipmitool-1.8.10-ipmievd-init.patch b/SOURCES/ipmitool-1.8.10-ipmievd-init.patch new file mode 100644 index 0000000..0821e31 --- /dev/null +++ b/SOURCES/ipmitool-1.8.10-ipmievd-init.patch @@ -0,0 +1,32 @@ +diff -up ipmitool-1.8.10/contrib/ipmievd.init.redhat.ipmievd-init ipmitool-1.8.10/contrib/ipmievd.init.redhat +--- ipmitool-1.8.10/contrib/ipmievd.init.redhat.ipmievd-init 2006-03-20 00:05:48.000000000 +0100 ++++ ipmitool-1.8.10/contrib/ipmievd.init.redhat 2008-10-14 13:46:35.000000000 +0200 +@@ -5,7 +5,7 @@ + # Based on example sysvinitfiles script + # Copyright (c) 2000 Red Hat Software, Inc. + # +-# chkconfig: 345 99 00 ++# chkconfig: - 99 00 + # description: ipmievd daemon to send events to syslog + # processname: ipmievd + # config: /etc/sysconfig/ipmievd +@@ -16,8 +16,8 @@ + # Should-Start: $time + # Required-Stop: $syslog ipmi + # Should-Stop: $time +-# Default-Start: 3 4 5 +-# Default-Stop: 0 1 2 6 ++# Default-Start: ++# Default-Stop: + # Short-Description: ipmievd daemon to send events to syslog + # Description: Start ipmievd to read events from BMC and + # log them to syslog. Events correspond to hardware faults, +@@ -85,7 +85,7 @@ case "$1" in + ;; + *) + echo "Usage: ipmievd {start|stop|status|reload|restart|condrestart}" +- exit 1 ++ exit 2 + ;; + esac + exit $? diff --git a/SOURCES/ipmitool-1.8.11-remove-umask0.patch b/SOURCES/ipmitool-1.8.11-remove-umask0.patch new file mode 100644 index 0000000..779c505 --- /dev/null +++ b/SOURCES/ipmitool-1.8.11-remove-umask0.patch @@ -0,0 +1,13 @@ +CVE-2011-4339 OpenIPMI: IPMI event daemon creates PID file with world writeable permissions + +diff -up ipmitool-1.8.11/lib/helper.c.original ipmitool-1.8.11/lib/helper.c +--- ipmitool-1.8.11/lib/helper.c.original 2011-10-03 13:00:54.000000000 +0900 ++++ ipmitool-1.8.11/lib/helper.c 2011-10-03 13:01:01.000000000 +0900 +@@ -427,7 +427,6 @@ ipmi_start_daemon(struct ipmi_intf *intf + #endif + + chdir("/"); +- umask(0); + + for (fd=0; fd<64; fd++) { + if (fd != intf->fd) diff --git a/SOURCES/ipmitool-1.8.13-dualbridgedoc.patch b/SOURCES/ipmitool-1.8.13-dualbridgedoc.patch new file mode 100644 index 0000000..00573cc --- /dev/null +++ b/SOURCES/ipmitool-1.8.13-dualbridgedoc.patch @@ -0,0 +1,13 @@ +diff -up ipmitool-1.8.13/doc/ipmitool.1.dualbridge ipmitool-1.8.13/doc/ipmitool.1 +--- ipmitool-1.8.13/doc/ipmitool.1.dualbridge 2013-11-05 10:10:20.139940133 +0100 ++++ ipmitool-1.8.13/doc/ipmitool.1 2013-11-05 10:10:35.197947425 +0100 +@@ -156,9 +156,6 @@ Set the local IPMB address. The local a + or is auto discovered on PICMG platforms when -m is not specified. + There should be no need to change the local address for normal operation. + .TP +-\fB\-M\fR <\fIaddress\fP> +-Set transit local address for bridge request. (dual bridge) +-.TP + \fB\-N\fR <\fIsec\fP> + Specify nr. of seconds between retransmissions of lan/lanplus messages. + Defaults are 2 seconds for lan and 1 second for lanplus interfaces. diff --git a/SOURCES/openipmi-ipmievd.sysconf b/SOURCES/openipmi-ipmievd.sysconf new file mode 100644 index 0000000..8cc15e0 --- /dev/null +++ b/SOURCES/openipmi-ipmievd.sysconf @@ -0,0 +1 @@ +IPMIEVD_OPTIONS="sel daemon pidfile=/var/run/ipmievd.pid" diff --git a/SOURCES/set-bmc-url.sh b/SOURCES/set-bmc-url.sh new file mode 100644 index 0000000..a179981 --- /dev/null +++ b/SOURCES/set-bmc-url.sh @@ -0,0 +1,11 @@ +# Export BMC URL +# + +BMC_INFO="/var/run/bmc-info" + +if [ "$(id -u)" = "0" ]; then + [ -f ${BMC_INFO} ] && . ${BMC_INFO} && \ + export "${BMC_URL}" "${BMC_IPv4}" >/dev/null 2>&1 +fi + +unset BMC_INFO diff --git a/SPECS/ipmitool.spec b/SPECS/ipmitool.spec new file mode 100644 index 0000000..866022a --- /dev/null +++ b/SPECS/ipmitool.spec @@ -0,0 +1,307 @@ +Name: ipmitool +Summary: Utility for IPMI control +Version: 1.8.13 +Release: 3%{?dist} +License: BSD +Group: System Environment/Base +URL: http://ipmitool.sourceforge.net/ +Source0: http://downloads.sourceforge.net/project/%{name}/%{name}/%{version}/%{name}-%{version}.tar.bz2 +Source1: openipmi-ipmievd.sysconf +Source2: ipmievd.service +Source3: exchange-bmc-os-info.service +Source4: exchange-bmc-os-info.sysconf +Source5: set-bmc-url.sh +Source6: exchange-bmc-os-info + +BuildRequires: openssl-devel readline-devel ncurses-devel +BuildRequires: systemd-units +# bootstrap +BuildRequires: automake autoconf libtool +Requires:OpenIPMI-modalias +Requires(post): systemd-sysv +Requires(post): systemd-units +Requires(preun): systemd-units +Requires(postun): systemd-units +Obsoletes: OpenIPMI-tools < 2.0.14-3 +Provides: OpenIPMI-tools = 2.0.14-3 + +Patch1: ipmitool-1.8.10-ipmievd-init.patch +Patch2: ipmitool-1.8.10-ipmievd-condrestart.patch +Patch3: ipmitool-1.8.11-remove-umask0.patch +# various threads. still pending. +Patch4: cxoem-jb-cx6.patch +# pending +#Patch5: ipmitool-1.8.12-fips.patch +# pending +#Patch6: ipmitool-1.8.12-fipsman.patch +# pending https://sourceforge.net/p/ipmitool/bugs/280/ +Patch7: ipmitool-1.8.13-dualbridgedoc.patch + +%description +This package contains a utility for interfacing with devices that support +the Intelligent Platform Management Interface specification. IPMI is +an open standard for machine health, inventory, and remote power control. + +This utility can communicate with IPMI-enabled devices through either a +kernel driver such as OpenIPMI or over the RMCP LAN protocol defined in +the IPMI specification. IPMIv2 adds support for encrypted LAN +communications and remote Serial-over-LAN functionality. + +It provides commands for reading the Sensor Data Repository (SDR) and +displaying sensor values, displaying the contents of the System Event +Log (SEL), printing Field Replaceable Unit (FRU) information, reading and +setting LAN configuration, and chassis power control. + +%package -n bmc-snmp-proxy +Requires: net-snmp +Requires: exchange-bmc-os-info +Requires:OpenIPMI-modalias +BuildArch: noarch +Summary: Reconfigure SNMP to include host SNMP agent within BMC +%description -n bmc-snmp-proxy +Given a host with BMC, this package would extend system configuration +of net-snmp to include redirections to BMC based SNMP. + + +%package -n exchange-bmc-os-info +Requires: hostname +Requires: ipmitool OpenIPMI +Requires:OpenIPMI-modalias +BuildArch: noarch +Requires(post): systemd-sysv +Requires(post): systemd-units +Requires(preun): systemd-units +Requires(postun): systemd-units + +Summary: Let OS and BMC exchange info + +%description -n exchange-bmc-os-info +Given a host with BMC, this package would pass the hostname & +OS information to the BMC and also capture the BMC ip info +for the host OS to use. + + +%prep + +%setup -q +%patch1 -p1 -b .ipmievd-init +%patch2 -p0 -b .condrestart +%patch3 -p1 -b .umask +%patch4 -p1 -b .cxoem +#patch5 -p0 -b .fips +#patch6 -p0 -b .fipsman +%patch7 -p1 -b .dualbridgedoc + +for f in AUTHORS ChangeLog; do + iconv -f iso-8859-1 -t utf8 < ${f} > ${f}.utf8 + mv ${f}.utf8 ${f} +done + +%build +# --disable-dependency-tracking speeds up the build +# --enable-file-security adds some security checks +# --disable-intf-free disables FreeIPMI support - we don't want to depend on +# FreeIPMI libraries, FreeIPMI has its own ipmitoool-like utility. + +# begin: release auto-tools +# Used to be needed by aarch64 support, now only cxoem patch makefiles are left. +aclocal +libtoolize --automake --copy +autoheader +automake --foreign --add-missing --copy +aclocal +autoconf +automake --foreign +# end: release auto-tools + +%configure --disable-dependency-tracking --enable-file-security --disable-intf-free +make %{?_smp_mflags} + +%install +make DESTDIR=%{buildroot} install + +install -Dpm 644 %{SOURCE2} %{buildroot}%{_unitdir}/ipmievd.service +install -Dpm 644 %{SOURCE1} %{buildroot}%{_sysconfdir}/sysconfig/ipmievd +install -Dm 644 %{SOURCE3} %{buildroot}%{_unitdir}/exchange-bmc-os-info.service +install -Dm 644 %{SOURCE4} %{buildroot}%{_sysconfdir}/sysconfig/exchange-bmc-os-info +install -Dm 644 %{SOURCE5} %{buildroot}%{_sysconfdir}/profile.d/set-bmc-url.sh +install -Dm 755 %{SOURCE6} %{buildroot}%{_libexecdir}/exchange-bmc-os-info + + +install -Dm 644 contrib/bmc-snmp-proxy.sysconf %{buildroot}%{_sysconfdir}/sysconfig/bmc-snmp-proxy +install -Dm 644 contrib/bmc-snmp-proxy.service %{buildroot}%{_unitdir}/bmc-snmp-proxy.service +install -Dm 755 contrib/bmc-snmp-proxy %{buildroot}%{_libexecdir}/bmc-snmp-proxy + +%post +%systemd_post ipmievd.service + +%preun +%systemd_preun ipmievd.service + +%postun +%systemd_postun_with_restart ipmievd.service + +%post -n exchange-bmc-os-info +%systemd_post exchange-bmc-os-info.service + +%preun -n exchange-bmc-os-info +%systemd_preun exchange-bmc-os-info.service + +%postun -n exchange-bmc-os-info +%systemd_postun_with_restart exchange-bmc-os-info.service + + +%triggerun -- ipmievd < 1.8.11-7 +# Save the current service runlevel info +# User must manually run systemd-sysv-convert --apply ipmievd +# to migrate them to systemd targets +/usr/bin/systemd-sysv-convert --save ipmievd >/dev/null 2>&1 ||: + +# Run these because the SysV package being removed won't do them +/sbin/chkconfig --del ipmievd >/dev/null 2>&1 || : +/bin/systemctl try-restart ipmievd.service >/dev/null 2>&1 || : + +%files +%config(noreplace) %{_sysconfdir}/sysconfig/ipmievd +%{_unitdir}/ipmievd.service +%{_bindir}/* +%{_sbindir}/* +%{_mandir}/man*/* +%doc %{_datadir}/doc/ipmitool +%{_datadir}/ipmitool + +%files -n exchange-bmc-os-info +%config(noreplace) %{_sysconfdir}/sysconfig/exchange-bmc-os-info +%{_sysconfdir}/profile.d/set-bmc-url.sh +%{_unitdir}/exchange-bmc-os-info.service +%{_libexecdir}/exchange-bmc-os-info + +%files -n bmc-snmp-proxy +%config(noreplace) %{_sysconfdir}/sysconfig/bmc-snmp-proxy +%{_unitdir}/bmc-snmp-proxy.service +%{_libexecdir}/bmc-snmp-proxy + +%changelog +* Tue Nov 5 2013 Ales Ledvinka <aledvink@redhat.com> 1.8.13-3 +- Cleanup of dual bridge option. + +* Tue Oct 15 2013 Ales Ledvinka <aledvink@redhat.com> 1.8.13-2 +- BMC SNMP agent redirection + +* Mon Oct 14 2013 Ales Ledvinka <aledvink@redhat.com> 1.8.13-1 +- Upstream release 1.8.13 + +* Fri Aug 09 2013 Ales Ledvinka <aledvink@redhat.com> 1.8.12-13073103 +- Avoid FIPS mode crashes if possible. +- Document FIPS limitations. + +* Wed Jul 31 2013 Ales Ledvinka <aledvink@redhat.com> 1.8.12-13073101 +- Include current upstream bugfixes. + +* Thu Jul 25 2013 Ales Ledvinka <aledvink@redhat.com> 1.8.12-16 +- Calxeda OEM extensions. + +* Thu Feb 14 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.8.12-15 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Mon Dec 17 2012 Praveen K Paladugu <praveen_paladugu@dell.com> - 1.8.12-14 +- Updated the exchange-bmc-os-info's service file with Requires stmt + +* Fri Dec 14 2012 Ales Ledvinka <aledvink@redhat.com> 1.8.12-13 +- fixed argument parsing leaks +- ask user for password only once and do so only when interactive password + is the chosen password method. + +* Thu Dec 13 2012 Praveen K Paladugu <praveen_paladugu@dell.com> - 1.8.12-12 +- Removed the extra symbols in the patch, as the build is failing. + +* Thu Dec 13 2012 Praveen K Paladugu <praveen_paladugu@dell.com> - 1.8.12-11 +- Subpackage for exchange-bmc-os-info as it requires OPenIPMI + +* Wed Dec 12 2012 Ales Ledvinka <aledvink@redhat.com> 1.8.12-10 +- documented fixed and conditional defaults. adjusted synopsis + +* Tue Dec 4 2012 Ales Ledvinka <aledvink@redhat.com> 1.8.12-9 +- fixed ipmitool documentation + +* Fri Nov 30 2012 Praveen K Paladugu <praveen_paladugu@dell.com> 1.8.12-8 +- service & scripts to allow OS to capture BMC's IP & URL info +- Also pass the OS information to BMC +- patches submitted by Charles Rose (charles_rose[at]dell.com) + +* Fri Nov 16 2012 Ales Ledvinka <aledvink@redhat.com> 1.8.12-7 +- failed sol session activation crashes while logging exit + +* Fri Nov 16 2012 Ales Ledvinka <aledvink@redhat.com> 1.8.12-6 +- revert default cipersuite back to 3 which includes integrity and confidentiality + +* Thu Oct 18 2012 Dan Horák <dan[at]danny.cz> - 1.8.12-5 +- fix build on big endian arches + +* Wed Oct 17 2012 Ales Ledvinka <aledvink@redhat.cz> 1.8.12-4 +- support setting OS name and Hostname on BMC + +* Tue Sep 04 2012 Dan Horák <dan[at]danny.cz> - 1.8.12-3 +- fix build on big endian arches + +* Mon Aug 27 2012 Jan Safranek <jsafrane@redhat.com> - 1.8.12-2 +- Fixed starting ipmievd under systemd (#819234). +- Updated RPM scriplets with latest systemd-rpm macros (#850161) + +* Fri Aug 10 2012 Jan Safranek <jsafrane@redhat.com> - 1.8.12-1 +- update to ipmitool-1.8.12 + +* Thu Jul 19 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.8.11-12 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue May 22 2012 Jan Safranek <jsafrane@redhat.com> - 1.8.11-11 +- start ipmievd.service after ipmi (#819234) + +* Thu Apr 26 2012 Jan Safranek <jsafrane@redhat.com> - 1.8.11-10 +- fixed ipmievd.service systemd unit (#807757) + +* Fri Jan 13 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.8.11-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Dec 13 2011 Jan Safranek <jsafrane@redhat.com> - 1.8.11-8 +- fixed CVE-2011-4339 + +* Mon Sep 12 2011 Tom Callaway <spot@fedoraproject.org> - 1.8.11-7 +- convert to systemd + +* Wed Feb 09 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.8.11-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Wed Mar 3 2010 Jan Safranek <jsafrane@redhat.com> - 1.8.11-5 +- Fixed exit code of ipmievd initscript with wrong arguments + +* Mon Nov 2 2009 Jan Safranek <jsafrane@redhat.com> 1.8.11-4 +- fix ipmievd initscript 'condrestart' action (#532188) + +* Fri Aug 21 2009 Tomas Mraz <tmraz@redhat.com> - 1.8.11-3 +- rebuilt with new openssl + +* Fri Jul 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.8.11-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Thu Feb 26 2009 Jan Safranek <jsafrane@redhat.com> 1.8.11-1 +- updated to new version + +* Tue Feb 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.8.10-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Sat Jan 17 2009 Tomas Mraz <tmraz@redhat.com> 1.8.10-3 +- rebuild with new openssl + +* Tue Oct 14 2008 Jan Safranek <jsafrane@redhat.com> 1.8.10-2 +- fix issues found during package review: + - clear Default-Start: line in the init script, the service should be + disabled by default + - added Obsoletes: OpenIPMI-tools + - compile with --disable-dependency-tracking to speed things up + - compile with --enable-file-security + - compile with --disable-intf-free, don't depend on FreeIPMI libraries + (FreeIPMI has its own ipmitool-like utility) + +* Mon Oct 13 2008 Jan Safranek <jsafrane@redhat.com> 1.8.10-1 +- package created, based on upstream .spec file