diff options
Diffstat (limited to 'util/ipmicmd.c')
-rw-r--r-- | util/ipmicmd.c | 1429 |
1 files changed, 1429 insertions, 0 deletions
diff --git a/util/ipmicmd.c b/util/ipmicmd.c new file mode 100644 index 0000000..dd2268b --- /dev/null +++ b/util/ipmicmd.c @@ -0,0 +1,1429 @@ +/*M* +// PVCS: +// $Workfile: ipmicmd.c $ +// $Revision: 1.12 $ +// $Modtime: 23 Feb 2005 11:24:14 $ +// $Author: arcress at users.sourceforge.net $ +// +// Define the ipmi_cmd routine and supporting logic to execute IPMI +// commands via one of the supported IPMI drivers: +// /dev/ipmi0 /dev/ipmi/0 = MontaVista OpenIPMI driver +// /dev/imb = Intel IMB ipmidrvr (comes with ISM) +// /dev/ipmikcs /dev/ipmi/kcs = valinux driver by San Mehat +// libfreeipmi.so = GNU FreeIPMI user-space library +// ldipmidaemon = LanDesk IPMI daemon (user-space process) +// +// 08/05/02 ARC - created +// 08/15/02 ARC - added decode_cc +// 10/24/02 ARC - made cmd param ushort to be more unique +// 01/29/03 ARC - added MontaVista OpenIPMI driver support +// 07/25/03 ARC - added serial-over-lan commands +// 07/30/03 ARC - added GetThresholds, fix for ipmi_cmd_raw, +// changed some error messages +// 09/04/03 ARC - added debug messages for fDriverTyp first time +// 05/05/04 ARC - leave _mv device open, rely on each app calling ipmi_close, +// helps performance. +// 08/10/04 ARC - fix typo in ipmi_cmd_raw/mv: cmd->icmd (thanks Kevin Gao) +// 08/26/04 ARC - fix out-of-bounds error in decode_cc +// 10/27/04 ARC - added gnu FreeIPMI library support +// 11/11/04 ARC - added fdebug to ipmi_getdeviceid & ipmi_open_gnu +// 02/23/05 ARC - added routines for LanDesk, fDriverTyp=5 +// 07/15/05 ARC - test for ldipmi first, since it hangs KCS if another +// driver tries to coexist. +// 07/06/06 ARC - better separate driver implementations, cleaner now + *M*/ +/*----------------------------------------------------------------------* +The BSD License + +Copyright (c) 2002-2006, Intel Corporation +Copyright (c) 2009 Kontron America, 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: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions 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. + c.. Neither the name of Intel Corporation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *----------------------------------------------------------------------*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <io.h> +#include <fcntl.h> +#elif defined(EFI) +// defined (EFI32) || defined (EFI64) || defined(EFIX64) +#include <bmc.h> +#include <libdbg.h> +#else +/* Linux, Solaris, BSD */ +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#ifndef DOS +#include <sys/ioctl.h> +#include <termios.h> +#endif +#include <stdarg.h> +#include <errno.h> +#endif + +#include "ipmicmd.h" /* has NCMDS, ipmi_cmd_t */ + +ipmi_cmd_t ipmi_cmds[NCMDS] = { /*if add here, also change NCMDS in ipmicmd.h*/ + {/*empty,temp*/ 0, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 0, 20}, + {GET_SEL_INFO, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 0, 14}, + {GET_SEL_ALLOCATION_INFO,BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 0, 9}, + {GET_SEL_ENTRY, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 6, 18}, + {RESERVE_SEL, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 0, 2}, + {CLEAR_SEL, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 6, 1}, + {GET_SEL_TIME, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 6, 4}, + {GET_LAN_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 4, 19}, + {SET_LAN_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 21, 0}, + {GET_LAN_STATS, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 2, 18}, + {GET_SER_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 4, 19}, + {SET_SER_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 21, 0}, + {SET_SER_MUX, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 2, 0}, + {GET_PEF_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 3, 22}, + {SET_PEF_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 22, 0}, +// {SET_PEF_ENABLE, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 4, 0}, /*old*/ + {GET_DEVSDR_INFO, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 0, 6}, + {GET_DEVICE_SDR, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 6, 18}, + {RESERVE_DEVSDR_REP,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 0, 2}, + {GET_SENSOR_READING,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 1, 4}, + {GET_SENSOR_READING_FACTORS,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 2, 7}, + {GET_SENSOR_TYPE, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 1, 2}, + {GET_SENSOR_THRESHOLD,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 1, 7}, + {SET_SENSOR_THRESHOLD,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 8, 0}, + {GET_SENSOR_HYSTERESIS,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 2, 2}, + {SET_SENSOR_HYSTERESIS,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 4, 0}, + {GET_SDR, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 6, 18},/*full=63*/ + {GET_SDR_REPINFO, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 0, 14}, + {RESERVE_SDR_REP, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 0, 2}, + {GET_FRU_INV_AREA, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 1, 3}, + {READ_FRU_DATA, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN, 4, 18}, + {WRITE_FRU_DATA, BMC_SA, PUBLIC_BUS, NETFN_STOR, BMC_LUN,20 /*3+N(17)*/, 1}, + {GET_DEVICE_ID, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 0, 15}, + {SET_USER_ACCESS, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 4, 0}, + {GET_USER_ACCESS, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 2, 4}, + {GET_USER_NAME, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 1, 16}, + {SET_USER_NAME, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 17, 0}, + {SET_USER_PASSWORD,BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 18, 0}, + {MASTER_WRITE_READ,BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 4 /*or 3*/, 1}, + {GET_SYSTEM_GUID, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 0, 16}, + {WATCHDOG_GET, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 0, 8}, + {WATCHDOG_SET, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 6, 0}, + {WATCHDOG_RESET, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 0, 0}, + {CHASSIS_STATUS, BMC_SA, PUBLIC_BUS, NETFN_CHAS, BMC_LUN, 0, 2}, + {CHASSIS_CTL, BMC_SA, PUBLIC_BUS, NETFN_CHAS, BMC_LUN, 1, 0}, + {CHASSIS_IDENTIFY, BMC_SA, PUBLIC_BUS, NETFN_CHAS, BMC_LUN, 1, 0}, + {GET_POWERON_HOURS,BMC_SA, PUBLIC_BUS, NETFN_CHAS, BMC_LUN, 0, 0}, + {SET_BOOT_OPTIONS, BMC_SA, PUBLIC_BUS, NETFN_CHAS, BMC_LUN, 19, 0}, + {GET_BOOT_OPTIONS, BMC_SA, PUBLIC_BUS, NETFN_CHAS, BMC_LUN, 3, 18}, + {ACTIVATE_SOL1, BMC_SA, PUBLIC_BUS, NETFN_SOL, BMC_LUN, 0, 0}, + {SET_SOL_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_SOL, BMC_LUN, 3, 0}, + {GET_SOL_CONFIG, BMC_SA, PUBLIC_BUS, NETFN_SOL, BMC_LUN, 4, 2}, + {ACTIVATE_SOL2, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 0, 0}, + {SET_SOL_CONFIG2, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 3, 0}, + {GET_SOL_CONFIG2, BMC_SA, PUBLIC_BUS, NETFN_TRANS, BMC_LUN, 4, 2}, + {GET_SEVT_ENABLE, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 1, 5}, + {SET_SEVT_ENABLE, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 6, 0}, + {REARM_SENSOR, BMC_SA, PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 6, 0}, + {READ_EVENT_MSGBUF,BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 0, 16}, + {GET_EVENT_RECEIVER,BMC_SA,PUBLIC_BUS, NETFN_SEVT, BMC_LUN, 0, 2}, + {GET_CHANNEL_INFO, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 1, 9}, + {SET_CHANNEL_ACC, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 3, 0}, + {GET_CHANNEL_ACC, BMC_SA, PUBLIC_BUS, NETFN_APP, BMC_LUN, 2, 1} }; + +/* Subroutine definitions for each driver */ +#ifdef EFI +int ipmi_open_efi(char fdebug); +int ipmi_cmdraw_efi( uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +#else + +#include "ipmilan2.h" /*includes ipmilan.h also*/ +#ifdef WIN32 +extern int ipmi_cmdraw_ia( uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_ia(char fdebug); +extern int ipmi_close_ia(void); +extern int ipmi_cmdraw_ms(uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_ms(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_ms(char fdebug); +extern int ipmi_close_ms(void); +#elif defined(SOLARIS) +extern int ipmi_cmdraw_bmc(uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_bmc(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_bmc(char fdebug); +extern int ipmi_close_bmc(void); +extern int ipmi_cmdraw_lipmi(uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_lipmi(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_lipmi(char fdebug); +extern int ipmi_close_lipmi(void); +#elif defined(LINUX) +extern int ipmi_cmdraw_ia( uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_ia(char fdebug); +extern int ipmi_close_ia(void); +extern int ipmi_cmdraw_mv(uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_mv(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_mv(char fdebug); +extern int ipmi_close_mv(void); +extern int ipmi_open_ld(char fdebug); +extern int ipmi_close_ld(void); +extern int ipmi_cmdraw_ld(uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_ld(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_direct(char fdebug); +extern int ipmi_close_direct(void); +extern int ipmi_cmdraw_direct( uchar cmd, uchar netfn, uchar lun, + uchar sa, uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_direct(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_set_max_kcs_loops(int ms); +#elif defined(DOS) +extern int ipmi_open_direct(char fdebug); +extern int ipmi_close_direct(void); +extern int ipmi_cmdraw_direct( uchar cmd, uchar netfn, uchar lun, + uchar sa, uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_direct(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_set_max_kcs_loops(int ms); +#else +/* BSD */ +extern int ipmi_open_direct(char fdebug); +extern int ipmi_close_direct(void); +extern int ipmi_cmdraw_direct( uchar cmd, uchar netfn, uchar lun, + uchar sa, uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_direct(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_set_max_kcs_loops(int ms); +extern int ipmi_cmdraw_mv(uchar cmd, uchar netfn, uchar lun, uchar sa, + uchar bus, uchar *pdata, int sdata, + uchar *presp, int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_cmd_mv(ushort cmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd); +extern int ipmi_open_mv(char fdebug); +extern int ipmi_close_mv(void); +#endif +extern int fd_wait(int fd, int nsec, int usec); +#endif + +/* Global Data */ +int fDriverTyp = DRV_UNKNOWN; /* 1=IMB driver, 2=VA driver, 3=MV open driver */ + /* 4= GNU FreeIPMI, 5= LanDesk, 6= builtin IPMI LAN */ + /* 7= direct KCS, 8= direct SMB, 9= IPMI LAN v2.0 */ +int fipmi_lan = 0; +int fjustpass = 0; +FILE *fperr = NULL; +FILE *fpdbg = NULL; +FILE *fplog = NULL; +char log_name[60] = {'\0'}; /*log_name global*/ +char *gnode = "localhost"; /* used for IPMI LAN, specified with option -N */ +char *guser = NULL; +char *gpswd = NULL; +char gnodename[SZGNODE] = {0}; /*the node name returned after a connection */ +int gcipher_suite = 3; /*used in ipmilanplus.c*/ +int gshutdown = 0; +int fauth_type_set = 0; +int gauth_type = IPMI_SESSION_AUTHTYPE_MD5; /*if 0, use any: MD5, MD2, etc.*/ +int gpriv_level = IPMI_PRIV_LEVEL_USER; /*or IPMI_PRIV_LEVEL_ADMIN */ +int gaddr_len = 0; +uchar gaddr[128]; /* sizeof(struct sockaddr_storage) = 128 */ + /* struct sockaddr_in/_in6 gaddr; _in6=28, _in=16 bytes */ +uchar my_devid[20] = {0,0,0,0,0,0,0,0}; /*saved devid, only needs 16 bytes*/ +char fdebug = 0; + +typedef struct { + uchar adrtype; + uchar sa; + uchar bus; + uchar lun; + uchar capab; +} mc_info; +mc_info bmc = { ADDR_SMI, BMC_SA, PUBLIC_BUS, BMC_LUN, 0x8F }; /*BMC via SMI*/ +mc_info mc2 = { ADDR_IPMB, BMC_SA, PUBLIC_BUS, BMC_LUN, 0x4F }; /*IPMB target*/ +mc_info mymc = { ADDR_IPMB, BMC_SA, PUBLIC_BUS, BMC_LUN, 0x4F }; /*IPMB */ +static char bcomma = ','; +static mc_info *mc = &bmc; +#ifdef WIN32 +static char msg_no_drv[] = { /*no Windows driver*/ + "Cannot open an IPMI driver: imbdrv.sys or ipmidrv.sys\n"}; +#elif defined(SOLARIS) +static char msg_no_drv[] = { /*no Solaris driver*/ + "Cannot open an IPMI driver: /dev/bmc or /dev/lipmi\n"}; +#elif defined(LINUX) +static char msg_no_drv[] = { /*no Linux driver*/ + "Cannot open an IPMI driver: /dev/imb, /dev/ipmi0, " + "/dev/ipmi/0, \n\t " +/* "/dev/ipmikcs, /dev/ipmi/kcs, " *no longer support valinux */ +#ifdef LINK_LANDESK + "ldipmi, " +#endif + "or direct driverless.\n" }; + +#elif defined(DOS) +static char msg_no_drv[] = { /*no DOS IPMI driver*/ + "Cannot open an IPMI direct KCS interface.\n"}; +#else +static char msg_no_drv[] = { /*no BSD IPMI driver*/ + "Cannot open an IPMI driver: /dev/ipmi0 or direct.\n"}; +#endif + +/* From IPMI v1.5/v2.0 spec, Table 5-2 Completion Codes */ +#define NUMCC 32 +struct { + uchar code; + char *mesg; + } cc_mesg[NUMCC] = { +/* Note: completion codes 0x80-0x9f may vary depending on the command. + * 0x80 = Invalid Session Handle or Empty Buffer or Unsupported Feature + */ +{0x00, "Command completed successfully"}, +{0x80, "Invalid Session Handle or Empty Buffer"}, +{0x81, "Lost Arbitration"}, +{0x82, "Bus Error"}, +{0x83, "NAK on Write - busy"}, +{0x84, "Truncated Read"}, +{0x85, "Invalid session ID in request"}, /*for ActivateSession*/ +{0x86, "Requested privilege level exceeds limit"}, /*for ActivateSession*/ +{0xC0, "Node Busy"}, +{0xC1, "Invalid Command"}, +{0xC2, "Command invalid for given LUN"}, +{0xC3, "Timeout while processing command"}, +{0xC4, "Out of space"}, +{0xC5, "Reservation ID cancelled or invalid"}, +{0xC6, "Request data truncated"}, +{0xC7, "Request data length invalid"}, +{0xC8, "Request data field length limit exceeded"}, +{0xC9, "Parameter out of range"}, +{0xCA, "Cannot return requested number of data bytes"}, +{0xCB, "Requested sensor, data, or record not present"}, +{0xCC, "Invalid data field in request"}, +{0xCD, "Command illegal for this sensor/record type"}, +{0xCE, "Command response could not be provided"}, +{0xCF, "Cannot execute duplicated request"}, +{0xD0, "SDR Repository in update mode, no response"}, +{0xD1, "Device in firmware update mode, no response"}, +{0xD2, "BMC initialization in progress, no response"}, +{0xD3, "Destination unavailable"}, +{0xD4, "Cannot execute command. Insufficient privilege level"}, +{0xD5, "Cannot execute command. Request parameters not supported"}, +{0xD6, "Cannot execute command. Subfunction unavailable"}, +{0xFF, "Unspecified error"} +}; + +char * decode_cc(ushort icmd, int cc) +{ + static char other_msg[25]; + char *pmsg; + int i; + for (i = 0; i < NUMCC; i++) { + if (cc == cc_mesg[i].code) break; + } + if (i == NUMCC) { /* if not found, show other_msg */ + sprintf(other_msg,"Other error 0x%02x",cc); + pmsg = other_msg; + } else { + if ((icmd == READ_EVENT_MSGBUF) && (cc == 0x80)) + pmsg = "no data available (queue/buffer empty)"; + else pmsg = cc_mesg[i].mesg; + } + return(pmsg); +} + +char *decode_rv(int rv) +{ + char *msg; + static char msgbuf[80]; + if (rv == 0x6F) msg = "License not supported"; /*for Dell*/ + else if (rv > 0) msg = decode_cc((ushort)0,rv); + else switch(rv) { + case 0: msg = "completed successfully"; break; + case -1: msg = "error -1"; break; + case LAN_ERR_SEND_FAIL: msg = "send to BMC failed"; break; + case LAN_ERR_RECV_FAIL: msg = "receive from BMC failed"; break; + case LAN_ERR_CONNECT: msg = "cannot connect to BMC"; break; + case LAN_ERR_ABORT: msg = "abort signal caught"; break; + case LAN_ERR_TIMEOUT: msg = "timeout occurred"; break; + case LAN_ERR_BADLENGTH: msg = "length greater than max"; break; + case LAN_ERR_INVPARAM: msg = "invalid lan parameter"; break; + case LAN_ERR_NOTSUPPORT: msg = "request not supported"; break; + case LAN_ERR_TOO_SHORT: msg = "receive too short"; break; + case LAN_ERR_HOSTNAME: msg = "error resolving hostname"; break; + case LAN_ERR_PING: msg = "error during ping"; break; + case LAN_ERR_V1: msg = "BMC only supports lan v1"; break; + case LAN_ERR_V2: msg = "BMC only supports lan v2"; break; + case LAN_ERR_OTHER: msg = "other error"; break; + case ERR_NO_DRV: msg = "cannot open IPMI driver"; break; + case ERR_BAD_PARAM: msg = "invalid parameter"; break; + case ERR_NOT_ALLOWED: msg = "access not allowed"; break; + case ERR_USAGE: msg = "usage or help requested"; break; + case LAN_ERR_DROPPED: msg = "session dropped by BMC"; break; + case ERR_FILE_OPEN: msg = "cannot open file"; break; + case ERR_NOT_FOUND: msg = "item not found"; break; + case ERR_BMC_MSG: msg = "error getting msg from BMC"; break; + /* ipmidir.h: ERGETTINGIPMIMESSAGE -504 */ + case ERR_BAD_FORMAT: msg = "bad format"; break; + case ERR_BAD_LENGTH: msg = "length less than min"; break; + default: + sprintf(msgbuf,"error %d",rv); + msg = msgbuf; + break; + } + return(msg); +} + +int get_cmd_rslen(uchar cmd, uchar netfn) +{ /* used by ipmicmd_gnu */ + int rslen = 0; + int i; + ushort cmdkey; + cmdkey = cmd | (netfn << 8); + for (i = 0; i < NCMDS; i++) { + if (ipmi_cmds[i].cmdtyp == cmdkey) { + rslen = ipmi_cmds[i].rslen; + break; + } + } + return(rslen); +} /*end get_cmd_rslen()*/ + +static int ndrivers = NDRIVERS; +static struct { + int idx; + char *tag; + } drv_types[NDRIVERS] = { + { DRV_IMB, "imb" }, + { DRV_MV, "open" }, + { DRV_LD, "landesk" }, + { DRV_LAN2, "lan2" }, + { DRV_LAN2I,"lan2i" }, + { DRV_LAN, "lan" }, + { DRV_KCS, "kcs" }, + { DRV_SMB, "smb" }, + { DRV_MS, "ms" }, + { DRV_BMC, "sun_bmc" }, + { DRV_LIPMI,"sun_lipmi" }, + { DRV_SMC, "supermicro" }, + { DRV_IBM, "ibm" }, + { DRV_HP, "hp" }, /*++++*/ +#ifdef EFI + { DRV_EFI, "efi" } +#else + { 0, "" } /*DRV_UNKNOWN*/ +#endif +}; + // { DRV_VA, "va" }, + // { DRV_GNU, "free" }, + +char *show_driver_type(int idx) +{ + int i; + char *tag; + for (i = 0; i < ndrivers; i++) + { + if (drv_types[i].idx == idx) { + tag = drv_types[i].tag; + break; + } + } + if (i >= ndrivers) { /*not found*/ + tag = "unknown"; + } + return(tag); +} + +int get_driver_type(void) +{ + return(fDriverTyp); +} + +void set_iana(int iana) +{ + my_devid[6] = (iana & 0x0000ff); + my_devid[7] = ((iana & 0x00ff00) >> 8); + my_devid[8] = ((iana & 0xff0000) >> 16); +} + +void set_mfgid(uchar *devid, int len) +{ + if (devid == NULL) return; + if (len > sizeof(my_devid)) len = sizeof(my_devid); + memcpy(my_devid,devid,len); +} + +void get_mfgid(int *pvend, int *pprod) +{ + if (pvend != NULL) + *pvend = my_devid[6] + (my_devid[7] << 8) + (my_devid[8] << 16); + if (pprod != NULL) + *pprod = my_devid[9] + (my_devid[10] << 8); +} + +int set_driver_type(char *tag) +{ + int rv = 0; + int i; + /* else if (str_icmp(tag,"lan2") == 0) * leave vendor id as is. */ + for (i = 0; i < ndrivers; i++) + { + if (str_icmp(drv_types[i].tag, tag) == 0) { + fDriverTyp = drv_types[i].idx; + if (fDriverTyp == DRV_LAN2I) { /*LAN2 Intel*/ + set_iana(VENDOR_INTEL); /*VENDOR_INTEL = 0x000157*/ + } else if (fDriverTyp == DRV_SMC) { /*supermicro*/ + set_iana(VENDOR_SUPERMICRO); /*VENDOR_SUPERMICRO = 0x002A7C*/ + fDriverTyp = DRV_LAN; + } + if (fDriverTyp == DRV_IBM) { /*LAN IBM*/ + set_iana(VENDOR_IBM); + fDriverTyp = DRV_LAN; + } + if (fDriverTyp == DRV_HP) { /*LAN2 HP ++++*/ + set_iana(VENDOR_HP); + fDriverTyp = DRV_LAN2; + gauth_type = IPMI_SESSION_AUTHTYPE_NONE; /*HP default*/ + } + break; + } + } + if (i >= ndrivers) { /*not found*/ + fDriverTyp = DRV_UNKNOWN; /*not set yet, so detect*/ + rv = 1; + // if (fdebugcmd) + { + printf("Invalid -F argument (%s), valid driver types are:\n",tag); + for (i = 0; i < ndrivers; i++) + printf("\t%s\n",drv_types[i].tag); + } + } + return(rv); +} + +/* + * use_devsdrs + * detect whether to use SDR repository or Device SDRs from + * the saved GetDeviceID response. + * ipmi_getdeviceid saves it into my_devid. + */ +int use_devsdrs(int picmg) +{ + int fdev, vend, prod; + /* set Device SDRs flag as specified in the GetDeviceID */ + if ((my_devid[1] & 0x80) == 0x80) fdev = 1; + else fdev = 0; + if (picmg) return(fdev); + /* check for vendor/products that can report the flag wrong */ + vend = my_devid[6] + (my_devid[7] << 8) + (my_devid[8] << 16); + prod = my_devid[9] + (my_devid[10] << 8); + switch(vend) { + case VENDOR_INTEL: + if ((prod != 0x800) && (prod != 0x808) && (prod != 0x841)) + fdev = 0; + break; + case VENDOR_NSC: fdev = 0; break; + case VENDOR_NEC: fdev = 0; break; + case VENDOR_DELL: fdev = 0; break; + case VENDOR_HP: fdev = 0; break; + case VENDOR_SUN: fdev = 0; break; + default: break; + } + return(fdev); +} + +/* get_lan_channel returns the next lan channel starting with chfirst. */ +int get_lan_channel(uchar chfirst, uchar *chan) +{ + int ret, j; + uchar iData[4]; + uchar rData[9]; + int rlen; + uchar cc; + int found = 0; + + for (j = chfirst; j < 12; j++) + { + rlen = sizeof(rData); + iData[0] = (uchar)j; /*channel #*/ + memset(rData,0,9); /*initialize recv data*/ + ret = ipmi_cmd(GET_CHANNEL_INFO, iData, 1, rData, &rlen, &cc, fdebug); + if (ret == 0xcc || cc == 0xcc) /* special case for ipmi_lan */ + continue; + if (ret != 0) { + if (fdebug) printf("get_chan_info rc = %x\n",ret); + break; + } + /* rData[1] == channel medium type */ + if (rData[1] == 4) { /* medium type 4 = 802.3 LAN type*/ + if (fdebug) printf("chan[%d] = lan\n",j); + found = 1; + *chan = (uchar)j; + break; + } + } + if (found == 0) ret = -1; + return(ret); +} + +int nodeislocal(char *nodename) +{ + if (nodename == NULL) return 1; + if (nodename[0] == 0) return 1; + if (strcmp(nodename,"localhost") == 0) return 1; + return 0; +} + +int set_max_kcs_loops(int ms) +{ + int rv = 0; +#if defined(LINUX) + rv = ipmi_set_max_kcs_loops(ms); +#elif defined(BSD) + rv = ipmi_set_max_kcs_loops(ms); +#elif defined(DOS) + rv = ipmi_set_max_kcs_loops(ms); +#endif + return(rv); +} + +/* + * ipmi_open + * This is called by ipmi_cmd and ipmicmd_raw if a session has not + * yet been opened (fDriverTyp == DRV_UNKNOWN). + * The order to try these drivers could be customized for specific + * environments by modifying this routine. + * + * ipmi_cmd[raw] would call a specific open routine if set_driver_type(). + */ +int ipmi_open(char fdebugcmd) +{ + int rc = 0; + fperr = stderr; + fpdbg = stdout; + + fdebug = fdebugcmd; +#ifdef EFI + rc = ipmi_open_efi(fdebugcmd); +#else + if (!nodeislocal(gnode)) { fipmi_lan = 1; } + if (fdebugcmd) printf("ipmi_open: driver type = %s\n", + show_driver_type(fDriverTyp)); + /* first time, so try each */ + if (fipmi_lan) { + /* Try IPMI LAN 1.5 first */ + rc = ipmi_open_lan(gnode,guser,gpswd,fdebugcmd); + fDriverTyp = DRV_LAN; + if (rc == LAN_ERR_V2) { + /* Use IPMI LAN 2.0 if BMC said it only supports LAN2 */ + /* This is a violation of IPMI 2.0 Spec section 13.4, + * but some HP firmware behaves this way, so handle it. */ + rc = ipmi_open_lan2(gnode,guser,gpswd,fdebugcmd); + fDriverTyp = DRV_LAN2; + } + } else { /* local, not lan */ +#ifdef WIN32 + rc = ipmi_open_ia(fdebugcmd); + if (rc == ACCESS_OK) + fDriverTyp = DRV_IMB; + else if ((rc = ipmi_open_ms(fdebugcmd)) == ACCESS_OK) + fDriverTyp = DRV_MS; + else rc = ERR_NO_DRV; +#elif defined(SOLARIS) + rc = ipmi_open_bmc(fdebugcmd); + if (rc == ACCESS_OK) + fDriverTyp = DRV_BMC; + else if ((rc = ipmi_open_lipmi(fdebugcmd)) == ACCESS_OK) + fDriverTyp = DRV_LIPMI; + else rc = ERR_NO_DRV; +#elif defined(LINUX) + if ((rc = ipmi_open_ld(fdebugcmd)) == ACCESS_OK) { + fDriverTyp = DRV_LD; + ipmi_close_ld(); + } else if ((rc = ipmi_open_mv(fdebugcmd)) == ACCESS_OK) { + fDriverTyp = DRV_MV; + /* ipmi_close_mv(); * leave it open until explicit close */ + } else if ((rc = ipmi_open_ia(fdebugcmd)) == ACCESS_OK) { + fDriverTyp = DRV_IMB; + } else if ((rc = ipmi_open_direct(fdebugcmd)) == ACCESS_OK) { + /* set to either DRV_KCS or DRV_SMB */ + } else rc = ERR_NO_DRV; +#elif defined(DOS) + rc = ipmi_open_direct(fdebugcmd); + /* sets fDriverTyp to either DRV_KCS or DRV_SMB */ + if (rc != ACCESS_OK) rc = ERR_NO_DRV; +#else + /* BSD or MACOS */ + if ((rc = ipmi_open_mv(fdebugcmd)) == ACCESS_OK) { + /* FreeBSD "kldload ipmi" has /dev/ipmi0 */ + fDriverTyp = DRV_MV; + /* ipmi_close_mv(); * leave it open until explicit close */ + } else if ((rc = ipmi_open_direct(fdebugcmd)) == ACCESS_OK) { + /* sets fDriverTyp to either DRV_KCS or DRV_SMB */ + } else rc = ERR_NO_DRV; +#endif + + } /*endelse local, not lan*/ +#endif + if (fdebugcmd) printf("ipmi_open rc = %d type = %s\n",rc, + show_driver_type(fDriverTyp)); + return (rc); +} + +int ipmi_close_(void) +{ + int rc = 0; +#ifndef EFI + switch (fDriverTyp) + { +#ifdef WIN32 + case DRV_IMB: rc = ipmi_close_ia(); break; + case DRV_MS: rc = ipmi_close_ms(); break; +#elif defined(SOLARIS) + case DRV_BMC: rc = ipmi_close_bmc(); break; + case DRV_LIPMI: rc = ipmi_close_lipmi(); break; +#elif defined(LINUX) + case DRV_IMB: rc = ipmi_close_ia(); break; + case DRV_MV: rc = ipmi_close_mv(); break; + case DRV_LD: rc = ipmi_close_ld(); break; + case DRV_SMB: + case DRV_KCS: rc = ipmi_close_direct(); break; +#elif defined(DOS) + case DRV_SMB: + case DRV_KCS: rc = ipmi_close_direct(); break; +#else + /* BSD or MACOS */ + case DRV_MV: rc = ipmi_close_mv(); break; + case DRV_SMB: + case DRV_KCS: rc = ipmi_close_direct(); break; +#endif + case DRV_LAN: rc = ipmi_close_lan(gnode); break; + case DRV_LAN2I: + case DRV_LAN2: rc = ipmi_close_lan2(gnode); break; + default: break; + } /*end switch*/ +#endif + fDriverTyp = DRV_UNKNOWN; + return (rc); +} + +/* don't worry about conflict with other ipmi libs any longer */ +int ipmi_close(void) { return(ipmi_close_()); } + +#if defined(EFI) +int ipmi_open_efi(int fdebugcmd) +{ + int rc = 0; + static bool BmcLibInitialized = false; + + if (BmcLibInitialized == false ) { + rc = BmcLibInitialize(); + if (rc == 0) { + BmcLibInitialized = true; + fDriverTyp = DRV_EFI; + } + } + return rc; +} + +#define TIMEOUT_EFI (1000*1000) /*see ipmi_timeout_ia*/ +int ipmi_cmdraw_efi(uchar cmd, uchar netfn, uchar sa, uchar bus, uchar lun, + uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + BMC_MESSAGE ReqMsg; + BMC_MESSAGE RespMsg; + int status = 0; + uchar * pc; + int sz, i; + + ReqMsg.DevAdd = sa; + ReqMsg.NetFn = netfn; + ReqMsg.LUN = lun; + ReqMsg.Cmd = cmd; + ReqMsg.Len = sdata; + for( sz=0; (sz<sdata && sz< IPMI_REQBUF_SIZE); sz++ ) + ReqMsg.Data[sz] = pdata[sz]; + sz = *sresp; /* note that sresp must be pre-set */ + memset(presp, 0, sz); + for ( i =0 ; i < BMC_MAX_RETRIES; i++) + { + *sresp = sz; /* retries may need to re-init *sresp */ + if((status =ProcessTimedMessage(&ReqMsg, &RespMsg,TIMEOUT_EFI)) == 0) { + *sresp = RespMsg.Len; + for( sz=0 ; sz<RespMsg.Len && sz<IPMI_RSPBUF_SIZE ; sz++ ) + presp[sz] = RespMsg.Data[sz]; + *pcc = RespMsg.CompCode; + break; + } + if (fdebugcmd) // only gets here if error + fprintf(fpdbg,"ipmi_cmd_efi: ProcessTimedMessage error status=%x\n", + (uint)status); + } + return(status); +} +#endif + +/* + * ipmi_cmdraw() + * + * This routine can be used to invoke IPMI commands that are not + * already pre-defined in the ipmi_cmds array. + * It invokes whichever driver-specific routine is needed (ia, mv, etc.). + * Parameters: + * uchar cmd (input): IPMI Command + * uchar netfn (input): IPMI NetFunction + * uchar sa (input): IPMI Slave Address of the MC + * uchar bus (input): BUS of the MC + * uchar lun (input): IPMI LUN + * uchar *pdata (input): pointer to ipmi data + * int sdata (input): size of ipmi data + * uchar *presp (output): pointer to response data buffer + * int *sresp (input/output): on input, size of response buffer, + * on output, length of response data + * uchar *cc (output): completion code + * char fdebugcmd(input): flag =1 if debug output desired + */ +int ipmi_cmdraw(uchar cmd, uchar netfn, uchar sa, uchar bus, uchar lun, + uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + int rc = 0; + ushort icmd; + + fperr = stderr; + fpdbg = stdout; + + if (sdata > 255) return(LAN_ERR_BADLENGTH); + if (fDriverTyp == DRV_UNKNOWN) { /*first time, so find which one */ + rc = ipmi_open(fdebugcmd); + if (fdebugcmd) + fprintf(fpdbg,"Driver type %s, open rc = %d\n", + show_driver_type(fDriverTyp),rc); + if (rc == ERR_NO_DRV && !fipmi_lan) fprintf(fperr, "%s", msg_no_drv); + else if (rc != 0) fprintf(fperr,"ipmi_open error = %d\n", rc); + if (rc != 0) return(rc); + } /*endif first time*/ + + icmd = (cmd & 0x00ff) | (netfn << 8); + *pcc = 0; + /* Check for the size of the response buffer being zero. */ + /* This may be valid for some commands, but print a debug warning. */ + if (fdebugcmd && (*sresp == 0)) printf("ipmi_cmdraw: warning, sresp==0\n"); + +#ifdef EFI + rc = ipmi_cmdraw_efi(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); +#else + switch (fDriverTyp) + { +#ifdef WIN32 + case DRV_IMB: + rc = ipmi_cmdraw_ia(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; + case DRV_MS: + rc = ipmi_cmdraw_ms(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; +#elif defined(SOLARIS) + case DRV_BMC: + rc = ipmi_cmdraw_bmc(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; + case DRV_LIPMI: + rc = ipmi_cmdraw_lipmi(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; +#elif defined(LINUX) + case DRV_IMB: + rc = ipmi_cmdraw_ia(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; + case DRV_MV: + rc = ipmi_cmdraw_mv(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; + case DRV_LD: + rc = ipmi_cmdraw_ld( cmd, netfn, lun, sa, bus, + pdata,sdata, presp,sresp, pcc, fdebugcmd); + break; + case DRV_SMB: + case DRV_KCS: + rc = ipmi_cmdraw_direct(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; +#elif defined(DOS) + case DRV_SMB: + case DRV_KCS: + rc = ipmi_cmdraw_direct(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; +#else + /* BSD or MACOS */ + case DRV_MV: + rc = ipmi_cmdraw_mv(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; + case DRV_SMB: + case DRV_KCS: + rc = ipmi_cmdraw_direct(cmd, netfn, lun, sa, bus, pdata,sdata, + presp,sresp, pcc, fdebugcmd); + break; +#endif + case DRV_LAN: + rc = ipmi_cmdraw_lan(gnode, cmd, netfn, lun, sa, bus, + pdata,sdata, presp,sresp, pcc, fdebugcmd); + break; + case DRV_LAN2I: + case DRV_LAN2: + rc = ipmi_cmdraw_lan2(gnode, cmd, netfn, lun, sa, bus, + pdata,sdata, presp,sresp, pcc, fdebugcmd); + break; + default: /* no ipmi driver */ + rc = ERR_NO_DRV; + break; + } /*end switch*/ +#endif + + if ((rc >= 0) && (*pcc != 0) && fdebugcmd) { + fprintf(fpdbg,"ccode %x: %s\n",*pcc,decode_cc(icmd,(int)*pcc)); + } + /* clear the temp cmd (OLD) */ + // ipmi_cmds[0].cmdtyp = 0; + // ipmi_cmds[0].sa = BMC_SA; + + return(rc); +} + +/* + * ipmi_cmd_mc() + * This uses the mc pointer to route commands via either the SMI or + * IPMB method to the designated mc. + * See also ipmi_set_mc and ipmi_restore_mc. + */ +int ipmi_cmd_mc(ushort icmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + uchar cmd, netfn; + int rv; + + cmd = icmd & CMDMASK; + netfn = (icmd & 0xFF00) >> 8; + if (sdata > 255) return(LAN_ERR_BADLENGTH); + if ((fDriverTyp != DRV_MV) && (mc->adrtype == ADDR_IPMB) && !fipmi_lan) { + rv = ipmi_cmd_ipmb(cmd, netfn, mc->sa, mc->bus, mc->lun, + pdata, sdata, presp, sresp, pcc, fdebugcmd); + } else { /* use ADDR_SMI */ + rv = ipmi_cmdraw(cmd, netfn, mc->sa, mc->bus, mc->lun, + pdata, sdata, presp, sresp, pcc, fdebugcmd); + } + return(rv); +} + +int ipmi_cmdraw_mc(uchar cmd, uchar netfn, + uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + int rv; + if (sdata > 255) return(LAN_ERR_BADLENGTH); + if ((fDriverTyp != DRV_MV) && (mc->adrtype == ADDR_IPMB) && !fipmi_lan) { + rv = ipmi_cmd_ipmb(cmd, netfn, mc->sa, mc->bus, mc->lun, + pdata, sdata, presp, sresp, pcc, fdebugcmd); + } else { /* use ADDR_SMI */ + rv = ipmi_cmdraw(cmd, netfn, mc->sa, mc->bus, mc->lun, + pdata, sdata, presp, sresp, pcc, fdebugcmd); + } + return(rv); +} + +/* + * ipmi_cmd() + * + * This is the externally exposed subroutine for commands that + * are defined in the ipmi_cmds array above. + * It calls the ipmi_cmdraw routine for further processing. + */ +int ipmi_cmd(ushort icmd, uchar *pdata, int sdata, uchar *presp, + int *sresp, uchar *pcc, char fdebugcmd) +{ + int rc, i; + uchar bcmd; + uchar netfn, sa, bus, lun; + + fperr = stderr; + fpdbg = stdout; + if (sdata > 255) return(LAN_ERR_BADLENGTH); + if (fDriverTyp == DRV_UNKNOWN) { /*first time, so find which one */ + rc = ipmi_open(fdebugcmd); + if (fdebugcmd) + fprintf(fpdbg,"Driver type %s, open rc = %d\n", + show_driver_type(fDriverTyp),rc); + if (rc != 0) { + if (rc == ERR_NO_DRV && !fipmi_lan) fprintf(fperr, "%s", msg_no_drv); + else fprintf(fperr,"ipmi_open error = %d\n", rc); + return(rc); + } + } /*endif first time*/ + + for (i = 0; i < NCMDS; i++) { + if (ipmi_cmds[i].cmdtyp == icmd) break; + } + if (i >= NCMDS) { + fprintf(fperr, "ipmi_cmd: Unknown command %x\n",icmd); + return(-1); + } + bcmd = icmd & CMDMASK; /* unmask it */ + netfn = ipmi_cmds[i].netfn; + lun = ipmi_cmds[i].lun; + sa = ipmi_cmds[i].sa; + bus = ipmi_cmds[i].bus; + + rc = ipmi_cmdraw(bcmd, netfn, sa, bus, lun, + pdata,sdata, presp,sresp, pcc, fdebugcmd); + return(rc); +} + +/* MOVED ipmi_cmd_ipmb() to ipmilan.c */ + +int ipmi_getpicmg(uchar *presp, int sresp, char fdebug) +{ + uchar idata[2]; + int rc; uchar cc; + + /* check that sresp is big enough */ + if (sresp < 4) return(-3); + idata[0] = PICMG_ID; + rc = ipmi_cmdraw(PICMG_GET_PROPERTIES, NETFN_PICMG, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, 1, presp,&sresp, &cc, fdebug); + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + return(ACCESS_OK); /* success */ +} + +int ipmi_getdeviceid(uchar *presp, int sresp, char fdebug) +{ + int rc, i; uchar cc; + /* check that sresp is big enough (default is 15 bytes for Langley)*/ + if (sresp < 15) return(ERR_BAD_LENGTH); + rc = ipmi_cmd_mc(GET_DEVICE_ID, NULL, 0, presp,&sresp, &cc, fdebug); + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + i = sresp; + if (i > sizeof(my_devid)) i = sizeof(my_devid); + memcpy(my_devid,presp,i); /* save device id for later use */ + return(ACCESS_OK); /* success */ +} + +void get_devid_ver(uchar *bmaj, uchar *bmin, uchar *iver) +{ + if (bmaj != NULL) *bmaj = my_devid[2]; + if (bmin != NULL) *bmin = my_devid[3]; + if (iver != NULL) *iver = my_devid[4]; +} + +void show_devid(uchar b1, uchar b2, uchar i1, uchar i2) +{ + /* b1 = devid[2]; b2 = devid[3]; i2|i1 = devid[4]; */ + printf("-- BMC version %x.%02x%c IPMI version %d.%d \n",b1,b2,bcomma,i1,i2); +} + +void ipmi_set_mc(uchar bus, uchar sa, uchar lun, uchar atype) +{ + mc = &mc2; + mc->bus = bus; + mc->sa = sa; + mc->lun = lun; + mc->adrtype = atype; /* ADDR_SMI or ADDR_IPMB */ + if (fdebug) printf("ipmi_set_mc(%02x,%02x,%02x,%02x)\n",bus,sa,lun,atype); + return; +} + +void ipmi_restore_mc(void) +{ + mc = &bmc; + return; +} + +void ipmi_get_mc(uchar *bus, uchar *sa, uchar *lun, uchar *type) +{ + /* mc = &bmc or &mc2; */ + if (bus != NULL) *bus = mc->bus; + if (sa != NULL) *sa = mc->sa; + if (lun != NULL) *lun = mc->lun; + if (type != NULL) *type = mc->adrtype; /* ADDR_SMI or ADDR_IPMB */ + return; +} + +void ipmi_set_mymc(uchar bus, uchar sa, uchar lun, uchar type) +{ + mymc.bus = bus; + mymc.sa = sa; + mymc.lun = lun; + mymc.adrtype = type; /* ADDR_SMI or ADDR_IPMB */ + return; +} + +void ipmi_get_mymc(uchar *bus, uchar *sa, uchar *lun, uchar *type) +{ + if (bus != NULL) *bus = mymc.bus; + if (sa != NULL) *sa = mymc.sa; + if (lun != NULL) *lun = mymc.lun; + if (type != NULL) *type = mymc.adrtype; /* ADDR_SMI or ADDR_IPMB */ + return; +} + +int ipmi_sendrecv(struct ipmi_rq * req, uchar *rsp, int *rsp_len) +{ /* compatible with intf->sendrecv() */ + int rv; + uchar ccode; + int rlen; + + rlen = IPMI_RSPBUF_SIZE; + *rsp_len = 0; + rv = ipmi_cmdraw_mc(req->msg.cmd, req->msg.netfn, + req->msg.data, (uchar)req->msg.data_len, + rsp, &rlen, &ccode, fdebug); + if (rv == 0 && ccode != 0) rv = ccode; + if (rv == 0) { /*success*/ + *rsp_len = rlen; + } + return (rv); +} + +#ifdef WIN32 +static HANDLE con_in = INVALID_HANDLE_VALUE; +static DWORD cmodein; +static DWORD cmodeold; + +void tty_setraw(int mode) +{ + // system("@echo off"); + con_in = GetStdHandle(STD_INPUT_HANDLE); + GetConsoleMode(con_in, &cmodein); + cmodeold = cmodein; + if (mode == 2) { + cmodein &= ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | + ENABLE_ECHO_INPUT); + } else { /* (mode==1) just suppress ECHO */ + cmodein &= ~ENABLE_ECHO_INPUT; + } + SetConsoleMode(con_in, cmodein); +} +void tty_setnormal(int mode) +{ + // system("echo on"); + if (mode == 1) + cmodein |= ENABLE_ECHO_INPUT; + else + cmodein = cmodeold; + SetConsoleMode(con_in, cmodein); +} +int tty_getattr(int *lflag, int *oflag, int *iflag) +{ + *lflag = (int)cmodein; + *oflag = 0; + *iflag = 0; + return(0); +} +#elif defined(DOS) +void tty_setraw(int mode) +{ return; } +void tty_setnormal(int mode) +{ return; } +int tty_getattr(int *lflag, int *oflag, int *iflag) +{ return(-1); } +#else + /*LINUX, SOLARIS, BSD*/ +// #include <curses.h> +static struct termios mytty; +static struct termios ttyold; +static ulong tty_oldflags; +int tty_getattr(int *lflag, int *oflag, int *iflag) +{ + int rv; + static struct termios outtty; + rv = tcgetattr(STDOUT_FILENO, &outtty); + if (rv == 0) { + *lflag = outtty.c_lflag; + *oflag = outtty.c_oflag; + *iflag = outtty.c_iflag; + } + return(rv); +} + +void tty_setraw(int mode) +{ + int i; + // system("stty -echo"); + i = tcgetattr(STDIN_FILENO, &mytty); + if (i == 0) { + tty_oldflags = mytty.c_lflag; + ttyold = mytty; +#ifdef SOLARIS + mytty.c_iflag |= IGNPAR; + mytty.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); + mytty.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL); + mytty.c_lflag &= ~IEXTEN; + /* mytty.c_oflag &= ~OPOST; // this causes NL but no CR on output */ + mytty.c_cc[VMIN] = 1; + mytty.c_cc[VTIME] = 0; + i = tcsetattr(STDIN_FILENO, TCSADRAIN, &mytty); +#else + if (mode == 2) { /*raw mode*/ + mytty.c_lflag &= ~(ICANON | ISIG | ECHO); + // mytty.c_oflag &= ~ONLCR; /* do not map NL to CR-NL on output */ + } else /* (mode==1) just suppress ECHO */ + mytty.c_lflag &= ~ECHO; + i = tcsetattr(STDIN_FILENO, TCSANOW, &mytty); +#endif + } +} +void tty_setnormal(int mode) +{ + // system("stty echo"); + if (mode == 1) + mytty.c_lflag |= ECHO; + else { /*(mode==2)*/ + mytty.c_lflag = tty_oldflags; + mytty = ttyold; + } + tcsetattr(STDIN_FILENO, TCSANOW, &mytty); +#ifdef SOLARIS + tcsetattr(fileno(stdin), TCSADRAIN, &mytty); +#endif +} +#endif + +static char *my_getline(char *prompt, char fwipe) +{ + /* getline is the same format as readline, but much simpler, and portable. */ + static char linebuf[128]; + int c, i; + + if (prompt != NULL) printf("%s\n",prompt); + if (fwipe) tty_setraw(1); + for (i = 0; i < (sizeof(linebuf)-1); i++) + { + c = getc(stdin); + if (c == EOF) break; + if (c == '\n') break; + if ((c < 0x20) || (c > 0x7F)) break; /*out of bounds for ASCII */ + linebuf[i] = c & 0xff; + } + linebuf[i] = 0; + if (fwipe) { + for (c = 0; c < i; c++) putc('*',stdout); + putc('\n',stdout); + tty_setnormal(1); + } + if (i == 0) return NULL; + return(linebuf); +} + +static char *getline_wipe(char *prompt) +{ + return(my_getline(prompt,1)); +} + +void set_debug(void) +{ + fdebug = 1; +} + +char is_remote(void) +{ + return((char)fipmi_lan); +} + +int get_lan_options(char *node, char *user, char *pswd, int *auth, int *priv, + int *cipher, void *addr, int *addr_len) +{ + if (fipmi_lan == 0) return(-1); + if (node != NULL) strcpy(node,gnode); + if (user != NULL) strcpy(user,guser); + if (pswd != NULL) strcpy(pswd,gpswd); + if (auth != NULL) *auth = gauth_type; + if (priv != NULL) *priv = gpriv_level; + if (cipher != NULL) *cipher = gcipher_suite; + if (addr != NULL && gaddr_len != 0) memcpy(addr,gaddr,gaddr_len); + if (addr_len != NULL) *addr_len = gaddr_len; + return(0); +} + +int set_lan_options(char *node, char *user, char *pswd, int auth, int priv, + int cipher, void *addr, int addr_len) +{ + int rv = 0; + if (node != NULL) { gnode = strdup_(node); fipmi_lan = 1; } + if (user != NULL) guser = strdup_(user); + if (pswd != NULL) gpswd = strdup_(pswd); + if (auth > 0 && auth <= 5) gauth_type = auth; + else rv = ERR_BAD_PARAM; + if (priv > 0 && priv <= 5) gpriv_level = priv; + else rv = ERR_BAD_PARAM; + if (cipher >= 0 && cipher <= 17) gcipher_suite = cipher; + else rv = ERR_BAD_PARAM; + if ((addr != NULL) && (addr_len > 15) && (addr_len <= sizeof(gaddr))) { + memcpy(gaddr,addr,addr_len); + gaddr_len = addr_len; + } + ipmi_flush_lan(gnode); + return(rv); +} + +void parse_lan_options(int c, char *popt, char fdebugcmd) +{ +#if defined(EFI) | defined(DOS) + return; +#else + int i; + size_t len; + static int fset_dtype = 0; + uchar sa; + + switch(c) + { + case 'F': /* force driver type */ + i = set_driver_type(popt); + if (i == 0) fset_dtype = 1; + break; + case 'T': /* auth type */ + i = atoi(popt); + if (i >= 0 && i <= 5) gauth_type = i; + fauth_type_set = 1; + break; + case 'V': /* priv level */ + i = atoi(popt); + if (i > 0 && i <= 5) gpriv_level = i; + break; + case 'J': + i = atoi(popt); + if (i >= 0 && i <= 17) gcipher_suite = i; + else printf("-J cipher suite %d > 17, defaults to %d\n", + i,gcipher_suite); + if (fset_dtype == 0) i = set_driver_type("lan2"); + break; + case 'N': gnode = popt; /* nodename */ + fipmi_lan = 1; + break; + case 'U': + guser = strdup_(popt); /*remote username */ + if (!guser) perror("strdup_"); + else { /* Hide username from 'ps' */ + memset(popt, ' ', strlen(popt)); + } + break; + case 'R': + case 'P': + gpswd = strdup_(popt); /*remote password */ + if (!gpswd) perror("strdup_"); + else { /* Hide password from 'ps' */ + len = strlen(popt); + memset(popt, ' ', len); + if (len > PSW_MAX) gpswd[PSW_MAX] = '\0'; + } + break; + case 'E': /* get password from IPMI_PASSWORD environment var */ + gpswd = getenv("IPMI_PASSWORD"); + if (gpswd == NULL) perror("getenv(IPMI_PASSWORD)"); + else { + if (strlen(gpswd) > PSW_MAX) gpswd[PSW_MAX] = '\0'; + if (fdebugcmd) printf("using IPMI_PASSWORD\n"); + } + break; + case 'Y': /* prompt for remote password */ + gpswd = getline_wipe("Enter IPMI LAN Password: "); + if (gpswd != NULL) { + if (strlen(gpswd) > PSW_MAX) gpswd[PSW_MAX] = '\0'; + } + break; + case 'Z': /* set local MC address */ + sa = htoi(&popt[0]); /*device slave address*/ + ipmi_set_mymc(mc->bus, sa, mc->lun, ADDR_IPMB); + break; + default: + if (fdebugcmd) printf("unrecognized option %c\n",c); + break; + } + ipmi_flush_lan(gnode); +#endif +} /*end parse_lan_options*/ + +void print_lan_opt_usage(void) +{ +#if defined(EFI) | defined(DOS) + return; +#else + printf(" -N node Nodename or IP address of target system\n"); + printf(" -U user Username for remote node\n"); + printf(" -P/-R pswd Remote Password\n"); + printf(" -E use password from Environment IPMI_PASSWORD\n"); + printf(" -F force driver type (e.g. imb, lan2)\n"); + printf(" -J 0 use lanplus cipher suite 0: 0 thru 14, 3=default\n"); + printf(" -T 1 use auth Type: 1=MD2, 2=MD5(default), 4=Pswd\n"); + printf(" -V 2 use priVilege level: 2=user(default), 4=admin\n"); + printf(" -Y prompt for remote password\n"); + printf(" -Z set slave address of local MC\n"); +#endif +} /*end parse_lan_options*/ + +char *get_nodename(void) +{ + return(gnode); +} + +extern int lasterr; /*defined in ipmilan.c */ +extern void show_LastError(char *tag, int err); + +void show_outcome(char *prog, int ret) +{ + if (prog == NULL) prog = ""; + if (ret == -1 && lasterr != 0) show_LastError(prog,lasterr); + printf("%s%c %s\n",prog,bcomma,decode_rv(ret)); +} + +/* end ipmicmd.c */ |