/*---------------------------------------------------------------------------
 * Filename:   ilan.c  (was pefconfig.c)
 *
 * Author:     arcress at users.sourceforge.net
 * Copyright (c) 2009 Kontron America, Inc.
 *
 * Abstract:
 * This tool sets up the custom Platform Event Filter for the panicSEL 
 * record (0x20, OS Critical Stop) to send a PEF SNMP alert for Linux
 * panics.  It also configures the BMC LAN parameters, which are needed 
 * to support PEF alerts.
 *
 * ----------- Change History -----------------------------------------------
 * 10/16/01 Andy Cress - created
 * 10/24/01 Andy Cress - mods for SetPefEntry(0c)
 * 11/02/01 Andy Cress - added option to disable a given PefEntry
 * 11/15/01 Andy Cress - added function to GetLanEntry
 * 11/19/01 Andy Cress - added function to SetLanEntry
 * 01/18/02 Andy Cress - added GetCfgData function
 * 01/31/02 Andy Cress - converted to use ipmi_cmd_ia
 * 02/06/02 Andy Cress - removed GetCfgData
 * 02/06/02 Andy Cress - added ipmi_cmd_va 
 * 02/08/02 Andy Cress - added GetChanAcc
 * 02/14/02 Andy Cress - added Get_IPMac_Addr()
 * 02/21/02 Andy Cress - added Alert IP/MAC logic to Get_IPMac_Addr()
 * 03/21/02 Andy Cress - do SetChanAcc(0x80) with every SetChanAcc(0x40)
 * 04/15/02 Andy Cress v1.2 - fix bug with user-specified Alert IP:
 *		            (ccode=c7 on SetLanEntry(16 & 18), also
 *		            added Get_Mac() for user-specified Alert IP.
 * 04/16/02 Andy Cress v1.3 added SetUser() to set password if specified,
 *                          also changed unset mac[0] to be 0xFF, not 0.
 * 05/09/02 Andy Cress v1.4 fixed bug 504 gwymac[0]=00 (mymac overwrote it),
 *                          also fixed alert scan to pick last trapsink
 * 05/31/02 Andy Cress v1.5 for gwy mac, changed arping -c 1 to -c 2,
 *                          also get com2sec community from snmpd.conf,
 *                          set dest type for no ack, no retry,
 *                          special handling to set preset PEF entries
 * 07/02/02 Andy Cress v1.6 added more Usage text
 * 07/08/02 Andy Cress v1.7 SetUserAccess length change 
 * 08/02/02 Andy Cress v1.8  moved common ipmi_cmd() code to ipmicmd.c
 * 08/27/02 Andy Cress v1.9 fixed 0xc7 on SETUSER_ACCESS with pefconfig -P "",
 *                          show message if alert dest not found
 * 09/10/02 Andy Cress v1.10 make channel nums into defines (16)
 * 09/17/02 Andy Cress v1.11 decode Dest Addr IP (19) in decimal,
 *                           fix enable user padding in SetUser,
 *                           display new community string when setting
 * 12/09/02 Andy Cress v1.12 fix error w -C & snmpd.conf conflict
 * 01/29/03 Andy Cress v1.13 added MV OpenIPMI support
 * 02/05/03 Andy Cress v1.14 show pef entry descriptions,
 *                           added EnablePef routine
 *                           show correct Alert dest mac if -A only
 * 04/04/03 Andy Cress v1.15 add eth interface option (-i) 
 * 05/13/03 Andy Cress v1.16 fix EnablePef if startup delay not supported
 * 06/19/03 Andy Cress v1.17 added errno.h (email from Travers Carter) 
 * 07/25/03 Andy Cress v1.18 add SerialOverLan configuration
 *                           mod to SetUser, added GetBmcEthDevice,
 *                           use 'arping -I' if eth1.
 * 08/18/03 Andy Cress v1.19 Don't abort if IPMI 1.0, just skip PEF,
 *                           SetLanEntry(10 & 11) for bmc grat arp,
 *                           SetLanEntry(2) to 0x17 for auth priv
 * 09/10/03 Andy Cress v1.20 Don't enable a PEF entry if it is empty,
 *                           added -L lan_ch parameter,
 *                           scan for lan_ch in GetBmcEthDevice
 * 09/22/03 Andy Cress v1.21 Add DHCP option (-D), from Jerry Yu.
 * 12/05/03 Andy Cress v1.22 Fix auth type enables for ServerConfig
 * 12/16/03 Andy Cress v1.23 Allow flexible auth types via authmask
 * 03/19/04 Andy Cress v1.24 Change default pefnum for mBMC to 10
 * 04/15/04 Andy Cress v1.25 Init each response for channel info, avoids
 *                           0xcc error with /dev/ipmi0 due to wrong lan_ch
 * 05/05/04 Andy Cress v1.26 call ipmi_close before exit.  Note that
 *                           Get_IPMac_Addr and GetBmcEthDevice
 *                           routines need more work for WIN32.
 * 05/24/04 Andy Cress v1.27 added CHAN_ACC params for ia64
 * 06/28/04 Andy Cress v1.28 added parsing to get community from trapsink
 * 07/23/04 Andy Cress v1.29 use lan_ch variable to set Alert Policy Table
 * 08/23/04 Andy Cress v1.30 fixed decoding of PE Table entries,
 *                           added -e option (same as no params)
 * 08/25/04 Andy Cress v1.31 added some WIN32 logic to Get_Mac, Get_IPMac_Addr
 * 11/01/04 Andy Cress v1.32 add -N / -R for remote nodes   
 *                           added -U for remote username
 * 11/18/04 Andy Cress v1.33 added -u to configure a lan username (user 2)
 * 11/23/04 Andy Cress v1.34 added pef_defaults if first 11 empty
 * 01/11/05 Andy Cress v1.35 allow scan for BMC LAN if fIPMI10
 * 01/20/05 Andy Cress v1.36 fix to allow IPMI 2.0
 * 02/16/05 Andy Cress v1.37 added IPMI 2.0 VLAN parameters, 
 *                           if DHCP, can set DHCP Server via -I param
 * 03/02/05 Andy Cress v1.38 show Serial-Over-Lan params, 
 *                           fix -L with lan_ch_parm. mods to GetBmcEthDevice
 * 03/18/05 Andy Cress v1.39 fix GetBmcEthDevice for invalid MAC compares
 * 06/03/05 Andy Cress v1.40 For my MAC in BMC, check user-specified, then 
			     check existing BMC MAC, then check OS MAC.
 * 06/10/05 Andy Cress v1.41 Display multiple Alert Destinations, 
 *                           handle fSOL20 commands
 * 07/07/05 Andy Cress v1.42 Fix GetBmcEthDevice for TIGI2U to skip GCM ch 3
 * 07/08/05 Andy Cress v1.43 Mods to handle Intel NSI2U miniBMC,
 * 08/01/05 Andy Cress v1.44 added -t option to test if BMC LAN configured
 * 08/10/05 Andy Cress v1.45 truncate extra string chars,
 *                           decode more PEF params
 * 09/07/05 Andy Cress v1.46 enable mBMC PEF entries 26 thru 30
 * 04/06/06 Andy Cress v1.47 show "gcm" as ifname if -L 3.
 * 06/20/06 Andy Cress v1.48 fix strcmp(gcm), show all 4 alert policies,
 *                           add PefDesc() for misc vendor pefdesc, add -a.
 * 08/08/06 Andy Cress v1.49 add Alcolu to fsharedMAC
 * 09/29/06 Andy Cress v1.52 use bmcmymac if valid, use bmcmyip if ok, 
 *                           added -q for user number, 
 *                           enhanced Get_IPMac_Addr for Windows
 * 10/12/06 Andy Cress v1.53 FindEthNum updates, always use gwy iface for mac
 * 11/02/06 Andy Cress v1.55 add user names, EnablePef mods for non-Intel.
 * 05/02/07 Brian Johnson v1.65 add fpefenable flag to not do SetPefEntry 
 *                           if no Alert Destination.  Previously did 
 *                           SetPefEntry but not EnablePef in this case.
 * 05/04/07 Andy Cress v1.65 Use 0x02 for DHCP source instead of 0x03,
 *                           fix 1714748 missing "X:" in getopt line
 * 05/23/07 Jakub Gorgolewski 
 *                     v1.66 Use iphlpapi for Windows detection
 * 10/31/07 Andy Cress v2.3  Fixed PEF entry for Power Redundancy Lost
 * 11/15/07 Andy Cress v2.4  Move custom PEF to #14, add to usage,
 *                           Allow broadcast MAC for -X
 * 12/17/07 Andy Cress v2.5  Add fSetPEFOks & secondary Gateway
 */
/*M*
 *---------------------------------------------------------------------------
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 Kontron 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.
 *---------------------------------------------------------------------------
 *M*/
#ifdef WIN32
#include <winsock2.h>
#include <iphlpapi.h>
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "getopt.h"
#elif defined(DOS)
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "getopt.h"
#else  
/* Linux or similar */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifndef HPUX
#include <getopt.h>
#endif
#include <string.h>
#include <sys/socket.h> 
#include <sys/ioctl.h>   
#include <net/if.h>     
#include <errno.h>
#endif
#ifdef LINUX
#include <unistd.h>
#endif
#ifdef SOLARIS
#include <sys/sockio.h>
#define SIOCGIFHWADDR   SIOCGENADDR
#define ifr_netmask         ifr_ifru.ifru_addr
// #define ifr_hwaddr.sa_data  ifr_ifru.ifru_enaddr
#endif
#ifdef BSD
#include <sys/sockio.h>
#define SIOCGIFHWADDR   SIOCGIFMAC
#define ifr_netmask         ifr_ifru.ifru_addr 
// #define ifr_hwaddr.sa_data  ifr_ifru.ifru_addr 
#endif
#include "ipmicmd.h" 
#include "oem_intel.h" 
 
#define SELprintf          printf
#define RTF_UP          0x0001   /* route usable */

#define SOL_ENABLE_FLAG			0x01
#define SOL_DISABLE_FLAG		0x00
#define SOL_PRIVILEGE_LEVEL_USER	0x02
#define SOL_PREFERRED_BAUD_RATE		0x0a  /*115.2k*/
/* For IPMI 1.5, use Intel SOL commands & subfunctions */
#define SOL_ENABLE_PARAM		0x01
#define SOL_AUTHENTICATION_PARAM 	0x02
#define SOL_ACC_INTERVAL_PARAM	 	0x03
#define SOL_RETRY_PARAM  	 	0x04
#define SOL_BAUD_RATE_PARAM		0x05  /*non-volatile*/
#define SOL_VOL_BAUD_RATE_PARAM		0x06  /*volatile*/
/* For IPMI 2.0, use IPMI SOL commands & subfunctions */
#define SOL_ENABLE_PARAM2		0x08
#define SOL_AUTHENTICATION_PARAM2 	0x09
#define SOL_BAUD_RATE_PARAM2		0x11

/* IPMI 2.0 SOL PAYLOAD commands */
#define SET_PAYLOAD_ACCESS  0x4C
#define GET_PAYLOAD_ACCESS  0x4D
#define GET_PAYLOAD_SUPPORT 0x4E

/* Channel Access values */
#define CHAN_ACC_DISABLE   0x20   /* PEF off, disabled*/
#define CHAN_ACC_PEFON     0x02   /* PEF on, always avail */
#define CHAN_ACC_PEFOFF    0x22   /* PEF off, always avail*/
/* special channel access values for ia64 */
#define CHAN_ACC_PEFON64   0x0A   /* PEF on, always avail, UserLevelAuth=off */
#define CHAN_ACC_PEFOFF64  0x2A   /* PEF off, always avail, UserLevelAuth=off */
#define OS_LINUX          1
#define OS_WINDOWS        2
#define OS_SOLARIS        3
#define OS_BSD            4
#define OS_HPUX           5

   /* TSRLT2 Channels: 0=IPMB, 1=Serial/EMP, 6=LAN2, 7=LAN1 */
   /* S5000 Channels: 0=IPMB, 1=LAN1, 2=LAN2, 3=RMM2, 4=Serial, 6=pci, 7=sys */
   /* For TIGPT1U/mBMC: 1=LAN channel, no serial */
#define LAN_CH   1  
#define SER_CH   4
#define MAXCHAN  12  /*was 16, reduced for gnu ipmi_lan*/
#define NUM_DEVICES_TO_CHECK		32   /*for GetBmcEthDevice()*/
#define MAC_LEN  6   /*length of MAC Address*/
#define PSW_LEN  16  /* see also PSW_MAX =20  in ipmicmd.h*/
/* Note: The optional IPMI 2.0 20-byte passwords are not supported here, 
 * due to back-compatibility issues. */

   /* IP address source values */
#define SRC_STATIC 0x01
#define SRC_DHCP   0x02  /* BMC running DHCP */
#define SRC_BIOS   0x03  /* BIOS, sometimes DHCP */
#define SRC_OTHER  0x04

/* PEF event severities */
#define PEF_SEV_UNSPEC   0x00
#define PEF_SEV_MON      0x01
#define PEF_SEV_INFO     0x02
#define PEF_SEV_OK       0x04
#define PEF_SEV_WARN     0x08
#define PEF_SEV_CRIT     0x10
#define PEF_SEV_NORECOV  0x20
#define FLAG_INIT  99  /*initial value of char flag, beyond scope*/
#define PARM_INIT  0xff

typedef struct
{            /* See IPMI Table 15-2 */
        uchar              rec_id;
        uchar              fconfig;
        uchar              action;
        uchar              policy;
        uchar              severity;
        uchar              genid1;
        uchar              genid2;
        uchar              sensor_type;
        uchar              sensor_no;
        uchar              event_trigger;
        uchar              data1;
        uchar              mask1;
        uchar              res[9];
}       PEF_RECORD;

typedef struct
{            /* See IPMI Table 19-3 */
        uchar              data[36];
}       LAN_RECORD;   /*LanRecord*/

#ifdef METACOMMAND
extern int get_lan_stats(uchar chan);  /*see bmchealth.c */
extern char *get_sensor_type_desc(uchar stype);  /*from ievents.c*/
#endif

#define MYIP   0x01
#define GWYIP  0x02
#define DESTIP 0x04
#define MAXPEF 41	 	/* max pefnum offset = 40 (41 entries) */
/*
 * Global variables 
 */
static char * progver   = "2.84";
static char * progname  = "ilan";
static char   fdebug    = 0;
static char   fipmilan  = 0;
static char   fIPMI10   = 0;      /* =1 if IPMI v1.0 or less */
static char   fIPMI20   = 0;      /* =1 if IPMI v2.0 or greater */
static char   fSOL20    = 1;      /* =1 if use Serial-Over-Lan 2.0 w IPMI 2.0 */
static char   fsharedMAC = 0;     /* =1 if special shared-MAC BMC LAN port */
static char   fAdjustPefNum = 0;  /* =1 adjust pefnum to first empty index */
static char   fUserPefNum = 0;    /* =1 if user specified a valid pefnum value*/
static char   freadonly = 1;      /* =1 to only read LAN & PEF parameters */
static char   fcanonical = 0;     /* =1 to show only canonical output */
static char   bdelim = BCOLON;    /* delimiter ':' or '|' if canonical output*/
static char   ftestonly = 0;
static char   fprivset  = 0;
static char   flanstats = 0;      /* =1 to show the IPMI LAN statistics */
static char   foptmsg    = 0;     /* =1 to show the option warning msg */
static char   nopts      = 0;     /* number of pefconfig options specified*/
static int    nerrs      = 0;     /* number of errors during processing */
static int    ngood      = 0;     /* number of good results */
static int    lasterr    = 0;     /* value of the last error */
static char   fCustomPEF = 0;     /* =1 if -j to input a custom PEF record */
static char   fSetPEFOks = 0;     /* =1 if -k to set PEF OK rules */
static char   fdisable  = 0;
static char   fenable   = 0;      /* =1 to config BMC LAN and PEF */
static char   fpefenable = 0;     /* =1 enable PEF if Alert Dest is specified*/
static char   fdisableSOL = 0;
static char   fgetser   = 0;
static char   fsetifn   = 0;	  /* =1 if user specified ifname[] with -i */
static char   fethfound = 0;      /* =1 if FindEthNum successful */
static char   fset_ip   = 0;	 /* !=0 if options used to specify an IP addr*/
static char   fpassword = 0;	  /* =1 user-specified a password, so set it. */
static uchar  fmBMC     = 0;      /* =1 mini-BMC, =0 Sahalee BMC */
static uchar  fiBMC     = 0;      /* =1 Intel iBMC */
static uchar  fRomley   = 0;      /* =1 Intel Romley BMC */
static uchar  fipv6     = 0;      /* =1 if BMC supports IPv6 */
static uchar  bmcpefctl  = 0;     /* existing BMC PEF Control, !0 = enabled */
static char   alertnum  = 1;      /* alert dest num (usu 1 thru 4) */
static char   alertmax  = 9;      /* alert dest num max (usu 4, error if >9) */
static char   pefnum    = 12;     /* 11 pre-defined entries, adding 12th */
static char   pefadd    = 0;      /* num PEF rules added (usu 2, could be 5 */
static char   pefmax    = MAXPEF; /* 20 for Sahalee, 30 for miniBMC */
static char  *myuser    = NULL;   /* username to set, specified by -u */
static uchar  usernum   = 0;      /* set non-zero to specify user number */
static uchar  rgmyip[4]    = {0,0,0,0};
static uchar  rggwyip[4]   = {0,0,0,0};
static uchar  rggwy2ip[4]  = {0,0,0,0};
static uchar  rgdestip[4]  = {0,0,0,0};
static uchar  rgsubnet[4]  = {0,0,0,0};
static uchar  bmcsubnet[4] = {255,255,255,0};  /* default subnet */
static uchar  ossubnet[4]  = {0,0,0,0}; 
static uchar  osmyip[4]    = {0,0,0,0};
static uchar  bmcmyip[4]   = {0,0,0,0};
static uchar  bmcdestip[4] = {0,0,0,0};
static uchar  bmcdestmac[6]= {0xff,0,0,0,0,0};
static uchar  bmcmymac[6]  = {0xff,0,0,0,0,0};
static uchar  rgmymac[6]   = {0xff,0,0,0,0,0};
static uchar  osmymac[6]   = {0xff,0,0,0,0,0};
static uchar  rggwymac[6]  = {0xff,0,0,0,0,0};
static uchar  rggwy2mac[6] = {0xff,0,0,0,0,0};
static uchar  rgdestmac[6] = {0xff,0,0,0,0,0};
static uchar  rgdhcpmac[6] = {0xff,0,0,0,0,0};
static char   rghostname[32] = {'\0'};
static uchar  custPEF[20];   /* max used = 18 bytes */
static char   rgcommunity[19] = "public";  /* default community */
static char   fsetcommunity = 0;    /* =1 if user-specified community */
static char   passwordData[PSW_MAX+1] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 
static uchar  authmask      = 0;    /* usu 0x17, mBMC = 0x15 */
static uchar  bAuth         = 0x16; /*exclude auth=None for security*/
static uchar  lan_access    = 0x04;   /* usu 4=Admin, 3=Operator, 2=User */
static uchar  lan_user      = 0x02;   /* if -u specified, use user 2 for lan */
static uchar  arp_interval  = 0x04;   /* in 500 ms increments, 0-based */
static uchar  arp_ctl       = 0x01;   /* 01=grat arp, 02=arp resp, 03=both*/
static uchar  fsetarp       = 0;      /* 1=user-specified arp_ctl */
#ifdef WIN32
static uchar  ostype        = OS_WINDOWS;  /*windows*/
static char   ifname[64]    = "Local Area Connection "; /* interface name */
static char   ifpattn[25]   = "Local Area Connection ";
#elif SOLARIS
/* for i86pc use "e1000g0", but for sun4u(sparc) this might be "eri0" */
static uchar  ostype        = OS_SOLARIS;  
#ifdef __SPARC__
static char   ifname[16]    = "eri0"; /* SPARC interface name */
static char   ifname0[16]   = "eri0"; 
static char   ifpattn[14]    = "eri";
#else
static char   ifname[16]    = "e1000g0"; /* Solaris x86 interface name */
static char   ifname0[16]   = "e1000g0"; 
static char   ifpattn[14]    = "e1000g";
#endif
#elif defined(BSD)
static uchar  ostype        = OS_BSD;  
static char   ifname[16]    = "em0"; /* interface name */
static char   ifname0[16]   = "em0"; 
static char   ifpattn[14]    = "em";
#elif defined(HPUX)
static uchar  ostype        = OS_HPUX;  
static char   ifname[16]    = "lan0"; /* interface name */
static char   ifname0[16]   = "lan0"; 
static char   ifpattn[14]    = "lan";
#else
static uchar  ostype        = OS_LINUX;  
static char   ifname[16]    = "eth0"; /* interface name */
static char   ifname0[16]   = "eth0"; 
static char   ifpattn[14]    = "eth";
#endif
static char  *pspace1 = "\t";  /*used for fcanonical output*/
static char  *pspace2 = "\t\t";
static char  *pspace3 = "\t\t\t";
static char  *pspace4 = "\t\t\t\t";
static int    vend_id;
static int    prod_id;
static int    lan_dhcp      = 0;      /*=1 if using DHCP for bmc lan channel*/
static uchar  ser_ch        = SER_CH;
static uchar  lan_ch        = LAN_CH;
static uchar  lan_ch_parm   = PARM_INIT;
static uchar  gcm_ch        = PARM_INIT;
static uchar  vlan_enable   = PARM_INIT;
static uchar  failover_enable = PARM_INIT;
static uchar  vlan_prio     = 0;  /*default = 0*/
static ushort vlan_id       = 0;  /*max 12 bits used*/
static uchar  max_users     = 5;  /* set in GetUser(1); */
static uchar  enabled_users = 0;  /* set in GetUser(1); */
static uchar  show_users    = 5;  /* default, adjusted based on DeviceID  */
static uchar  fnewbaud      = 0;  /* =1 if user specified baud */
static uchar  sol_baud      = SOL_PREFERRED_BAUD_RATE; /*115.2k default*/
static uchar  sol_accum[2] = { 0x04, 0x32 };
static uchar  sol_retry[2] = { 0x06, 0x14 };
static uchar  sol_bvalid    = 0;  /* =1 if SOL baud is valid */
static uchar  chan_pefon    = CHAN_ACC_PEFON;
static uchar  chan_pefoff   = CHAN_ACC_PEFOFF;
static uchar  SessInfo[18];     /* Session Info data */
// static uchar  bparm7[3] = {0x00, 0x00, 0x00}; /*ipv4 header before*/
static uchar  iparm7[3] = {0x1E, 0x00, 0x00}; /*intel ipv4 TTL,Flags,Service*/
static uchar  oparm7[3] = {0x40, 0x40, 0x10}; /*other ipv4 TTL,Flags,Service*/
static uchar *parm7 = &oparm7[0];
#define MAX_PEFPARAMS  14	/* max pef params = 14 */
uchar peflen[MAX_PEFPARAMS] = {0,1,1,1,1,1,21,2,1,4,17,1,3,18}; /*for ShowPef*/
uchar pef_array[MAXPEF][21];    /* array of all PEF entries read, */
                                /* sizeof(PEF_RECORD) = 21  */
uchar pef_defaults[11][21] = {  /* array of first 11 default PEF entries */
0x01,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x01,0xff,0x01,0x95,0x0a,0,0,0,0,0,0,0,0,0, /*Temp*/
0x02,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x02,0xff,0x01,0x95,0x0a,0,0,0,0,0,0,0,0,0, /*Volt*/
0x03,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x04,0xff,0x01,0x95,0x0a,0,0,0,0,0,0,0,0,0, /*Fan*/
0x04,0x80,1,1,PEF_SEV_WARN,0xff,0xff,0x05,0x05,0x03,0x01,0x00,0,0,0,0,0,0,0,0,0, /*Chass*/
0x05,0x80,1,1,PEF_SEV_WARN,0xff,0xff,0x08,0xff,0x6f,0x06,0x00,0,0,0,0,0,0,0,0,0, /*PS*/
0x06,0x80,1,1,PEF_SEV_WARN,0xff,0xff,0x0c,0x08,0x6f,0x02,0x00,0,0,0,0,0,0,0,0,0, /*ECC*/
0x07,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x0f,0x06,0x6f,0x01,0x00,0,0,0,0,0,0,0,0,0, /*FRB*/
0x08,0x80,1,1,PEF_SEV_WARN,0xff,0xff,0x07,0xff,0x6f,0x1c,0x00,0,0,0,0,0,0,0,0,0, /*POST*/
0x09,0x80,1,1,PEF_SEV_CRIT,0xff,0xff,0x13,0xff,0x6f,0x3e,0x03,0,0,0,0,0,0,0,0,0, /*NMI*/
0x0a,0x80,1,1,PEF_SEV_INFO,0xff,0xff,0x23,0x03,0x6f,0x0e,0x00,0,0,0,0,0,0,0,0,0, /*WDT*/
0x0b,0x80,1,1,PEF_SEV_MON,0xff,0xff,0x12,0xff,0x6f,0x02,0x00,0,0,0,0,0,0,0,0,0 };/*Restart*/

char **pefdesc;
char *pefdesc1[MAXPEF] = {    /* for Sahalee BMC */
/* 0 0x00 */ "",
/* 1 0x01 */ "Temperature Sensor",
/* 2 0x02 */ "Voltage Sensor",
/* 3 0x04 */ "Fan Failure",
/* 4 0x05 */ "Chassis Intrusion",
/* 5 0x08 */ "Power Supply Fault",
/* 6 0x0c */ "Memory ECC Error",
/* 7 0x0f */ "BIOS POST Error",
/* 8 0x07 */ "FRB Failure",
/* 9 0x13 */ "Fatal NMI",
/*10 0x23 */ "Watchdog Timer Reset",
/*11 0x12 */ "System Restart",
/*12 0x20 */ "OS Critical Stop",
/*13 0x09 */ "Power Redundancy Lost",
/*14 0x00 */ "reserved",
/*15 0x00 */ "reserved",
/*16 0x00 */ "reserved",
/*17 */ "reserved",
/*18 */ "reserved",
/*19 */ "reserved",
/*20 */ "reserved",
/*21 */ "reserved",
/*22 */ "reserved",
/*23 */ "reserved",
/*24 */ "reserved",
/*25 */ "reserved",
/*26 */ "reserved",
/*27 */ "reserved",
/*28 */ "reserved",
/*29 */ "unused",
/*30 */ "unused" };

char *pefdesc2[MAXPEF] = {    /* for NSC miniBMC */
/* 0 */ "",
/* 1 0x02*/ "Voltage Sensor Assert",
/* 2 0x23*/ "Watchdog FRB Timeout",  /* was "Proc FRB Thermal", */
/* 3 0x02*/ "Voltage Sensor Deassert",
/* 4 0x07*/ "Proc1 IERR",
/* 5 0xff*/ "Digital Sensor OK",
/* 6 0x14*/ "Chassis Identify",
/* 7 0x13*/ "NMI Button",
/* 8 0x14*/ "Clear CMOS via Panel",
/* 9 0x0f*/ "OS Load POST Code",
/*10 0x20*/ "OS Critical Stop",
/*11 0x09 */ "Power Redundancy Lost",
/*12 0x00*/ "reserved",
/*13 */ "reserved",
/*14 */ "reserved",
/*15 */ "reserved",
/*16 */ "reserved",
/*17 */ "reserved",
/*18 */ "reserved",
/*19 */ "reserved",
/*20 */ "reserved",
/*21 */ "reserved",
/*22 */ "reserved",
/*23 */ "reserved",
/*24 */ "reserved",
/*25 */ "reserved",
/*26 0x05*/ "Chassis Intrusion",
/*27 0x0f*/ "POST Code Error",
/*28 0x02*/ "Voltage Failure",
/*29 0x04*/ "Fan Failure",
/*30 0x01*/ "Temperature Failure"};

#define NLAN  39
char canon_param[NLAN] = { 0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,1,0,0,1,
			   0,0,0,0,0,0,1,1,1,1};
struct {
  int cmd;
  int sz;
  char desc[28];
} lanparams[NLAN] = {   /* see IPMI Table 19-4 */
 /*  0 */  0, 1, "Set in progress",
 /*  1 */  1, 1, "Auth type support",
 /*  2 */  2, 5, "Auth type enables",
 /*  3 */  3, 4, "IP address",
 /*  4 */  4, 1, "IP addr src",  /* (DHCP/Static) */
 /*  5 */  5, 6, "MAC addr",
 /*  6 */  6, 4, "Subnet mask",
 /*  7 */  7, 3, "IPv4 header",
 /*  8 */  8, 2, "Prim RMCP port",
 /*  9 */  9, 2, "Sec RMCP port",
 /* 10 */ 10, 1, "BMC grat ARP",
 /* 11 */ 11, 1, "grat ARP interval",
 /* 12 */ 12, 4, "Def gateway IP",
 /* 13 */ 13, 6, "Def gateway MAC",
 /* 14 */ 14, 4, "Sec gateway IP",
 /* 15 */ 15, 6, "Sec gateway MAC",
 /* 16 */ 16,18, "Community string",
 /* 17 */ 17, 1, "Num dest",
 /* 18 */ 18, 5, "Dest type",
 /* 19 */ 19, 13, "Dest address",
 /* 20 */ 20, 2,  "VLAN ID",
 /* 21 */ 21, 1,  "VLAN Priority",
 /* 22 */ 22, 1,  "Cipher Suite Support",
 /* 23 */ 23,17,  "Cipher Suites",
 /* 24 */ 24, 9,  "Cipher Suite Privilege",
 /* 25 */ 25, 4,  "VLAN Dest Tag",
 /* 26 */ 96, 28, "OEM Alert String",
 /* 27 */ 97,  1, "Alert Retry Algorithm",
 /* 28 */ 98,  3, "UTC Offset",
 /* 29 */ 102, 1, "IPv6 Enable",
 /* 30 */ 103, 1, "IPv6 Addr Source",
 /* 31 */ 104,16, "IPv6 Address",
 /* 32 */ 105, 1, "IPv6 Prefix Len",
 /* 33 */ 106,16, "IPv6 Default Gateway",
 /* 34 */ 108,17, "IPv6 Dest address",
 /* 35 */ 192, 4, "DHCP Server IP",
 /* 36 */ 193, 6, "DHCP MAC Address",
 /* 37 */ 194, 1, "DHCP Enable",
 /* 38 */ 201, 2, "Channel Access Mode(Lan)"
};

#define NSER  22   /* max=32 */
struct {
  int cmd;
  int sz;
  char desc[28];
} serparams[NSER] = {   /* see IPMI Table 20-4 */
 /*  0 */  0, 1, "Set in progress",
 /*  1 */  1, 1, "Auth type support",
 /*  2 */  2, 5, "Auth type enables",
 /*  3 */  3, 1, "Connection Mode",
 /*  4 */  4, 1, "Sess Inactiv Timeout",
 /*  5 */  5, 5, "Channel Callback",
 /*  6 */  6, 1, "Session Termination",
 /*  7 */  7, 2, "IPMI Msg Comm",
 /*  8 */  8, 2, "Mux Switch",
 /*  9 */  9, 2, "Modem Ring Time",
 /* 10 */ 10,17, "Modem Init String",
 /* 11 */ 11, 5, "Modem Escape Seq",
 /* 12 */ 12, 8, "Modem Hangup Seq",
 /* 13 */ 13, 8, "Modem Dial Command",
 /* 14 */ 14, 1, "Page Blackout Interval",
 /* 15 */ 15,18, "Community String",
 /* 16 */ 16, 1, "Num of Alert Dest",
 /* 17 */ 17, 5, "Destination Info",
 /* 18 */ 18, 1, "Call Retry Interval",
 /* 19 */ 19, 3, "Destination Comm Settings",
 /* 20 */ 29, 2, "Terminal Mode Config",
 /* 21 */ 201, 2,"Channel Access Mode (Ser)"
};

static void getauthstr(uchar auth, char *s)
{
     if (s == NULL) return;
     s[0] = 0;
     if (auth & 0x01) strcat(s,"None ");
     if (auth & 0x02) strcat(s,"MD2 ");
     if (auth & 0x04) strcat(s,"MD5 ");
     if (auth & 0x10) strcat(s,"Pswd ");
     if (auth & 0x20) strcat(s,"OEM ");
     return;
}

static int GetDeviceID(LAN_RECORD *pLanRecord)
{
	uchar responseData[MAX_BUFFER_SIZE];
	int responseLength = MAX_BUFFER_SIZE;
	int status;
	uchar inputData[24];
	uchar completionCode;

	if (pLanRecord == NULL) return(-1);

        status = ipmi_cmd(GET_DEVICE_ID, inputData, 0, responseData,
                        &responseLength, &completionCode, fdebug); 

	if (status == ACCESS_OK) {
		if( completionCode ) {
			SELprintf("GetDeviceID: completion code=%x\n", 
				completionCode); 
			status = completionCode;
		} else {
			memcpy(pLanRecord,&responseData[0],responseLength);
			set_mfgid(&responseData[0],responseLength);
			return(0);  // successful, done
		}
	}  /* endif */
	/* if get here, error */
 	return(status);
}  /*end GetDeviceID() */

static int GetChanAcc(uchar chan, uchar parm, LAN_RECORD *pLanRecord)
{
	uchar responseData[MAX_BUFFER_SIZE];
	int responseLength = MAX_BUFFER_SIZE;
	int status;
	uchar inputData[24];
	uchar completionCode;

	if (pLanRecord == NULL) return(-1);
	responseLength = 3;
	inputData[0] = chan;
	inputData[1] = parm;  /* 0x80 = active, 0x40 = non-volatile */
	responseLength = sizeof(responseData);
        status = ipmi_cmd(GET_CHANNEL_ACC, inputData, 2, responseData,
                        &responseLength, &completionCode, fdebug); 

	if (status == ACCESS_OK) {
		if( completionCode ) {
			SELprintf("GetChanAcc: completion code=%x\n", 
				completionCode); 
			status = completionCode;
		} else {
			// dont copy first byte (Parameter revision, usu 0x11)
			memcpy(pLanRecord,&responseData[0],responseLength);
			return(0);  // successful, done
		}
	}  /* endif */
	/* if get here, error */
 	return(status);
}  /*GetChanAcc()*/

static int SetChanAcc(uchar chan, uchar parm, uchar val)
{
	uchar responseData[MAX_BUFFER_SIZE];
	int responseLength = MAX_BUFFER_SIZE;
	int status;
	uchar inputData[24];
	uchar completionCode;

	if (fmBMC) return(0);  /* mBMC doesn't support this */
        /* parm: 0x80 = active, 0x40 = set non-vol*/
	responseLength = 1;
	inputData[0] = chan;  /* channel */
	inputData[1] = (parm & 0xc0) | (val & 0x3F); 
	inputData[2] = (parm & 0xc0) | lan_access; /* set priv level to Admin */

	responseLength = sizeof(responseData);
        status = ipmi_cmd(SET_CHANNEL_ACC, inputData, 3, responseData,
                        &responseLength, &completionCode, fdebug); 

	if (status == ACCESS_OK) {
		if( completionCode ) {
			SELprintf("SetChanAcc: completion code=%x\n", 
				completionCode); 
			status = completionCode;
		} else {
			return(0);  // successful, done
		}
	}  /* endif */
	/* if get here, error */
 	return(status);
}  /*SetChanAcc()*/

int
SetPasswd(int unum, char *uname, char *upswd)
{
   uchar responseData[MAX_BUFFER_SIZE];
   int responseLength = MAX_BUFFER_SIZE;
   int status, i, psw_len;
   uchar completionCode;
   char  inputData[24];
   int ret = 0;

	inputData[0] = (uchar)unum;  /*user 1 = null user */
	responseLength = sizeof(responseData);
        status = ipmi_cmd(GET_USER_NAME, inputData, 1, responseData, 
		        &responseLength, &completionCode, fdebug);
        SELprintf("GET_USERNAME: %x %x %x, status = %x, ccode=%x\n",
                responseData[0],responseData[1],responseData[2],
		status,completionCode);
	if (fdebug) {
		char aname[17];
                printf("User %d: ",unum);
		for (i = 0; i < responseLength; i++) {
                   printf("%02x ",responseData[i]);
		   if (responseData[i] < 0x20) aname[i] = '.';
		   else aname[i] = responseData[i];
		}
		aname[16] = 0;
                printf(" %s\n",aname);
	}

	if (unum != 1) 
        {   /* user specified a lan username */
	   if (fiBMC && (unum == 2)) {
	      if (uname != NULL) {
		if (strcmp(uname,"root") != 0) 
                   printf("SETUSERNAME - user2 name %s must be root\n",uname);
	      }
	   } else {
	      inputData[0] = (uchar)unum;
              memset(&inputData[1],0,16);
	      if (uname != NULL)
                 memcpy(&inputData[1],uname,strlen(uname));
              status = ipmi_cmd(SET_USER_NAME, inputData, 17, responseData, 
		           &responseLength, &completionCode, fdebug);
	      if (completionCode == 0xCC) 
		status = 0;  /*setting username to previous gives 0xCC, ok*/
	      else {
                SELprintf("SETUSERNAME - %x %x %x  status = %x, ccode=%x\n",
                   inputData[0],inputData[1],inputData[2],
	   	   status,completionCode);
	        if (status == 0) status = completionCode;
	        if (status != 0) ret = status;
	      }
	   }
	}

	if ((unum != 1) && (uname == NULL)) {
	   ;  /* if no username, do not enable user */
	} else {
           inputData[0] = (uchar)unum;  /*user 1 = null user */
           inputData[1] = 0x01;  /*enable user*/
	   responseLength = sizeof(responseData);
           status = ipmi_cmd(SET_USER_PASSWORD, inputData, 2, responseData, 
		        &responseLength, &completionCode, fdebug);
           printf("SETUSERENAB - inputData %x %x %x, status = %x, ccode=%x\n",
                inputData[0],inputData[1],inputData[2],
		status,completionCode);
	   if (status == 0) status = completionCode;
	   if (status != 0) ret = status;
	}

         inputData[0] = (uchar)unum;  /*user 1 = null user */
         inputData[1] = 0x02;  /*set password*/
         memset(&inputData[2],0,PSW_LEN);
	 if (upswd != NULL)
	    strcpy(&inputData[2],upswd);
	 psw_len = 16;   /*change if 20-byte passwords supported */
	 if (fdebug) {
		char apsw[PSW_LEN+1];
		char c;
                printf("Pswd %d: ",unum);
		for (i = 0; i < PSW_LEN; i++) {
		   c = inputData[i+2];
                   printf("%02x ",(unsigned char)c);
		   if (c < 0x20) apsw[i] = '.';
		   else apsw[i] = c;
		}
		apsw[PSW_LEN] = 0;
                printf(" %s\n",apsw);
	 }
	 responseLength = sizeof(responseData);
         status = ipmi_cmd(SET_USER_PASSWORD, inputData, 2+PSW_LEN, 
			responseData,&responseLength, &completionCode,fdebug);
         SELprintf("SETUSERPSW - inputData %x %x %x, status = %x, ccode=%x\n",
                inputData[0],inputData[1],inputData[2],
		status,completionCode);
	 if (status == 0) status = completionCode;
	 if (status != 0) ret = status;

         inputData[0] = (uchar)unum;  /*user 1 = null user */
         inputData[1] = 0x03;  /*test password*/
         memset(&inputData[2],0,PSW_LEN);
	 if (upswd != NULL) 
	    strcpy(&inputData[2],upswd);
	 responseLength = sizeof(responseData);
         status = ipmi_cmd(SET_USER_PASSWORD, inputData, 2+PSW_LEN, 
			responseData,&responseLength, &completionCode,fdebug);
         SELprintf("TESTUSERPSW - inputData %x %x %x, status = %x, ccode=%x\n",
                inputData[0],inputData[1],inputData[2],
		status,completionCode);

	if (fiBMC && (unum == 2)) { /*iBMC doesn't support this on user 2*/
	    if (fdebug)
		printf("skipping SETUSER_ACCESS on iBMC for user %d\n",unum);
	} else {
           inputData[0] = 0x90 | lan_ch;   /* = 0x97 */
           inputData[1] = (uchar)unum;   /* user num */
           inputData[2] = lan_access;  /* usu admin */
           inputData[3] = 0x00;   /* User Session Limit, 0=not limited*/
	   responseLength = sizeof(responseData);
           status = ipmi_cmd(SET_USER_ACCESS, inputData, 4, responseData,
                           &responseLength, &completionCode, fdebug);
           printf("SETUSER_ACCESS - inputData %x %x %x, status = %x ccode=%x\n",
		   (uchar)inputData[0],inputData[1],inputData[2],
		   status,completionCode);
	   if (status == 0) status = completionCode;
	   if (status != 0) ret = status;
	}

   return(ret);
}  /*end SetPswd()*/

int SetUser(int unum, char *uname, char *passwd)
{
      int ret = 0; 
      /* if the user specified a username or password, set it. */
      if ((fpassword) || (uname != NULL)) {
	   ret = SetPasswd(unum, uname,passwd); /*set username and password*/
      }
      return(ret);
}  /*end SetUser()*/

int
DisableUser(int unum)
{
   uchar responseData[MAX_BUFFER_SIZE];
   int responseLength = MAX_BUFFER_SIZE;
   int status;
   uchar completionCode;
   char  inputData[24];

   inputData[0] = 0x80 | lan_ch;   /* = 0x87, no IPMI */
   inputData[1] = (uchar)unum;   /* user 1 */
   inputData[2] = 0x0F;   /* No access  */
   inputData[3] = 0x00;   /* User Session Limit, 0=not limited*/
   responseLength = sizeof(responseData);
   status = ipmi_cmd(SET_USER_ACCESS, inputData, 4, responseData,
                     &responseLength, &completionCode, fdebug);
   if (status == 0) status = completionCode;
   return(status);
}

static void show_priv(uchar c)
{
            c = (c & 0x0f);
            switch(c) {
		case 1:    printf("Callback"); break;
		case 2:    printf("User  "); break;
		case 3:    printf("Operator"); break;
		case 4:    printf("Admin "); break;
		case 5:    printf("OEM   "); break;
		case 0x0f: printf("No access"); break;
		default:   printf("Reserved");
            }
}

static int valid_priv(int c)
{
	int rv;
        switch(c) {
		case 1:  
		case 2: 
		case 3: 
		case 4: 
		case 5: 
		case 0x0f: 
		    rv = 1;
		    break;
		default:  
		    rv = 0;
		    break;
	}
	return rv;
}

int GetUser(uchar user_num)
{
      uchar responseData[MAX_BUFFER_SIZE];
      int responseLength = MAX_BUFFER_SIZE;
      int status;
      uchar completionCode;
      char  inputData[24];

         inputData[0] = lan_ch;
         inputData[1] = user_num;  /* usually = 1 for BMC LAN */
	 responseLength = sizeof(responseData);
         status = ipmi_cmd(GET_USER_ACCESS, inputData, 2, responseData,
                        &responseLength, &completionCode, fdebug);
	 if (status == 0 && completionCode == 0) {
	    uchar c;
	    if (user_num == 1) { /*get max_users and enabled_users*/
		max_users = responseData[0] & 0x3f;
		enabled_users = responseData[1] & 0x3f;
		if (enabled_users > show_users) show_users = enabled_users;
		if (show_users > max_users) show_users = max_users;
		if (!fcanonical)
                  SELprintf("Users:  showing %d of max %d users (%d enabled)\n",
			  show_users,max_users,enabled_users);
	    }
	    if (fcanonical) 
              SELprintf("Channel %d User %d Access %s%c ", lan_ch, user_num,
			pspace2,bdelim);
	    else 
              SELprintf("User Access(chan%d,user%d): %02x %02x %02x %02x : ",
			lan_ch, user_num, (uchar)responseData[0],
			responseData[1],responseData[2], responseData[3]);
	    c = responseData[3];
            inputData[0] = user_num;  /* usually = 1 for BMC LAN */
	    responseLength = sizeof(responseData);
            status = ipmi_cmd(GET_USER_NAME, inputData, 1, responseData, 
	 	        &responseLength, &completionCode, fdebug);
	    if (status != 0 || completionCode != 0) 
                responseData[0] = 0;
            if (c & 0x10) printf("IPMI, ");
            show_priv(c);
            printf(" (%s)\n",responseData);  /*show user name */
	 } else 
            SELprintf("Get User Access(%d,%d), status=%x, ccode=%x\n",
			lan_ch, user_num, status, completionCode);
	return(status);
}  /*end GetUser()*/

static int GetSerEntry(uchar subfunc, LAN_RECORD *pLanRecord)
{
	uchar responseData[MAX_BUFFER_SIZE];
	int responseLength = MAX_BUFFER_SIZE;
	uchar inputData[24];
	int status;
	uchar completionCode;
	uchar chan; uchar bset;

	if (pLanRecord == NULL)
	{
	   if (fdebug)
	      printf("GetSerEntry(%d): error, output buffer is NULL\n",subfunc);
 	   return (-1);
	}

        chan = ser_ch;  /* 1=EMP, 0=IPMB, 6=LAN2, 7=LAN1 */
	bset = 0;

	inputData[0]            = chan;  // flags, channel 3:0 (1=EMP)
	inputData[1]            = subfunc;  // Param selector 
	inputData[2]            = bset;  // Set selector 
	inputData[3]            = 0;  // Block selector
	if (subfunc == 10)  {
	   inputData[2] = 0;
	   inputData[3] = 1;
 	}

        status = ipmi_cmd(GET_SER_CONFIG, inputData, 4, responseData,
                        &responseLength, &completionCode, fdebug); 

	if (status == ACCESS_OK) {
		if( completionCode ) {
			if (fdebug)
			  SELprintf("GetSerEntry(%d,%d): completion code=%x\n", 
				chan,subfunc,completionCode); 
		} else {
			// dont copy first byte (Parameter revision, usu 0x11)
			memcpy(pLanRecord,&responseData[1],responseLength-1);
			pLanRecord->data[responseLength-1] = 0;
			//successful, done
			return(0);
		}
	}

	// we are here because completionCode is not COMPLETION_CODE_OK
	if (fdebug) 
		SELprintf("GetSerEntry(%d,%d): ipmi_cmd status=%x ccode=%x\n",
                          chan,subfunc,status,completionCode);
 	return -1;
}

static int GetLanEntry(uchar subfunc, uchar bset, LAN_RECORD *pLanRecord)
{
	uchar responseData[MAX_BUFFER_SIZE];
	int responseLength = MAX_BUFFER_SIZE;
	uchar inputData[24]; 
	int status, n;
	uchar completionCode;
	uchar chan; 

	if (pLanRecord == NULL)
	{
	   if (fdebug)
	       printf("GetLanEntry: error, output buffer is NULL\n");
 	   return (-1);
	}

        chan = lan_ch;  /* LAN 1 = 7 */

	inputData[0]            = chan;  // flags, channel 3:0 (LAN 1)
	inputData[1]            = subfunc;  // Param selector (3 = ip addr)
	inputData[2]            = bset;  // Set selector 
	inputData[3]            = 0;  // Block selector

        status = ipmi_cmd(GET_LAN_CONFIG, inputData, 4, responseData,
                        &responseLength, &completionCode, fdebug); 

	if (status == ACCESS_OK) {
		if( completionCode ) {
			if (fdebug) 
			   SELprintf("GetLanEntry: completion code=%x\n", 
					completionCode);
			status = completionCode;
		} else {
			// dont copy first byte (Parameter revision, usu 0x11)
			if (responseLength > 0) {
			   n = responseLength-1;
			   memcpy(pLanRecord,&responseData[1],n);
			} else n = 0;
			pLanRecord->data[n] = 0;
			//successful, done
			return(0);
		}
	}

	// we are here because completionCode is not COMPLETION_CODE_OK
	if (fdebug) 
		SELprintf("GetLanEntry: ipmi_cmd status=%d completionCode=%x\n",
                          status,completionCode);
 	return status;
}  /* end GetLanEntry() */

static int SetLanEntry(uchar subfunc, LAN_RECORD *pLanRecord, int reqlen)
{
	uchar responseData[MAX_BUFFER_SIZE];
	int responseLength = MAX_BUFFER_SIZE;
	uchar inputData[24];
	int status;
	uchar completionCode;

	if (pLanRecord == NULL)
	{
	   if (fdebug)
	       printf("SetLanEntry(%d): error, input buffer is NULL\n",subfunc);
 	   return (-1);
	}

	inputData[0]            = lan_ch;  // flags, channel 3:0 (LAN 1)
	inputData[1]            = subfunc;  // Param selector (3 = ip addr)
	memcpy(&inputData[2],pLanRecord,reqlen);

        status = ipmi_cmd(SET_LAN_CONFIG, inputData, (uchar)(reqlen+2), 
			responseData, &responseLength,&completionCode,fdebug);

	if (status == ACCESS_OK) {
		if( completionCode ) {
			if (fdebug)
			   SELprintf("SetLanEntry(%d): completion code=%x\n", 
				  subfunc,completionCode); // responseData[0]);
                        return(completionCode);
		} else {
			//successful, done
			return(0);
		}
	}

	// we are here because completionCode is not COMPLETION_CODE_OK
	if (fdebug) 
	    SELprintf("SetLanEntry(%d): ipmi_cmd status=%d ccode=%x\n",
                          subfunc,status,completionCode);
 	return status;
}  /* end SetLanEntry() */

int GetPefEntry(uchar subfunc, ushort rec_id, PEF_RECORD *pPefRecord)
{
	uchar responseData[MAX_BUFFER_SIZE];
	int responseLength = MAX_BUFFER_SIZE;
	uchar inputData[24]; /* only use 3 bytes for input */
	int status, n;
	uchar completionCode;

	if (pPefRecord == NULL)
	{
	   if (fdebug)
	      printf("GetPefEntry(%d): error, output buffer is NULL\n",subfunc);
 	   return (-1);
	}

	inputData[0]            = subfunc; // Parameter = Evt Filter Table
	inputData[1]            = (uchar)rec_id; 
	inputData[2]            = 0; 

        status = ipmi_cmd(GET_PEF_CONFIG, inputData, 3, responseData,
                        &responseLength, &completionCode, fdebug); 

        if (status == ACCESS_OK) {
                if( completionCode ) {
			if (fdebug)
                           SELprintf("GetPefEntry(%d/%d): completion code=%x\n",
                                subfunc,rec_id,completionCode); 
			status = completionCode;
                } else {
			/* expect PEF record to be >=21 bytes */
			if (responseLength > 1) n = responseLength-1;
			else n = 0;
			if (n > 21) n = 21; /*only use 21 bytes*/
			if ((subfunc == 6) && (n < 21)) {
			  if (fdebug)
                             printf("GetPefEntry(%d/%d): length %d too short\n",
					subfunc,rec_id,responseLength); 
			}
                        // dont copy first byte (Parameter revision, usu 0x11)
			if (n == 0) memset(pPefRecord,0,21); 
			else memcpy(pPefRecord,&responseData[1],n);
                        //successful, done
                        return(0);
                }
	}

	// we are here because completionCode is not COMPLETION_CODE_OK
	if (fdebug) 
	      SELprintf("GetPefEntry: ipmi_cmd status=%x completionCode=%x\n",
                         status, completionCode);
 	return status;
}  /* end GetPefEntry() */

int SetPefEntry(PEF_RECORD *pPefRecord)
{
	uchar responseData[MAX_BUFFER_SIZE];
	int responseLength = MAX_BUFFER_SIZE;
	uchar inputData[32]; /* sizeof(PEF_RECORD) = 21 +1=22 */
	int status;
	uchar completionCode;
	uchar subfunc;

	subfunc = 0x06; // Parameter = Evt Filter Table

	if (pPefRecord == NULL) {
	   if (fdebug)
	       printf("SetPefEntry: error, output buffer is NULL\n");
 	   return (-1);
	}

        //  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21
        // 06 0c 80 01 01 00 ff ff 20 ff 6f ff 00 00 00 00 00 00 00 00 00 00
	// memset(&inputData[0],0,requestData.dataLength);
	inputData[0]            = subfunc; 
	memcpy(&inputData[1],pPefRecord,sizeof(PEF_RECORD));

        status = ipmi_cmd(SET_PEF_CONFIG, inputData, sizeof(PEF_RECORD)+1, 
		       responseData, &responseLength, &completionCode, fdebug); 

	if (status == ACCESS_OK) {
		if( completionCode ) {
			if (fdebug)
			   SELprintf("SetPefEntry: completion code=%x\n", 
				   completionCode); // responseData[0]);
			status = completionCode;
		} else {
			//successful, done
			return(0);
		}

	}

	// we are here because completionCode is not COMPLETION_CODE_OK
	if (fdebug) 
	    SELprintf("SetPefEntry: ipmi_cmd status=%d completion code=%x\n",
                          status,completionCode);
 	return(status);
 
}  /* end SetPefEntry() */

int DisablePef(int anum)
{
	uchar iData[24]; /* sizeof(PEF_RECORD) = 21 +1=22 */
	uchar rData[MAX_BUFFER_SIZE];
	int rLength = MAX_BUFFER_SIZE;
	uchar cc;
	int status;

	if (fmBMC) {
           SELprintf("mini-BMC does not support disabling BMC LAN\n");
	   return(-1);
	} else {
           status = SetChanAcc(lan_ch, 0x80, CHAN_ACC_DISABLE);
           if (fdebug) SELprintf("SetChanAcc(lan/active), ret = %d\n",status);
           status = SetChanAcc(lan_ch, 0x40, CHAN_ACC_DISABLE); 
           SELprintf("SetChanAcc(lan), ret = %d\n",status);
	   if (status != 0) return(status);
	}

	iData[0] = 0x01;        /* PEF Control Param */
	iData[1] = 0x00;	/* PEF disable */
	rLength = MAX_BUFFER_SIZE;
        status = ipmi_cmd(SET_PEF_CONFIG, iData, 2, rData, &rLength, 
			  &cc, fdebug); 
	if (status != 0) return(status);
	if( cc ) {
	   SELprintf("DisablePef[%d]: completion code=%x\n",iData[0],cc);
	   return(-1);
	}

        if (anum != 0) {
	  iData[0] = 0x09;        /* PEF Alert Policy Table */
	  iData[1] = (uchar)anum; /* Policy number (default 0x01) */
	  iData[2] = 0x10;        /* PEF LAN, policy disable */
	  iData[3] = 0x00;        /* LAN_CH=00, default dest=00 */
	  iData[4] = 0x00;        /* No alert string */
	  rLength = MAX_BUFFER_SIZE;
          status = ipmi_cmd(SET_PEF_CONFIG, iData, 5, rData, &rLength, 
			  &cc, fdebug); 
	  if (status != 0) return(status);
	  if( cc ) {
		SELprintf("DisablePef[%d]: completion code=%x\n",iData[0],cc);
		return(-1);
	  }
        }
	return(status);
}

int ShowPef(void)
{
	uchar iData[24]; /* sizeof(PEF_RECORD) = 21 +1=22 */
	uchar rData[MAX_BUFFER_SIZE];
	int rLength = MAX_BUFFER_SIZE;
	uchar cc;
	int status, i,j;
	 
	for (j = 1; j < MAX_PEFPARAMS; j++) {
	   if (j == 4 && fmBMC) {
		/* fmBMC gets cc=0x80 for param 4, so skip it. */
		continue;
	   }
	   iData[0] = (uchar)j;         /* PEF Control Param */
	   if (j == 6 || j == 7 || j == 9) iData[1] = 1; 
	   else iData[1] = 0x00;	 /* PEF Set Selector */
	   if (j == 13) iData[2] = 1; 
	   else iData[2] = 0x00;	 /* PEF Block Selector */
	   rLength = MAX_BUFFER_SIZE;
	   status = ipmi_cmd(GET_PEF_CONFIG, iData, 3, rData, &rLength, 
				&cc, fdebug); 
	   if (status == 0 && cc == 0) {
		SELprintf("PefParam[%d]: ",iData[0]);
		if (rLength > 0)
		  for (i=0;i<peflen[j];i++) SELprintf("%02x ", rData[1+i]);
		SELprintf("\n");
	   } else
		SELprintf("PefParam[%d]: GET_PEF status=%d cc=%x\n",
			  	iData[0],status,cc);
	}
	return(status);
}

int EnablePef(int anum)
{
	uchar iData[24]; /* sizeof(PEF_RECORD) = 21 +1=22 */
	uchar rData[MAX_BUFFER_SIZE];
	int rLength = MAX_BUFFER_SIZE;
	uchar cc;
	int status;
	uchar sdelay;

        status = SetChanAcc(lan_ch, 0x80, chan_pefon);  
        if (fdebug) SELprintf("SetChanAcc(lan/active), ret = %d\n",status);
        status = SetChanAcc(lan_ch, 0x40, chan_pefon); 
        SELprintf("SetChanAcc(lan), ret = %d\n",status);
	if (status != 0) return(status);

	{
	  iData[0] = 0x01;         /* PEF Control Param */
	  iData[1] = 0x00;	   /* PEF Set Selector */
	  iData[2] = 0x00;	   /* PEF Block Selector */
	  rLength = MAX_BUFFER_SIZE;
          status = ipmi_cmd(GET_PEF_CONFIG, iData, 3, rData, &rLength, 
			  &cc, fdebug); 
	  if (status != 0 || cc != 0) sdelay = 0;
	  else sdelay = rData[1];
	  if (fdebug) SELprintf("EnablePef[%d]: get cc=%x, control=%02x\n",
			  	iData[0],cc,sdelay);
	  iData[0] = 0x01;         /* PEF Control Param (0x01 or 0x05) */
	  iData[1] = 0x01;	   /* PEF enable, & no startup delay */
	  rLength = MAX_BUFFER_SIZE;
          status = ipmi_cmd(SET_PEF_CONFIG, iData, 2, rData, &rLength, 
			  &cc, fdebug); 
	  if (status != 0) return(status);
	  if( cc ) {
		SELprintf("EnablePef[%d]: completion code=%x\n",iData[0],cc);
		return(-1);
	  }

#ifdef TEST
	  iData[0] = 0x01;         /* Serial Channel */
	  iData[1] = 0x13;         /* Dest Com settings = 19. */
	  iData[2] = 0x01;         /* POL Default Dest */
	  iData[3] = 0x60;         
	  iData[4] = 0x07;        
          status = ipmi_cmd(SET_SER_CONFIG, iData, 5, rData, &rLength, 
			  &cc, fdebug); 
#endif

	  iData[0] = 0x02;         /* PEF Action Param */
	  iData[1] = 0x00;	   /* PEF Set Selector */
	  iData[2] = 0x00;	   /* PEF Block Selector */
	  rLength = MAX_BUFFER_SIZE;
          status = ipmi_cmd(GET_PEF_CONFIG, iData, 3, rData, &rLength, 
			  &cc, fdebug); 
	  if (fdebug) SELprintf("EnablePef[%d]: get cc=%x, val=%02x\n",
			  	iData[0],cc,rData[1]);
	  iData[0] = 0x02;         /* PEF Action Param */
          if (vend_id == VENDOR_INTEL)
	      iData[1] = 0x2f; /* enable alerts, reset, power cycle/down, diag*/
          else 
	      iData[1] = 0x0f; /* enable alerts, reset, power cycle/down */
	  rLength = MAX_BUFFER_SIZE;
          status = ipmi_cmd(SET_PEF_CONFIG, iData, 2, rData, &rLength, 
			  &cc, fdebug); 
	  if (status != 0) return(status);
	  if( cc ) {
		SELprintf("EnablePef[%d]: completion code=%x\n",iData[0],cc);
		return(-1);
	  }

	  if ((sdelay & 0x04) != 0) {  /* startup delay is supported */
	    iData[0] = 0x03;         /* PEF Startup Delay Param */
	    iData[1] = 0x00;         /* 0 seconds, default is 0x3c (60 sec) */
	    rLength = MAX_BUFFER_SIZE;
            status = ipmi_cmd(SET_PEF_CONFIG, iData, 2, rData, &rLength, 
			  &cc, fdebug); 
	    if (fdebug) SELprintf("EnablePef[%d]: set val=%02x cc=%x\n",
			  	 iData[0],iData[1],cc);
	    if (status != 0) return(status);
	    if( cc ) {
		SELprintf("EnablePef[%d]: completion code=%x\n",iData[0],cc);
		// return(-1);
	    }
	    iData[0] = 0x04;         /* PEF Alert Startup Delay Param */
	    iData[1] = 0x00;         /* 0 seconds, default is 0x3c (60 sec) */
	    rLength = MAX_BUFFER_SIZE;
            status = ipmi_cmd(SET_PEF_CONFIG, iData, 2, rData, &rLength, 
			  &cc, fdebug); 
	    if (fdebug) SELprintf("EnablePef[%d]: set val=%02x cc=%x\n",
			  	 iData[0],iData[1],cc);
	    if (status != 0) return(status);
	    if( cc ) {
		SELprintf("EnablePef[%d]: completion code=%x\n",iData[0],cc);
		// return(-1);
	    }
	  } /*endif sdelay*/

	  iData[0] = 0x09;        /* PEF Alert Policy Table */
	  iData[1] = (uchar)anum; /* Policy number (default 0x01) */
	  iData[2] = 0x18;        /* PEF LAN, always alert, policy enable */
	  iData[3] = (lan_ch << 4) + anum;  /* LAN_CH=70, default dest=01 */
	  iData[4] = 0x00;        /* No alert string */
	  rLength = MAX_BUFFER_SIZE;
          status = ipmi_cmd(SET_PEF_CONFIG, iData, 5, rData, &rLength, 
			  &cc, fdebug); 
	  if (fdebug) SELprintf("EnablePef[%d]: set val=%02x cc=%x\n",
			  	 iData[0],iData[1],cc);
	  if (status != 0) return(status);
	  if( cc ) {
		SELprintf("EnablePef[%d]: completion code=%x\n",iData[0],cc);
		return(-1);
	  }
	}  /*endif IPMI 1.5 */

	return(status);
}  /* end EnablePef */

#define NBAUDS  10
static struct {
       unsigned char val;
       char str[8];
    } mapbaud[NBAUDS] = {
       { 6,  "9600" },
       { 6,  "9.6K" },
       { 7,  "19.2K" },
       { 7,  "19200" },
       { 8,  "38.4K" },
       { 8,  "38400" },
       { 9,  "57.6K" },
       { 9,  "57600" },
       { 10, "115.2K" },
       { 10, "115200" }
    };

static unsigned char Str2Baud(char * str)
{
   unsigned char baud = 0;
   int i, n, len;
   len = strlen(str);
   for (i = 0; i < len; i++)  /*toupper*/
      if (str[i] >= 'a' && str[i] <= 'z') str[i] &= 0x5F;
   for (i = 0; i < NBAUDS; i++) {
       n = strlen(mapbaud[i].str);
       if (strncmp(str,mapbaud[i].str,n) == 0) {
           baud = mapbaud[i].val;
           break;
       }
   }
   if (i == NBAUDS || baud == 0) {
       printf("Invalid -B parameter value (%s), using 19.2K.\n",str);
       i = 1; /* default is 19.2K */
       baud = mapbaud[i].val; /* =7 */
   }
   if (fdebug) printf("new baud = %02x (%s)\n",baud,mapbaud[i].str);
   return(baud);
}

static char *Baud2Str(unsigned char bin)
{
    char *baudstr;
    unsigned char b;
    b = bin & 0x0f;
    switch(b) {
	case 6:  baudstr = "9600 "; break;
	case 7:  baudstr = "19.2k"; break;
	case 8:  baudstr = "38.4k"; break;
	case 9:  baudstr = "57.6k"; break;
	case 10: baudstr = "115.2k"; break;
	default: baudstr = "nobaud";
    }
    return(baudstr);
}

static int BaudValid(unsigned char b)
{
    int val = 0;
    switch(b) {
	case 6:  val = 1; break; 
	case 7:  val = 1; break; 
	case 8:  val = 1; break; 
	case 9:  val = 1; break; 
	case 10: val = 1; break; 
	default: val = 0; break; 
    }
    return(val);
}

/*
 * atomac - converts ASCII string to binary MAC address (array).
 * Accepts input formatted as 11:22:33:44:55:66 or 11-22-33-44-55-66.
 */
void atomac(uchar *array, char *instr)
{
   int i,j,n;
   char *pi;
   j = 0;
   pi = instr;
   n = strlen(instr);
   for (i = 0; i <= n; i++) {
      if (instr[i] == ':') {
	array[j++] = htoi(pi);
	pi = &instr[i+1];
      } else if (instr[i] == '-') {
	array[j++] = htoi(pi);
	pi = &instr[i+1];
      } else if (instr[i] == 0) {
	array[j++] = htoi(pi);
      }
      if (j >= MAC_LEN) break; /*safety valve*/
   }
   if (fdebug) 
      printf("atomac: %02x %02x %02x %02x %02x %02x\n", 
         array[0],array[1],array[2],array[3], array[4],array[5]);
}  /*end atomac()*/

/* extern void atoip(uchar *array,char *instr); *from subs.c*/

int MacIsValid(uchar *mac)
{
   int fvalid = 0;
   int i;
   /* check for initial invalid value of FF:00:... */
   if (mac[0] == 0xff && mac[1] == 0x00)  /* marked as invalid */
	return(fvalid);
   /* check for all zeros */
   for (i = 0; i < MAC_LEN; i++)
	if (mac[i] != 0) {  /* not all zeros */
	    fvalid = 1;
	    break;
	}
   return(fvalid);
}

int IpIsValid(uchar *ipadr)
{
   int fvalid = 1;
   if (ipadr[0] == 0) fvalid = 0;
   return(fvalid);
}

int SubnetIsValid(uchar *subnet)
{
   int fvalid = 0;
   /* if masking off at least one bit, say valid */
   if (subnet[0] != 0) fvalid = 1;
   return(fvalid);
}

int SubnetIsSame(uchar *ip1, uchar *ip2, uchar *subnet)
{
    int i;
    uchar c1, c2;
    for (i = 0; i < 4; i ++) {
	c1 = ip1[i] & subnet[i];
	c2 = ip2[i] & subnet[i];
	if (c1 != c2) return 0; 
    }
    return 1;    /*same, return true*/
}

#ifdef WIN32
/*
 * Obtain network adapter information (Windows).
 */
PIP_ADAPTER_ADDRESSES GetAdapters() {
    PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL;
    ULONG OutBufferLength = 0;
	ULONG RetVal = 0, i;
      
    // The size of the buffer can be different 
    // between consecutive API calls.
    // In most cases, i < 2 is sufficient;
    // One call to get the size and one call to get the actual parameters.
    // But if one more interface is added or addresses are added, 
    // the call again fails with BUFFER_OVERFLOW. 
    // So the number is picked slightly greater than 2. 
    // We use i <5 in the example
    for (i = 0; i < 5; i++) {
        RetVal = GetAdaptersAddresses(
                AF_INET, 0, NULL, 
                AdapterAddresses, 
                &OutBufferLength);
        
        if (RetVal != ERROR_BUFFER_OVERFLOW) {
            break;
        }

        if (AdapterAddresses != NULL) {
            free(AdapterAddresses);
        }
        
        AdapterAddresses = (PIP_ADAPTER_ADDRESSES) malloc(OutBufferLength);
        if (AdapterAddresses == NULL) {
            RetVal = GetLastError();
            break;
        }
    }
    if (RetVal == NO_ERROR) {
      // If successful, return pointer to structure
        return AdapterAddresses;
    }
    else { 
      LPVOID MsgBuf;
      
      printf("Call to GetAdaptersAddresses failed.\n");
      if (FormatMessage( 
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM | 
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        RetVal,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
        (LPTSTR) &MsgBuf,
        0,
        NULL )) {
        printf("\tError: %s", MsgBuf);
      }
      LocalFree(MsgBuf);
    }  
    return NULL;
}

/*
 * Set BMC MAC corresponding to current BMC IP address (Windows).
 */
int GetLocalMACByIP() {
    PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL;
    PIP_ADAPTER_ADDRESSES AdapterList;
    int result = 0;

    struct sockaddr_in *si;
    
    AdapterAddresses = GetAdapters();
    AdapterList = AdapterAddresses;
    
    while (AdapterList) {
        PIP_ADAPTER_UNICAST_ADDRESS addr;
        addr = AdapterList->FirstUnicastAddress;
	if (addr == NULL) si = NULL;
        else si = (struct sockaddr_in*)addr->Address.lpSockaddr;
	if (si != NULL) {
           if(memcmp(&si->sin_addr.s_addr, rgmyip, 4) == 0) {
	      if (!MacIsValid(rgmymac))
		memcpy(rgmymac, AdapterList->PhysicalAddress, MAC_LEN);
              memcpy(osmyip, &si->sin_addr.s_addr, 4);
	      memcpy(osmymac, AdapterList->PhysicalAddress, MAC_LEN);
              wcstombs(ifname,AdapterList->FriendlyName, sizeof(ifname));
              result = 1;
              break;
           }
        }
        AdapterList = AdapterList->Next;
    }   

    if (AdapterAddresses != NULL) {
        free(AdapterAddresses);
    }
    return result;
}

/*
 * Get First IP Address in Windows OS
 *   ipaddr is 4 bytes, macaddr is 6 bytes, ipname can be 64 bytes.
 * (called by idiscover.c)
 */
int GetFirstIP(uchar *ipaddr, uchar *macadr, char *ipname, char fdbg) 
{
    PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL;
    PIP_ADAPTER_ADDRESSES AdapterList;
    struct sockaddr_in *si;
    uchar *psaddr;
    int result = -1;
    
    AdapterAddresses = GetAdapters();
    AdapterList = AdapterAddresses;
    
    while (AdapterList) {
        PIP_ADAPTER_UNICAST_ADDRESS addr;
		
	addr = AdapterList->FirstUnicastAddress;
	si = (struct sockaddr_in*)addr->Address.lpSockaddr;
	psaddr = (uchar *)&si->sin_addr.s_addr;
	if ((psaddr[0] != 0) && (psaddr[0] != 169)) {
	    if (fdbg) printf("found IP: s_addr=%d.%d.%d.%d\n",
				psaddr[0], psaddr[1], psaddr[2], psaddr[3]);
	    if (ipaddr != NULL)
               memcpy(ipaddr, &si->sin_addr.s_addr, 4);
	    if (macadr != NULL) {
	       memcpy(macadr, AdapterList->PhysicalAddress, MAC_LEN);
	       if (fdbg) printf("found MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
			macadr[0], macadr[1], macadr[2], macadr[3],
			macadr[4], macadr[5]);
	    }
	    if (ipname != NULL) {
               wcstombs(ipname,AdapterList->FriendlyName, sizeof(ifname));
	       if (fdbg) printf("found Adapter: %d\n",ipname);
	    }
            result = 0;
            break;
        }
        AdapterList = AdapterList->Next;
    }   

    if (AdapterAddresses != NULL) {
        free(AdapterAddresses);
    }
    return result;
}

/*
 * Set BMC MAC corresponding to current BMC IP address (Windows).
 */
int GetLocalIPByMAC(uchar *macadr) {
    PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL;
    PIP_ADAPTER_ADDRESSES AdapterList;
    int result = 0;

    struct sockaddr_in *si;
    
    AdapterAddresses = GetAdapters();
    AdapterList = AdapterAddresses;
    
    while (AdapterList) {
        PIP_ADAPTER_UNICAST_ADDRESS addr;
        if(memcmp(AdapterList->PhysicalAddress, macadr, MAC_LEN) == 0) {
            addr = AdapterList->FirstUnicastAddress;
            
            si = (struct sockaddr_in*)addr->Address.lpSockaddr;
	    if (fdebug) {
		uchar *psaddr;
		psaddr = (uchar *)&si->sin_addr.s_addr;
		printf("mac match: rgmyip=%d.%d.%d.%d s_addr=%d.%d.%d.%d\n",
			rgmyip[0], rgmyip[1], rgmyip[2], rgmyip[3],
			psaddr[0], psaddr[1], psaddr[2], psaddr[3]);
	    }
 	    if (!IpIsValid(rgmyip) && (fsharedMAC==1)) /*not specified, shared*/
		memcpy(rgmyip, &si->sin_addr.s_addr, 4);
            memcpy(osmyip, &si->sin_addr.s_addr, 4);
	    memcpy(osmymac, AdapterList->PhysicalAddress, MAC_LEN);
            wcstombs(ifname,AdapterList->FriendlyName, sizeof(ifname));
            result = 1;
            break;
        }
        AdapterList = AdapterList->Next;
    }   

    if (AdapterAddresses != NULL) {
        free(AdapterAddresses);
    }
    return result;
}
/*
 * Set MAC and IP address from given interface name (Windows).
 */
int GetLocalDataByIface() {
    PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL;
    PIP_ADAPTER_ADDRESSES AdapterList;
    int result = 0;

    size_t origsize, newsize, convertedChars;
    wchar_t* wcstring;
    struct sockaddr_in *si;
    
    AdapterAddresses = GetAdapters();
    AdapterList = AdapterAddresses;
    
    origsize = strlen(ifname) + 1;
    newsize = origsize;
    convertedChars = 0;
    wcstring = (wchar_t*) malloc(sizeof(wchar_t) * newsize)  ;
    if (wcstring == NULL) AdapterList = NULL;  /*skip loop, do free*/
    else mbstowcs(wcstring, ifname, origsize );
    
    while (AdapterList) {
        PIP_ADAPTER_UNICAST_ADDRESS addr;
        if(wcsstr(AdapterList->FriendlyName, wcstring)) {
            printf("Using interface: %S\n", AdapterList->FriendlyName);
            printf("\t%S\n", AdapterList->Description);
            addr = AdapterList->FirstUnicastAddress;
            
            si = (struct sockaddr_in*)addr->Address.lpSockaddr;
	    if (fdebug) {
		uchar *psaddr;
		psaddr = (uchar *)&si->sin_addr.s_addr;
		printf("mac match: rgmyip=%d.%d.%d.%d s_addr=%d.%d.%d.%d "
			"fsharedMAC=%d\n",
			rgmyip[0], rgmyip[1], rgmyip[2], rgmyip[3],
			psaddr[0], psaddr[1], psaddr[2], psaddr[3],
			fsharedMAC);
	    }
	    if (!IpIsValid(rgmyip)) {  /*IP not specified*/
               memcpy(rgmyip, &si->sin_addr.s_addr, 4);
               memcpy(rgmymac, AdapterList->PhysicalAddress, MAC_LEN);
	    }
            memcpy(osmyip, &si->sin_addr.s_addr, 4);
	    memcpy(osmymac, AdapterList->PhysicalAddress, MAC_LEN);
            /* FriendlyName == ifname already */
            result = 1;
            break;
        }
        AdapterList = AdapterList->Next;
    }   

    if (AdapterAddresses != NULL) {
        free(AdapterAddresses);
    }
    return result;
}

int FindEthNum(uchar *macadrin)
{
   int i;
   uchar macadr[MAC_LEN];
   memcpy(macadr,macadrin,MAC_LEN);
   if (fsharedMAC == 0 && vend_id == VENDOR_INTEL)  {
	/* Intel factory assigns them this way, so use that to compare */
	macadr[MAC_LEN-1] -= 2; /*OS MAC = BMC MAC - 2*/
   }
   i = GetLocalIPByMAC(macadr);
   if (i == 1) fethfound = 1;
   if (fdebug)  /* show the local OS eth if and MAC */
	printf("FindEth: OS %s IP=%d.%d.%d.%d MAC=%02x:%02x:%02x:%02x:%02x:%02x\n",
                ifname, osmyip[0], osmyip[1], osmyip[2], osmyip[3], 
		osmymac[0], osmymac[1], osmymac[2], osmymac[3], 
		osmymac[4], osmymac[5]);
   /* The actual Windows ethernet interface is determined 
    * in Get_IPMac_Addr using ipconfig, so
    * init eth interface number as eth0 for Windows. */
   return(0);
}
#elif defined(HPUX)
#define INSAP 22
#define OUTSAP 24

#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <sys/stropts.h>
#include <sys/poll.h>
#include <sys/dlpi.h>

#define bcopy(source, destination, length) memcpy(destination, source, length)
#define AREA_SZ 5000 /*=* buffer length in bytes *=*/
#define GOT_CTRL 1
#define GOT_DATA 2
#define GOT_BOTH 3
#define GOT_INTR 4
#define GOT_ERR 128
static u_long ctl_area[AREA_SZ];
static u_long dat_area[AREA_SZ];
static struct strbuf ctl = {AREA_SZ, 0, (char *)ctl_area};
static struct strbuf dat = {AREA_SZ, 0, (char *)dat_area};
static char *dlpi_dev[] = {"/dev/dlpi", ""};

/*=* get a message from a stream; return type of message *=*/
static int get_msg(int fd)
{
    int flags = 0;
    int res, ret;
    ctl_area[0] = 0;
    dat_area[0] = 0;
    ret = 0;
    res = getmsg(fd, &ctl, &dat, &flags);
    if(res < 0) {
        if(errno == EINTR) {
            return(GOT_INTR);
        } else {
            return(GOT_ERR);
        }
    }
    if(ctl.len > 0) {
        ret |= GOT_CTRL;
    }
    if(dat.len > 0) {
        ret |= GOT_DATA;
    }
    return(ret);
}

/*=* verify that dl_primitive in ctl_area = prim *=*/
static int check_ctrl(int prim)
{
    dl_error_ack_t *err_ack = (dl_error_ack_t *)ctl_area;
    if(err_ack->dl_primitive != prim) {
        return GOT_ERR;
    }
    return 0;
}

/*=* put a control message on a stream *=*/
static int put_ctrl(int fd, int len, int pri)
{
    ctl.len = len;
    if(putmsg(fd, &ctl, 0, pri) < 0) {
        return GOT_ERR;
    }
    return  0;
}

/*=* put a control + data message on a stream *=*/
static int put_both(int fd, int clen, int dlen, int pri)
{
    ctl.len = clen;
    dat.len = dlen;
    if(putmsg(fd, &ctl, &dat, pri) < 0) {
        return GOT_ERR;
    }
    return  0;
}

/*=* open file descriptor and attach *=*/
static int dl_open(const char *dev, int ppa, int *fd)
{
    dl_attach_req_t *attach_req = (dl_attach_req_t *)ctl_area;
    if((*fd = open(dev, O_RDWR)) == -1) {
        return GOT_ERR;
    }
    attach_req->dl_primitive = DL_ATTACH_REQ;
    attach_req->dl_ppa = ppa;
    put_ctrl(*fd, sizeof(dl_attach_req_t), 0);
    get_msg(*fd);
    return check_ctrl(DL_OK_ACK);
}

/*=* send DL_BIND_REQ *=*/
static int dl_bind(int fd, int sap, u_char *addr)
{
    dl_bind_req_t *bind_req = (dl_bind_req_t *)ctl_area;
    dl_bind_ack_t *bind_ack = (dl_bind_ack_t *)ctl_area;
    bind_req->dl_primitive = DL_BIND_REQ;
    bind_req->dl_sap = sap;
    bind_req->dl_max_conind = 1;
    bind_req->dl_service_mode = DL_CLDLS;
    bind_req->dl_conn_mgmt = 0;
    bind_req->dl_xidtest_flg = 0;
    put_ctrl(fd, sizeof(dl_bind_req_t), 0);
    get_msg(fd);
    if (GOT_ERR == check_ctrl(DL_BIND_ACK)) {
        return GOT_ERR;
    }
    bcopy((u_char *)bind_ack + bind_ack->dl_addr_offset, addr,
        bind_ack->dl_addr_length);
    return 0;
}

int FindEthNum(uchar *addr)
{               /* Need to use DLPI for HPUX */
   /*See http://cplus.kompf.de/artikel/macaddr.html */
    int fd;
    int ppa;
    u_char mac_addr[25];
    char **dev;
    int i = 0;

    for (dev = dlpi_dev; **dev != ''; ++dev) {
        for (ppa=0; ppa<10; ++ppa) {
            if (GOT_ERR != dl_open(*dev, ppa, &fd)) {
                if (GOT_ERR != dl_bind(fd, INSAP, mac_addr)) {
                    // bcopy( mac_addr, addr, 6);
		    i = ppa;
		    if (memcmp(mac_addr,addr,MAC_LEN) == 0) {
		       memcpy(osmymac, addr, MAC_LEN);
                       return(ppa);
		    }
                }
            }
            close(fd);
        }
    }
    return(i);
}
#else

static char *get_ifreq_mac(struct ifreq *ifrq)
{
    char *ptr;
#ifdef SOLARIS
    ptr = (char *)&ifrq->ifr_ifru.ifru_enaddr[0];
#elif BSD
    ptr = (char *)&ifrq->ifr_ifru.ifru_addr.sa_data[0];
#else
    ptr = (char *)&ifrq->ifr_hwaddr.sa_data[0];
#endif
    return (ptr);
}

extern int find_ifname(char *ifname);   /*see idiscover.c*/

int FindEthNum(uchar *macadrin)
{                     /*only used for Linux*/
    struct ifreq ifr;
    int skfd;
    int nCurDevice;
    int devnum = -1;
    int devos = 0;
    uchar macadr[MAC_LEN];
    uchar macsav[MAC_LEN];
    uchar mactmp[MAC_LEN];
    uchar ipsav[4];
    char szDeviceName[ 16 ];    /* MAX_DEVICE_NAME_LENGTH + 1 */
    uchar fipvalid = 0;
    int n;

    memcpy(macadr,macadrin,MAC_LEN);
    if (fsharedMAC == 0 && vend_id == VENDOR_INTEL)  {
	/* Intel factory assigns them this way, so use that to compare */
	macadr[MAC_LEN-1] -= 2; /*OS MAC = BMC MAC - 2*/
    }
#ifdef DBG
    if (fdebug) {
          uchar *pb;
          pb = macadrin;
          printf("input mac:%02x:%02x:%02x:%02x:%02x:%02x   "
                 "tmp mac:%02x:%02x:%02x:%02x:%02x:%02x\n",  
		pb[0],pb[1],pb[2],pb[3],pb[4],pb[5],
		macadr[0],macadr[1],macadr[2],macadr[3],macadr[4],macadr[5]);
    }
#endif
    
    n = find_ifname(szDeviceName);
    if (n >= 0) {
	n = strlen(szDeviceName);
	if (n < sizeof(ifpattn)) {
           strcpy(ifpattn,szDeviceName);
           ifpattn[n - 1] = 0;  /*truncate last digit*/
	}
	if (fdebug) 
	   printf("found ifname %s, pattern %s\n",szDeviceName,ifpattn);
    }

    if ( ( skfd = socket(AF_INET, SOCK_DGRAM, 0 ) ) < 0) {
       if ( fdebug ) {
          perror("socket");
          return devnum;
       }
    }
	    
    for( nCurDevice = 0 ;
    	 (nCurDevice < NUM_DEVICES_TO_CHECK) && (devnum == -1);
	 nCurDevice++ )
    {
		sprintf( szDeviceName, "%s%d", ifpattn, nCurDevice ); /*eth%d*/
		memset((char *)&ifr,0,sizeof(ifr));
		strcpy(ifr.ifr_name, szDeviceName );
		if (ioctl(skfd, SIOCGIFHWADDR, &ifr) > 0) {
		    if ( fdebug ) 
			printf("FindEthNum: Could not get MAC address for %s\n",
				 szDeviceName);
		} else {
		    uchar *pb;
		    pb = get_ifreq_mac(&ifr);
#ifdef DBG
		    if (fdebug) {
			printf("%s mac: %02x:%02x:%02x:%02x:%02x:%02x\n",  
			     szDeviceName, pb[0],pb[1],pb[2],pb[3],pb[4],pb[5]);
		    }
#endif
		    memcpy(macsav, pb, MAC_LEN);
		    /* check if this device is configured for IP addr */
		    memset((char *)&ifr,0,sizeof(ifr));
		    strcpy(ifr.ifr_name, szDeviceName);
		    ifr.ifr_addr.sa_family = AF_INET;
		    if (ioctl(skfd, SIOCGIFADDR, &ifr) >= 0) {
			fipvalid = 1;
			memcpy(ipsav, &ifr.ifr_addr.sa_data[2], 4);
		    } else fipvalid = 0;
		    if (memcmp(macsav, macadr, MAC_LEN) == 0) { /*found match*/
			devnum = nCurDevice;
		        memcpy(osmymac, macsav, MAC_LEN);
			if (fipvalid) memcpy(osmyip, ipsav, 4);
			break;
		    }
		    if (nCurDevice == 0) {   /*set a default of eth0*/
			devos = nCurDevice;
			memcpy(osmymac,macsav, MAC_LEN);
			if (fipvalid) memcpy(osmyip, ipsav, 4);
		    } else if (fipvalid) {   /*check if NIC1 is eth1,2,3,...*/
			memcpy(mactmp,osmymac,MAC_LEN);
			mactmp[MAC_LEN-1] -= 1;
			if (memcmp(mactmp,macsav,MAC_LEN) == 0) {
			    devos = nCurDevice;
		            memcpy(osmymac, macsav, MAC_LEN);
			    memcpy(osmyip, ipsav, 4);
			}
		    }
		} /*end else*/
    }
    if (!fsetifn) {
      if (devnum == -1) {  /*not found, use devos default*/
	devnum = devos;
	sprintf( ifname, "%s%d", ifpattn, devnum ); /*eth%d*/
      } else {  /* match was found, devnum set */
	fethfound = 1;
	strcpy(ifname, szDeviceName );
      }
    }
    close(skfd);
    if (fdebug)  /* show the local OS eth if and MAC */
	printf("FindEth: OS %s IP=%d.%d.%d.%d MAC=%02x:%02x:%02x:%02x:%02x:%02x\n",
                ifname, osmyip[0], osmyip[1], osmyip[2], osmyip[3], 
		osmymac[0], osmymac[1], osmymac[2], osmymac[3], 
		osmymac[4], osmymac[5]);
    return(devnum);
}
#endif

/*
 * GetBmcEthDevice
 * Attempt to auto-detect the BMC LAN channel and matching OS eth port.
 * INPUT:  lan_parm = lan channel from user -L option, 0xFF if not specified
 * OUTPUT: lan_ch is set to BMC LAN channel number
 *         if success, returns index of OS eth port (0, 1, ...). 
 *         if no lan channels found, returns -2.
 *         if other error, returns -1.
 */
int GetBmcEthDevice(uchar lan_parm)
{
	    LAN_RECORD LanRecord;
	    int devnum = -1;
	    int ret;
	    uchar bmcMacAddress[ MAC_LEN ];  /*MAC_LEN = 6*/
	    int rlen;
	    uchar iData[2];
	    uchar rData[10];
	    uchar cc;
	    int i = 0;
	    int j, jstart, jend, jlan;
	    uchar mtype;
	    uchar *pb;
	    int fchgmac;
	    // int found = 0;

	    /* Find the LAN channel(s) via Channel Info */
	    if (lan_parm < MAXCHAN) {  /* try user-specified channel only */
		lan_ch = lan_parm;
		jstart = lan_parm;
		jend = lan_parm+1;  
	    } else {
		jstart = 1;
		jend = MAXCHAN; 
	    }
	    memset(bmcMacAddress,0xff,sizeof(bmcMacAddress)); /*initialize to invalid*/
	    for (j = jstart; j < jend; 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;
		}
		mtype = rData[1];  /* channel medium type */
		if (mtype == 4) {  /* 802.3 LAN type*/
			if (fdebug) printf("chan[%d] = lan\n",j);
			jlan = lan_ch;  /*save prev lan chan */
			/* Get BMC MAC for this LAN channel. */
			/* Note: BMC MAC may not be valid yet. */
			lan_ch = (uchar)j; /*set lan channel for GetLanEntry*/
			ret = GetLanEntry( 5 /*MAC_ADDRESS_LAN_PARAM*/,0, &LanRecord);
			if ( ret != 0 ) {
			   lan_ch = (uchar)jlan;  /*restore lan_ch*/
			   printf( "GetBmcEthDevice: GetLanEntry failed\n" );
			   return devnum;
			} else {
			  pb = &LanRecord.data[0];
			  if (fdebug) printf("chan[%d] BMC MAC %x:%x:%x:%x:%x:%x\n",j,
					   pb[0], pb[1], pb[2], pb[3], pb[4], pb[5] );
			  fchgmac = 0;
			  /* use the lowest valid lan channel MAC address */
			  if (!MacIsValid(bmcMacAddress)) /* old MAC not valid*/
				fchgmac = 1; 
			  else if (MacIsValid(pb) &&   /* new MAC is valid and*/
			      (memcmp(bmcMacAddress,pb, sizeof(bmcMacAddress)) > 0))
				fchgmac = 1;   /* new MAC lower */
			  /* if no -L 3 and this is gcm, do not pick it. */
			  if ((j == gcm_ch) && (lan_parm == PARM_INIT)) 
				fchgmac = 0;
			  if (fchgmac) {    /* pick this channel & MAC */
			     memcpy(bmcMacAddress,pb,sizeof(bmcMacAddress));
			     lan_ch = (uchar)j;
			  } else lan_ch = (uchar)jlan; /*restore prev lan chan*/
			} 
			i++;  /* i = num lan channels found */
		} else if (mtype == 5) { /* serial type*/
			if (fdebug) printf("chan[%d] = serial\n",j);
			ser_ch = (uchar)j;    /* set to last serial channel */
		} else if (mtype == 7) { /* PCI SMBus */
			if (fdebug) printf("chan[%d] = pci_smbus\n",j);
		} else if (mtype == 12) { /* system interface */
			if (fdebug) printf("chan[%d] = system_interface\n",j);
		} else  /* other channel medium types, see IPMI 1.5 Table 6-3 */
			if (fdebug) printf("chan[%d] = %d\n",j,mtype);
	    }
	    if (i == 0) return(-2);  /* no lan channels found */
	    if (fdebug) printf("lan_ch detected = %d\n",lan_ch);

	    /* This will work if the BMC MAC is shared with the OS */
	    /* Otherwise, wait until we get the eth dev from the gateway below */
	    devnum = FindEthNum(bmcMacAddress);
	    if ( fdebug ) 
		printf("GetBmcEthDevice: channel %d, %s%d\n",lan_ch,ifpattn,devnum);
    return devnum;
}

/* file_grep/findmatch - No longer used here, see ievents.c */

/* 
 * Get_Mac
 * This routine finds a MAC address from a given IP address.
 * Usually for the Alert destination.
 * It uses ARP cache to do this.
 */
#if defined(WIN32)
int Get_Mac(uchar *ipadr,uchar *macadr, char *nodname)
{
    DWORD dwRetVal;
    IPAddr DestIp = 0;
    IPAddr SrcIp = 0;       /* default for src ip */
    ULONG MacAddr[2];       /* for 6-byte hardware addresses */
    ULONG PhysAddrLen = MAC_LEN;  /* default to length of six bytes */
    BYTE *bPhysAddr;

    if (!IpIsValid(ipadr)) {
	if (fdebug) printf("Get_Mac: invalid IP addr\n");
	return 1; /*error*/
    }
    memcpy(&DestIp, ipadr, 4);
    
    /* invoke system ARP query */
    dwRetVal = SendARP(DestIp, SrcIp, MacAddr, &PhysAddrLen);

    if (dwRetVal == NO_ERROR) 
    { /* no error - get the MAC */
        bPhysAddr = (BYTE *) & MacAddr;
        if (PhysAddrLen) {
            memcpy(macadr, bPhysAddr, MAC_LEN);
        } else
            printf("Warning: SendArp completed successfully, but returned length=0\n");
    } else if (dwRetVal == ERROR_GEN_FAILURE) 
    { /* MAC not available in this network - get gateway MAC */ 
        memcpy(macadr, rggwymac, MAC_LEN);
    } else 
    { /* other errors */
        printf("Error: SendArp failed with error: %d", dwRetVal);
        switch (dwRetVal) {
        case ERROR_INVALID_PARAMETER:
            printf(" (ERROR_INVALID_PARAMETER)\n");
            break;
        case ERROR_INVALID_USER_BUFFER:
            printf(" (ERROR_INVALID_USER_BUFFER)\n");
            break;
        case ERROR_BAD_NET_NAME:
            printf(" (ERROR_GEN_FAILURE)\n");
            break;
        case ERROR_BUFFER_OVERFLOW:
            printf(" (ERROR_BUFFER_OVERFLOW)\n");
            break;
        case ERROR_NOT_FOUND:
            printf(" (ERROR_NOT_FOUND)\n");
            break;
        default:
            printf("\n");
            break;
        }
        return 1;
    }
    return 0;
}  /* end Get_Mac() for WIN32*/
#elif defined(SOLARIS)
int Get_Mac(uchar *ipadr,uchar *macadr, char *nodename)
{
   FILE *fparp;
   char buff[1024]; 
   /* char arpfile[] = "/proc/net/arp";  */
   char alertfile[] = "/tmp/dest.arping";
   char arping_cmd[128];
   char *pb, *pm;
   int num, i;
   int foundit = 0;
   int ret = 0;

   if (IpIsValid(ipadr)) {  /* if valid IP address */
      sprintf(arping_cmd,
	      "ping %d.%d.%d.%d >/dev/null; arp -a -n |grep %d.%d.%d.%d  >%s\n",
              ipadr[0],ipadr[1],ipadr[2],ipadr[3],
              ipadr[0],ipadr[1],ipadr[2],ipadr[3], alertfile);
   } else if (nodename != NULL) {  /*if valid nodename */
      sprintf(arping_cmd,
	      "ping %s >/dev/null; arp -a |grep %s  >%s\n",
		nodename,nodename,alertfile);
   } else ret = -1;

   if (ret == 0) {   /* if valid IP address */
      /* make sure the destination is in the arp cache */
      if (fdebug) printf("%s", arping_cmd);
      system(arping_cmd);

      fparp = fopen(alertfile,"r");
      if (fparp == NULL) {
          fprintf(stdout,"Get_Mac: Cannot open %s, errno = %d\n",
			alertfile,get_errno());
	  ret = -1;
       } else {
	 /* sample output: */
	 /* e1000g0 cooper9     255.255.255.255 o   00:07:e9:06:55:c8 */
         while (fgets(buff, 1023, fparp)) {
	   /* should only run through loop once */
	   num = strcspn(buff," \t");    /* skip 1st word ("e1000g0") */
	   i = strspn(&buff[num]," \t"); /* skip whitespace */
	   pb = &buff[num+i];
	   num = strcspn(pb," \t");    /* skip 2nd word (nodename/IP) */
	   i = strspn(&pb[num]," \t"); /* skip whitespace */
	   pb += (num+i);
	   pm = &pb[25]; /* Now pb[25] has the MAC address */
	   {   /*validate new address?*/
	      if (fdebug) printf("Get_Mac: mac=%s\n",pm);
	      foundit = 1;
	      if (!MacIsValid(macadr)) atomac(macadr,pm);
	      break;
	   }
         } /*end while*/
         fclose(fparp);
       }  /*end else file opened*/
   }  /*endif valid IP */

   if (foundit == 0) {  /* no errors, but no mac reply */
      if (MacIsValid(rggwymac) && !MacIsValid(macadr))  
	 /* this is useful if the ipadr is not in the local subnet */
         memcpy(macadr,rggwymac,6); /* get to it from the default gateway */
   }
   return(ret);
}  /*end Get_Mac for Solaris*/
#elif defined(BSD)
int Get_Mac(uchar *ipadr,uchar *macadr, char *nodename)
{
   FILE *fparp;
   char buff[1024]; 
   /* char arpfile[] = "/proc/net/arp";  */
   char alertfile[] = "/tmp/dest.arping";
   char arping_cmd[128];
   char *pb, *pm;
   int num, i, j;
   int foundit = 0;
   int ret = 0;

   if (IpIsValid(ipadr)) {  /* if valid IP address */
      sprintf(arping_cmd,
	   "ping -c2 %d.%d.%d.%d >/dev/null; arp -a -n |grep %d.%d.%d.%d >%s\n",
              ipadr[0],ipadr[1],ipadr[2],ipadr[3],
              ipadr[0],ipadr[1],ipadr[2],ipadr[3], alertfile);
   } else if (nodename != NULL) {  /*if valid nodename */
      sprintf(arping_cmd,
	      "ping -c2 %s >/dev/null; arp -a |grep %s  >%s\n",
		nodename,nodename,alertfile);
   } else ret = -1;

   if (ret == 0) {   /* if valid IP address */
      /* make sure the destination is in the arp cache */
      if (fdebug) printf("%s", arping_cmd);
      system(arping_cmd);

      fparp = fopen(alertfile,"r");
      if (fparp == NULL) {
          fprintf(stdout,"Get_Mac: Cannot open %s, errno = %d\n",
			alertfile,get_errno());
	  ret = -1;
       } else {
	 /* sample output of arp -a -n: */
	 /* ? (192.168.1.200) at 00:0e:0c:e5:df:65 on em0 [ethernet] */
	 /* sample output of arp -a: */
	 /* telcoserv (192.168.1.200) at 00:0e:0c:e5:df:65 on em0 [ethernet] */
         while (fgets(buff, 1023, fparp)) {
	   /* should only run through loop once */
	   pb = &buff[0];
	   for (j = 0; j < 3; j++) { /* skip 3 words */
	      num = strcspn(pb," \t");    /* skip jth word */
	      i = strspn(&pb[num]," \t"); /* skip whitespace */
	      pb += (num+i);
	   }
	   pm = &pb[0]; /* Now pb[0] has the MAC address */
	   {   /* no need to validate new address*/
	      if (fdebug) printf("Get_Mac: mac=%s\n",pm);
	      foundit = 1;
	      if (!MacIsValid(macadr)) atomac(macadr,pm);
	      break;
	   }
         } /*end while*/
         fclose(fparp);
       }  /*end else file opened*/
   }  /*endif valid IP */

   if (foundit == 0) {  /* no errors, but no mac reply */
      if (MacIsValid(rggwymac) && !MacIsValid(macadr))  
	 /* this is useful if the ipadr is not in the local subnet */
         memcpy(macadr,rggwymac,6); /* get to it from the default gateway */
   }
   return(ret);
}  /*end Get_Mac for BSD */
#else
int Get_Mac(uchar *ipadr,uchar *macadr, char *nodename)
{   /* Get_Mac for Linux */
   FILE *fparp;
   char buff[1024]; 
   /* char arpfile[] = "/proc/net/arp";  */
   char alertfile[] = "/tmp/dest.arping";
   char arping_cmd[128];
   char *pb, *pm, *px;
   int num, i;
   int foundit = 0;
   int ret = 0;
   char *_ifname;

   if (strcmp(ifname,"gcm") == 0) _ifname = ifname0; /*see gcm_ch instead*/
   else _ifname = ifname;

   /* Get a MAC address for a given IP address or nodename */
   if (IpIsValid(ipadr)) {  /* if valid IP address */
      sprintf(arping_cmd,
	      "arping -I %s -c 2 %d.%d.%d.%d |grep reply |tail -n1 >%s\n",
              _ifname,ipadr[0],ipadr[1],ipadr[2],ipadr[3],alertfile);
   } else if (nodename != NULL) {  /*if valid nodename */
      sprintf(arping_cmd,
	      "arping -I %s -c 2 %s |grep reply |tail -n1 >%s\n",
              _ifname,nodename,alertfile);
   } else ret = -1;

   if (ret == 0) {   /* if valid IP address */
      /* make sure the destination is in the arp cache */
      if (fdebug) printf("%s", arping_cmd);
      ret = system(arping_cmd);

      fparp = fopen(alertfile,"r");
      if (fparp == NULL) {
         fprintf(stdout,"Get_Mac: Cannot open %s, errno = %d\n",
			alertfile,get_errno());
	 ret = -1;
       } else {
	 ret = 0;
         while (fgets(buff, 1023, fparp)) {
	   /* should only run through loop once */
	   num = strcspn(buff," \t");    /* skip 1st word ("Unicast") */
	   i = strspn(&buff[num]," \t");
	   pb = &buff[num+i];
  	   if (strncmp(pb,"reply",5) == 0) {  /* valid output */
	      /* Find the ip address */
	      pb += 6 + 5;         /* skip "reply from " */
	      num = strcspn(pb," \t");
	      pb[num] = 0;
	      if (fdebug) printf("Get_Mac: ip=%s\n",pb);
	      /* IP address should already match input param */
              if (!IpIsValid(ipadr))  /* had nodname only*/
 	           atoip(ipadr,pb);   /* fill in ipadr */
	      /* Now find the mac address */
	      pm = strchr(&pb[num+1],'[');
	      if (pm == NULL) pm = &pb[num+2];  /* just in case */
	      pm++;
	      px = strchr(pm,']');
	      if (px == NULL) px = pm + 17;    /* just in case */
	      px[0] = 0;
	      if (fdebug) printf("Get_Mac: mac=%s\n",pm);
	      foundit = 1;
 	      if (!MacIsValid(macadr)) atomac(macadr,pm);
	      break;
	   }
         } /*end while*/
         fclose(fparp);
       }  /*end else file opened*/
   }  /*endif valid IP */

   if (foundit == 0) {  /* no errors, but no mac reply */
      if (MacIsValid(rggwymac) && !MacIsValid(macadr))  
	 /* this is useful if the ipadr is not in the local subnet */
         memcpy(macadr,rggwymac,6); /* get to it from the default gateway */
   }
   return(ret);
}  /* end Get_Mac() for Linux*/
#endif

#ifdef WIN32
/*
 * Set subnet mask based on current IP address (Windows).
 */
int SetSubnetMask() {
    PMIB_IPADDRTABLE pIPAddrTable;
    unsigned int i;
    DWORD dwSize = 0, dwRetVal;
    LPVOID lpMsgBuf;

    pIPAddrTable = (MIB_IPADDRTABLE*) malloc( sizeof( MIB_IPADDRTABLE) );

    if ( pIPAddrTable ) {
        // Make an initial call to GetIpAddrTable to get the
        // necessary size into the dwSize variable
        if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
            free( pIPAddrTable );
            pIPAddrTable = (MIB_IPADDRTABLE *) malloc ( dwSize );
        }
    } else
        printf("Memory allocation failed.\n");

    if ( pIPAddrTable ) {
        // Make a second call to GetIpAddrTable to get the
        // actual data we want
        if ( (dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 )) == NO_ERROR ) { 
	        for(i = 0; i < pIPAddrTable->dwNumEntries; ++i) {
                if(memcmp(&(pIPAddrTable->table[i].dwAddr), rgmyip, 4) == 0) {
                    memcpy(rgsubnet, &(pIPAddrTable->table[i].dwMask), 4);
                    free( pIPAddrTable );
                    return 1;     
                }
            }
        } else {
            if (FormatMessage( 
                FORMAT_MESSAGE_ALLOCATE_BUFFER | 
                FORMAT_MESSAGE_FROM_SYSTEM | 
                FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL,
                dwRetVal,
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                (LPTSTR) &lpMsgBuf,
                0,
                NULL )) {
                printf("\tError: %s", lpMsgBuf);
            }

            printf("Call to GetIpAddrTable failed.\n");
        }
    }

    if ( pIPAddrTable )
        free( pIPAddrTable );

    return 0;
}

/*
 * Extract gateway address from routing table (Windows).
 */
int SetDefaultGateway() {
    PMIB_IPFORWARDTABLE pIpForwardTable;
    DWORD dwRetVal, dwSize;

    unsigned int nord_mask;
    unsigned int nord_ip;
    unsigned int nord_net;

    unsigned int i;

    nord_mask = *((unsigned int *)rgsubnet);
    nord_ip = *((unsigned int *)rgmyip);

    nord_net = nord_ip & nord_mask;

    pIpForwardTable = (MIB_IPFORWARDTABLE*) malloc(sizeof(MIB_IPFORWARDTABLE));
    if (pIpForwardTable == NULL) {
        printf("Error allocating memory\n");
        return 0;
    }

    dwSize = 0;
    if (GetIpForwardTable(pIpForwardTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
        free(pIpForwardTable);
        pIpForwardTable = (MIB_IPFORWARDTABLE*) malloc(dwSize);
        if (pIpForwardTable == NULL) {
            printf("Error allocating memory\n");
            return 0;
        }
    }

    /* 
     * Note that the IPv4 addresses returned in 
     * GetIpForwardTable entries are in network byte order 
     */
    if ((dwRetVal = GetIpForwardTable(pIpForwardTable, &dwSize, 0)) == NO_ERROR) {
        for (i = 0; i < (int) pIpForwardTable->dwNumEntries; i++) {
            unsigned int gwaddr = pIpForwardTable->table[i].dwForwardNextHop;
            if(nord_net == (gwaddr & nord_mask) && nord_ip != gwaddr) 
            { /* searching for gateways from our network with different address than ours */
                memcpy(rggwyip, &gwaddr, 4);
                return 0;
            }
        }
        free(pIpForwardTable);
        return 1;
    }
    else {
        printf("\tGetIpForwardTable failed.\n");
        free(pIpForwardTable);
        return 0;
    }
    
}
/*endif  WIN32*/
#endif

/* 
 * Get_IPMac_Addr
 * This routine finds the IP and MAC for the local interface, 
 * the default gateway, and SNMP alert destination from the 
 * BMC and OS information.
 *
 * Linux snmpd.conf locations (see ipmiutil.spec):
 * RedHat, MontaVista:  /etc/snmp/snmpd.conf
 * SuSE SLES 8:   /etc/ucdsnmpd.conf
 * SuSE SLES 9:   /etc/snmpd.conf
 */
#ifdef WIN32
int Get_IPMac_Addr()
{  				/*for Windows*/
   char ipstr[]  = "IP Address";
   char macstr[] = "Physical Address";
   char gwystr[] = "Default Gateway";
   char substr[] = "Subnet Mask";
   int found = 0;
   char fgetmac;

    if (IpIsValid(rgmyip)) 
    { /* user-specified ip, get mac */
        if (fdebug) printf("User IP was specified\n");
        if (!MacIsValid(rgmymac))
        {  /* no user-specified MAC, get it from IP */
            if (fdebug) printf("No user MAC specified\n");
            if(!GetLocalMACByIP())
            { /* couldn't get MAC from IP, get old one */
                if (fdebug) printf("No MAC from IP, use old\n");
                if(IpIsValid(bmcmyip) && MacIsValid(bmcmymac)) 
                {
                    printf("Using current BMC MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
				            bmcmymac[0], bmcmymac[1],
				            bmcmymac[2], bmcmymac[3],
				            bmcmymac[4], bmcmymac[5]);
                    memcpy(rgmymac,bmcmymac,MAC_LEN);
                } else {
                    printf("Failed to obtain valid MAC\n");
                }
            } else { 
                printf("Using adapter MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
			            rgmymac[0], rgmymac[1],
			            rgmymac[2], rgmymac[3],
			            rgmymac[4], rgmymac[5]);
            }
        } else { /* user MAC available */
            printf("Using user MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
		            rgmymac[0], rgmymac[1],
                            rgmymac[2], rgmymac[3],
                            rgmymac[4], rgmymac[5]);
        }
    } else { /* no user-specified IP */
        if (fdebug) printf("No user IP specified\n");
        if (!MacIsValid(rgmymac))
        {  /* no user-specified MAC, get it from interface */
            if(!GetLocalDataByIface()) 
            {  /* use existing MAC an IP */
                printf("Using current BMC IP %d.%d.%d.%d\n",
				        bmcmyip[0], bmcmyip[1],
				        bmcmyip[2], bmcmyip[3]);
                memcpy(rgmyip,bmcmyip,4);
                printf("Using current BMC MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
				        bmcmymac[0], bmcmymac[1],
				        bmcmymac[2], bmcmymac[3],
				        bmcmymac[4], bmcmymac[5]);
                memcpy(rgmymac,bmcmymac,MAC_LEN);
                
            }
        } else { /* user-specified MAC */
            if(!GetLocalIPByMAC(rgmymac))
            { /* use existing MAC and IP */
                printf("Using current BMC IP %d.%d.%d.%d\n",
				        bmcmyip[0], bmcmyip[1],
				        bmcmyip[2], bmcmyip[3]);
                memcpy(rgmyip,bmcmyip,4);
                printf("Using current BMC MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
				        bmcmymac[0], bmcmymac[1],
				        bmcmymac[2], bmcmymac[3],
				        bmcmymac[4], bmcmymac[5]);
                memcpy(rgmymac,bmcmymac,MAC_LEN);
            }
        }
    }

    if (rghostname[0] == 0) {  /*hostname not specified*/
       if (!fipmilan)
          gethostname(rghostname,sizeof(rghostname));
    }
   if (fdebug)  /* show the local OS eth if and MAC */
	   printf("OS %s IP=%d.%d.%d.%d %s MAC=%02x:%02x:%02x:%02x:%02x:%02x used for arp\n",
                ifname, osmyip[0],osmyip[1],osmyip[2],osmyip[3], rghostname,
		osmymac[0], osmymac[1], osmymac[2], osmymac[3], 
		osmymac[4], osmymac[5]);

    if(!SubnetIsValid(rgsubnet)) {
        SetSubnetMask();
    }
    if (!IpIsValid(rggwyip)) {  /* if gwy ip not user-specified */
        SetDefaultGateway();
	}

    if (lan_ch == gcm_ch) {
	if (SubnetIsSame(rgmyip,rggwyip,rgsubnet)) fgetmac = 1;
	else fgetmac = 0;
    } else fgetmac = 1;

    if (fgetmac) {
      if (IpIsValid(rggwyip) && !MacIsValid(rggwymac)) /*gwy mac not specified*/
	    Get_Mac(rggwyip,rggwymac,NULL);

      if (IpIsValid(rggwy2ip) && !MacIsValid(rggwy2mac)) /*gwy2 mac not valid*/
	    Get_Mac(rggwy2ip,rggwy2mac,NULL);
    }

   return(0);
} /* end Get_IPMac_Addr for Windows */

#elif defined(HPUX)
int Get_IPMac_Addr()
{  				/*for HP-UX*/
    return(-1);
}
#else
int Get_IPMac_Addr()
{  				/*for Linux*/
#if defined(SOLARIS) 
   char rtfile[] = "/tmp/route"; 
   char snmpfile[] = "/etc/snmp/conf/snmpd.conf";
#elif defined(BSD)
   char rtfile[] = "/tmp/route"; 
   char snmpfile[] = "/etc/snmpd.config";
#else
   char rtfile[] = "/proc/net/route";
   char snmpfile[] = "/etc/snmp/snmpd.conf";
#endif
   // char alertfile[] = "/tmp/alert.arping";
   // FILE *fparp;
   FILE *fprt;
   int fd = -1;
   int skfd; 
   uchar *pc;
   int rc = 0;
   int i,j;
   uchar bnetadr[4];
   uchar bgateadr[4];
   char gate_addr[128]; 
   char iface[16]; 
   char defcommunity[19] = "public"; 
   char buff[1024]; 
   char alertname[60];
   int num, nmatch;
   struct ifreq ifr;
   char *_ifname;
   char fgetmac;

   /* Get the IP address and associated MAC address specified. */
   /* Local for ethN; Default Gateway; Alert Destination */

   /* Get the default gateway IP */
#if defined(SOLARIS) || defined(BSD)
   char rtcmd[80];
   sprintf(rtcmd,"netstat -r -n |grep default |awk '{ print $2 }' >%s",rtfile);
   system(rtcmd);
   /* use rtfile output from netstat -r, see also /etc/defaultroute */
   fprt = fopen(rtfile,"r");
   if (fprt == NULL) {
      fprintf(stdout,"netstat: Cannot open %s, errno = %d\n",rtfile,get_errno());
   } else {
      while (fgets(buff, 1023, fprt)) {
	  if ((buff[0] > '0') && (buff[0] <= '9')) { /*valid*/
 	    atoip(bgateadr,buff); 
	    if (fdebug)
	       printf("default gateway: %s, %d.%d.%d.%d %s\n",buff,
                   bgateadr[0], bgateadr[1], bgateadr[2], bgateadr[3],ifname);
 	    if (!IpIsValid(rggwyip))   /* if not user-specified */
	       memcpy(rggwyip,bgateadr,4);
            break;
	  }
      }
      fclose(fprt);
   }  /*end-else good open */
#else
   /* cat /proc/net/route and save Gwy if Dest == 0 and Gateway != 0 */
   fprt = fopen(rtfile,"r");
   if (fprt == NULL) {
      fprintf(stdout,"route: Cannot open %s, errno = %d\n",rtfile,get_errno());
   } else {
      char rtfmt[]  = "%16s %128s %128s %X %d %d %d %128s %d %d %d\n";
      int  iflags, refcnt, use, metric, mss, window, irtt;
      char mask_addr[128], net_addr[128];
      uint *pnet;  
      uint *pgate;

      pnet = (uint *)&bnetadr[0];
      pgate = (uint *)&bgateadr[0];
      while (fgets(buff, 1023, fprt)) {
        num = sscanf(buff, rtfmt,
                     iface, net_addr, gate_addr,
                     &iflags, &refcnt, &use, &metric, mask_addr,
                     &mss, &window, &irtt); 
        if (num < 10 || !(iflags & RTF_UP))
            continue;

	j = 6;
	for (i = 0; i < 4; i ++) {
            bnetadr[i] = htoi(&net_addr[j]);
            bgateadr[i] = htoi(&gate_addr[j]);
	    j -= 2;
	    }
        if ((*pnet == 0) && (*pgate != 0)) {  /* found default gateway */
	    if (fdebug)
	       printf("default gateway: %s, %d.%d.%d.%d %s\n",gate_addr,
                   bgateadr[0], bgateadr[1], bgateadr[2], bgateadr[3],iface);
 	    if (!IpIsValid(rggwyip))   /* if not user-specified */
	       memcpy(rggwyip,bgateadr,4);
            _ifname = iface;  /*use this iface for gwy mac */
            if (!fsetifn) strncpy(ifname,iface,16); 
            break;
	}
      } /*end while*/
      fclose(fprt);
   }  /*end-else good open */
#endif

   /* Create a channel to the NET kernel. */
   if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket");
        return(-3);
   }

   /* Find a valid local BMC MAC Address */
   if (lan_ch == gcm_ch) {
       /* GCM has its own unique mac address */
       if (!MacIsValid(rgmymac)) {
          if (MacIsValid(bmcmymac)) {
            memcpy(rgmymac,bmcmymac,MAC_LEN); /*use existing*/
          } else {   /*error*/
	    printf("invalid MAC address for gcm\n");
          }
       } /*else use rgmymac if specified*/
       _ifname = iface;  /*use the iface from gwy (e.g. eth0) */
       fsharedMAC = 0;   /*gcm has separate NIC, separate MAC*/

       // fd = -1;
       fd = skfd;   // get_socket_for_af(AF_INET) below;
   } else {   /*else not gcm*/
       if (!fsetifn && !fethfound) {  /*do not have ifname yet*/
           i = FindEthNum(bmcmymac);
           if (i >= 0) sprintf(ifname,"%s%d",ifpattn,i);
       }
       ifr.ifr_addr.sa_family = AF_INET;
       if (fdebug) printf("getipmac: ifname=%s\n",ifname);
       _ifname = ifname;
       strcpy(ifr.ifr_name, _ifname);

       /* Get the local if HWADDR (MAC Address) from OS */
       if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) {
	   if (fdebug)
	    printf("ioctl(SIOCGIFHWADDR,%s) error, errno = %d\n",_ifname,get_errno());
       } else memcpy(osmymac,get_ifreq_mac(&ifr),MAC_LEN); /*OS mac*/
	  
       if (memcmp(bmcmymac,osmymac,MAC_LEN) == 0) {
	   /* osmymac and ifname were set above by FindEthNum */
	   printf("\tBMC shares IP/MAC with OS NIC %s\n",_ifname);
	   fsharedMAC = 1;
       } /* else fsharedMAC = 0; */

       if (fsharedMAC == 0) {  /* then BMC has separate MAC */
          if (!MacIsValid(rgmymac) && MacIsValid(bmcmymac)) 
	      memcpy(rgmymac,bmcmymac,MAC_LEN); /*use existing*/
       } else {  /* else OS & BMC share a MAC */
          /* Use the local if HWADDR (MAC Address) from OS */
	  if (!MacIsValid(rgmymac)) {  /* if not user-specified */
	        if (MacIsValid(bmcmymac))  
	             memcpy(rgmymac,bmcmymac,MAC_LEN); /*use existing*/
	        else memcpy(rgmymac,osmymac,MAC_LEN); /*use OS mac*/
	  }
       }
       fd = skfd;   // get_socket_for_af(AF_INET) below;
   } 

   if (fd >= 0) {   /* if valid fd, find OS IP */
        strcpy(ifr.ifr_name, _ifname);
        ifr.ifr_addr.sa_family = AF_INET;
        /* Get the IFADDR (IP Address) from OS */
        if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
	    int err;
	    err = get_errno();
	    /* errno 99 here means that eth0 is not enabled/up/defined. */
            if (err == 99) 
	       printf("ioctl(SIOCGIFADDR) error, %s not enabled\n",_ifname);
            else if (fdebug) 
	          printf("ioctl(SIOCGIFADDR,%s) error, errno=%d\n",_ifname,err);
	} else {  /* got the local OS IP successfully */
	    pc = &ifr.ifr_addr.sa_data[2];
	    if (fdebug)
	      printf("%s addr = %d.%d.%d.%d\n",_ifname,pc[0],pc[1],pc[2],pc[3]);
            memcpy(osmyip, pc, 4);   
 	    if (!IpIsValid(rgmyip) && (fsharedMAC==1)) /*not specified, shared*/
               memcpy(rgmyip, osmyip, 4);   

	    /* get the local OS netmask */
            strcpy(ifr.ifr_name, _ifname);
            if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0) {
		if (fdebug)
	          printf("ioctl(SIOCGIFNETMASK) error, errno=%d\n",get_errno());
		/* if leave invalid, will use default rgsubnet */
            } else {              // sizeof(struct sockaddr)
	       pc = &ifr.ifr_netmask.sa_data[2];
	       if (fdebug)
	          printf("subnet = %d.%d.%d.%d \n", pc[0],pc[1],pc[2],pc[3]);
               memcpy(ossubnet, pc, 4); 
               if (!SubnetIsValid(rgsubnet) && fsharedMAC) /*not specified*/
		  memcpy(rgsubnet, pc, 4);
	    }

            /* Get the localhost OS HWADDR (MAC Address) */
            if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
	       if (fdebug)
		  printf("ioctl(SIOCGIFHWADDR,%s) error, errno = %d\n",
			 _ifname,get_errno());
	    } else memcpy(osmymac,get_ifreq_mac(&ifr),MAC_LEN); /*OS mac*/
	}
   }
   close(skfd);  /* done, close the socket */

   if (rghostname[0] == 0) {  /*hostname not specified*/
       if (!fipmilan)
          gethostname(rghostname,sizeof(rghostname));
   }
   if (fdebug)  /* show the local OS eth if and MAC */
	   printf("OS %s IP=%d.%d.%d.%d %s MAC=%02x:%02x:%02x:%02x:%02x:%02x used for arp\n",
                _ifname, osmyip[0],osmyip[1],osmyip[2],osmyip[3], rghostname,
		osmymac[0], osmymac[1], osmymac[2], osmymac[3], 
		osmymac[4], osmymac[5]);

   if (!IpIsValid(rgmyip) && IpIsValid(bmcmyip)) {
       /* If no user-specified IP and there is a valid IP already in the 
        * BMC LAN configuration, use the existing BMC LAN IP.  */
       memcpy(rgmyip,bmcmyip,4);
       if (fdebug) printf("Using current IP %d.%d.%d.%d\n",
				bmcmyip[0], bmcmyip[1],
				bmcmyip[2], bmcmyip[3]);
   }

   /* Get the default gateway MAC */
   if (lan_ch == gcm_ch) {
	if (SubnetIsSame(osmyip,rggwyip,ossubnet)) fgetmac = 1;
	else {  /* gateway is not on the same subnet as RMM/GCM */
	   fgetmac = 0; /*don't try to get mac if not the same subnet*/
	   if ((fset_ip & GWYIP) == 0) memset(rggwyip,0,4);
	}
   } else fgetmac = 1;
   if (fgetmac && IpIsValid(rggwyip) && !MacIsValid(rggwymac)) 
        Get_Mac(rggwyip,rggwymac,NULL); /*gwy mac not specified, so get mac*/

   /* Get the Alert Destination IP */
   /* By default, attempt to obtain this from /etc/snmp/snmpd.conf. */
   /* cat /etc/snmp/snmpd.conf | grep trapsink |tail -n1 | cut -f2 -d' ' */
   alertname[0] = 0;  /* default to null string */
   fprt = fopen(snmpfile,"r");
   if (fprt == NULL) {
      printf("snmp: Cannot open %s, errno = %d\n",snmpfile,get_errno());
   } else {
      // char snmpfmt[] = "%20s %60s\n";
      // char *keywd, *value;
      while (fgets(buff, 1023, fprt)) {
	/* parse each line */
	if (buff[0] == '#') continue;  /*skip comment lines*/
	/* skip leading whitespace here */
	j = strspn(&buff[0]," \t");
	if (strncmp(&buff[j],"com2sec",7) == 0) {  /* found community line */
	   /* usu like this: "com2sec demouser default  public" */
	   i = j + 7;
	   for (j = 0; j < 3; j++) {
	     num = strspn(&buff[i]," \t");
	     i += num;
	     num = strcspn(&buff[i]," \t\r\n");
	     if (j < 2) i += num;
	   }
	   buff[i+num] = 0;
 	   if (fsetcommunity == 0) {  /* if not user-specified */
	      strcpy(rgcommunity,&buff[i]);
	      strcpy(defcommunity,&buff[i]);
	   }
	}
#ifdef BSD
	if (strncmp(&buff[j],"traphost :=",11) == 0) nmatch = 11;
	else nmatch = 0;
#else
	if (strncmp(&buff[j],"trapsink",8) == 0) nmatch = 8;
	else if (strncmp(&buff[j],"trap2sink",9) == 0) nmatch = 9;
	else nmatch = 0;
#endif
	if (nmatch > 0) { /* found trapsink line match */
	   if (fdebug) printf("%s: %s",snmpfile,&buff[j]);
	   num = strspn(&buff[j+nmatch]," \t");
	   i = j + nmatch + num;
	   if (buff[i] == '`') continue;
	   num = strcspn(&buff[i]," \t\r\n");
	   strncpy(alertname,&buff[i],num);   /* save alert destination */
	   alertname[num] = 0;
	   i += num;
	   num = strspn(&buff[i]," \t"); /*skip whitespace*/
	   i += num;
	   num = strcspn(&buff[i]," \t\r\n");  /*span next word*/
	   if (num != 0) {  /* there is another word, that is community */
 	      if (fsetcommunity == 0) {  /* if not user-specified */
	         strncpy(rgcommunity,&buff[i],num); /* save community */
		 rgcommunity[num] = 0;
		 }
	   } else {  /*have trapsink node with no community*/
	      /* use previously discovered default community from above */
	      strcpy(rgcommunity,defcommunity);
	   }
	   /* dont break, keep looking, use the last one */
	}
      } /*end while*/
      fclose(fprt);
      if (fdebug) 
	printf("snmp alertname=%s community=%s\n",alertname,rgcommunity);
   }  /*end else snmpfile*/
   
   /* Get the Alert Destination MAC from the alertname. */
   if (alertname[0] != 0) {
#ifdef TEST
      char arping_cmd[128];
      char *pb, *pm, *px;
      int num, i;
      if (fdebug) printf("alert %s ip=%d.%d.%d.%d osip=%d.%d.%d.%d "
			 "mac=%02x:%02x:%02x:%02x:%02x:%02x "
			 "osmac=%02x:%02x:%02x:%02x:%02x:%02x\n",
		alertname, 
		rgdestip[0], rgdestip[1], rgdestip[2], rgdestip[3],
		osmyip[0], osmyip[1], osmyip[2], osmyip[3],
		rgdestmac[0], rgdestmac[1], rgdestmac[2], rgdestmac[3], 
		rgdestmac[4], rgdestmac[5],
		osmymac[0], osmymac[1], osmymac[2], osmymac[3], 
		osmymac[4], osmymac[5]);
#endif
      if (!IpIsValid(rgdestip)) {    /* if not user-specified with -A */
	if (IpIsValid(bmcdestip)) {  /* use existing if valid */
            memcpy(rgdestip,bmcdestip,4);
	    if (MacIsValid(bmcdestmac))
	       memcpy(rgdestmac,bmcdestmac,MAC_LEN);
	} 
	else if ((strncmp(alertname,"localhost",9) == 0) ) 
	{   /* snmpd.conf = localhost (self) is the SNMP alert destination */
	  if (IpIsValid(osmyip))
	    memcpy(rgdestip,osmyip,4);
	  if (!MacIsValid(rgdestmac)) {   /* if not user-specified */
	    // Get_Mac(rgdestip,rgdestmac,alertname);  (wont work for local)
	    memcpy(rgdestmac,osmymac,MAC_LEN);
	  }
        } /*endif local */
      }
      if (!MacIsValid(rgdestmac))    /* if MAC not vaild or user-specified */
      {
         /* Use arping to get MAC from alertname or IP */
 	 Get_Mac(rgdestip,rgdestmac,alertname);
      } 
   }  /*endif have alertname*/

   return(rc);
} /* end Get_IPMac_Addr */
#endif

int ShowChanAcc(uchar bchan)
{
    LAN_RECORD LanRecord;
    int ret = 0;
    uchar access;
    char *pstr;
    uchar pb0, pb1;

    if (bchan == lan_ch) pstr = "lan";
    else if (bchan == ser_ch) pstr = "ser";
    else pstr = "?";
    ret = GetChanAcc(bchan, 0x40, &LanRecord);
    if (fdebug)
         printf("  GetChanAcc(%d), ret = %d, data = %02x %02x\n",
 	        bchan,ret, LanRecord.data[0], LanRecord.data[1]);
    pb0 = LanRecord.data[0];
    pb1 = LanRecord.data[1];
    if (fcanonical)
      printf("Channel %d Access Mode %s%c ",bchan,pspace3,bdelim);
    else
      printf("Channel(%d=%s) Access Mode: %02x %02x : ",bchan,pstr,pb0,pb1);
    access = pb0;
    switch (access & 0x03) {
	     case 0: printf("Disabled, ");     break;
	     case 1: printf("Pre-Boot, ");     break;
	     case 2: printf("Always Avail, "); break;
	     case 3: printf("Shared, ");       break;
	     }
    if (access & 0x20) printf("PEF Alerts Disabled\n"); /*0*/
    else printf("PEF Alerts Enabled\n");   /*1*/
    return(ret);
}

static int GetSessionInfo(uchar *rData, int sz)
{
   int rv, rlen;
   uchar ccode;
   uchar iData[5];

   iData[0] = 0x00;  /*get data for this session*/
   rlen = sz;
   rv = ipmi_cmdraw(CMD_GET_SESSION_INFO,NETFN_APP, BMC_SA,PUBLIC_BUS,BMC_LUN,
			iData,1,rData, &rlen, &ccode, fdebug);
   if ((rv == 0) && (ccode != 0)) rv = ccode;
   return(rv);
}

static int GetPefCapabilities(uchar *bmax)
{
   int rv, rlen;
   uchar ccode;
   uchar rData[MAX_BUFFER_SIZE];

   rlen = sizeof(rData);
   rv = ipmi_cmdraw(0x10, NETFN_SEVT, BMC_SA,PUBLIC_BUS,BMC_LUN,
                        NULL,0,rData, &rlen, &ccode, fdebug);
   if ((rv == 0) && (ccode != 0)) rv = ccode;
   if ((rv == 0) && (bmax != NULL))
      *bmax = rData[2]; /*max num PEF table entries*/
   return(rv);
}

int GetSerialOverLan( uchar chan, uchar bset, uchar block )
{
	uchar requestData[24];
	uchar rData[MAX_BUFFER_SIZE];
	int rlen;
	int status, i;
	uchar ccode;
	uchar enable_parm, auth_parm, baud_parm;
	ushort getsolcmd;
	uchar user;

        if (fIPMI20 && fSOL20) {
	   getsolcmd = GET_SOL_CONFIG2;
	   enable_parm = SOL_ENABLE_PARAM;
	   auth_parm   = SOL_AUTHENTICATION_PARAM;
	   baud_parm   = SOL_BAUD_RATE_PARAM;
	} else {
	   getsolcmd = GET_SOL_CONFIG;
	   enable_parm = SOL_ENABLE_PARAM;
	   auth_parm   = SOL_AUTHENTICATION_PARAM;
	   baud_parm   = SOL_BAUD_RATE_PARAM;
	   chan = 0;  /*override chan for IPMI 1.5*/
	}
	if (!fcanonical)
	   printf("%s, GetSOL for channel %d ...\n",progname,chan);

	requestData[0] = chan;  /*channel*/
	requestData[1] = enable_parm;
	requestData[2] = bset;    /*set*/
	requestData[3] = block;   /*block*/
	rlen = sizeof(rData);
        status = ipmi_cmd(getsolcmd, requestData,4, rData, &rlen,&ccode,fdebug);
	if (status != 0) return(status);
	if (ccode) {
		if (ccode == 0xC1) { /* unsupported command */
		   printf("Serial-Over-Lan not available on this platform\n");
		   return(status);
		} else {
	     	   printf("SOL Enable ccode = %x\n",ccode);
	     	   status = ccode;
		}
	} else {  /*success*/
	     if (fcanonical) {
	        printf("Channel %d SOL Enable %s",chan,pspace3);
	     } else {
	        printf("SOL Enable: ");
	        for (i = 1; i < rlen; i++) printf("%02x ",rData[i]);
	     }
             if (rData[1] == 0x01) printf("%c enabled\n",bdelim);
	     else printf("%c disabled\n",bdelim);
	}

	if (!fcanonical) 
	{
	  requestData[0] = chan;
	  requestData[1] = auth_parm;
	  requestData[2] = bset;   // selector
	  requestData[3] = block;  // block
	  rlen = sizeof(rData);
          status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); 
	  if (status != 0) return(status);
	  if (ccode) {
	     printf("SOL Auth ccode = %x\n",ccode);
	     status = ccode;
	  } else {  /*success*/
	     printf("SOL Auth: ");
	     for (i = 1; i < rlen; i++) printf("%02x ",rData[i]);
	     printf(": ");
             show_priv(rData[1]);  /* priv level = User,Admin,... */
	     printf("\n");
	  }

	  requestData[0] = chan;
	  requestData[1] = SOL_ACC_INTERVAL_PARAM;
	  requestData[2] = bset;
	  requestData[3] = block;
	  rlen = sizeof(rData);
          status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); 
	  if (status != 0) return(status);
	  if (ccode) {
	     printf("SOL Accum Interval ccode = %x\n",ccode);
	     status = ccode;
	  } else {  /*success*/
	     printf("SOL Accum Interval: ");
	     for (i = 1; i < rlen; i++) printf("%02x ",rData[i]);
             printf(": %d msec\n",(rData[1] * 5));
          }

	  requestData[0] = chan;
	  requestData[1] = SOL_RETRY_PARAM;
	  requestData[2] = bset;
	  requestData[3] = block;
	  rlen = sizeof(rData);
          status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug);
	  if (status != 0) return(status);
	  if (ccode) {
	     printf("SOL Retry ccode = %x\n",ccode);
	     status = ccode;
	  } else {  /*success*/
	     printf("SOL Retry Interval: ");
	     for (i = 1; i < rlen; i++) printf("%02x ",rData[i]);
             printf(": %d msec\n",(rData[2] * 10));
          }
        }

        if (!fRomley)
	{
	  requestData[0] = chan;
	  requestData[1] = baud_parm;
	  requestData[2] = bset;
	  requestData[3] = block;
	  rlen = sizeof(rData);
          status = ipmi_cmd(getsolcmd,requestData,4,rData, &rlen,&ccode,fdebug);
	  if (status != 0) return(status);
	  if (ccode) {
	     printf("SOL nvol Baud ccode = %x\n",ccode);
	     status = ccode;
	  } else {  /*success*/
	     uchar b;
	     if (fcanonical) {
	        printf("Channel %d SOL Baud Rate%s",chan,pspace3);
	     } else {
	        printf("SOL nvol Baud Rate: ");
	        for (i = 1; i < rlen; i++) printf("%02x ",rData[i]);
	     }
	     /* if not user-specified and previously enabled, use existing */
	     b = (rData[1] & 0x0f);
	     if ((fnewbaud == 0) && BaudValid(b)) { 
		sol_baud = b; 
		sol_bvalid = 1; 
	     }
             printf("%c %s\n",bdelim,Baud2Str(b));
          }

	  if (!fcanonical) 
	  {
	    requestData[0] = chan;
	    requestData[1] = SOL_VOL_BAUD_RATE_PARAM;  /*0x06*/
	    requestData[2] = bset;
	    requestData[3] = block;
	    rlen = sizeof(rData);
            status = ipmi_cmd(getsolcmd,requestData,4,rData,&rlen,&ccode,fdebug); 
	    if (status != 0) return(status);
	    if (ccode) {
	       printf("SOL vol Baud ccode = %x\n",ccode);
	       status = ccode;
	    } else {  /*success*/
	       printf("SOL vol Baud Rate: ");
	       for (i = 1; i < rlen; i++) printf("%02x ",rData[i]);
               printf("%c %s\n",bdelim,Baud2Str(rData[1]));
	    }
	  }
	}
        if (fIPMI20) {
	   if (!fcanonical) {
	    requestData[0] = chan;  
	    rlen = sizeof(rData);
	    status = ipmi_cmdraw(GET_PAYLOAD_SUPPORT, NETFN_APP, 
			BMC_SA,PUBLIC_BUS,BMC_LUN,
			requestData,1,rData, &rlen, &ccode, fdebug);
            if ((status != 0) || (ccode != 0)) {
	      printf("SOL Payload Support error %d, ccode = %x\n",status,ccode);
	      if (status == 0) status = ccode;
            } else {  /*success*/
	      printf("SOL Payload Support(%d): ",chan);
	      for (i = 0; i < rlen; i++) printf("%02x ",rData[i]);
              printf("\n");
            }
	   } /*endif not canonical*/
	   /* get Payload Access for 4 users, not just lan_user */
	   for (user = 1; user <= show_users; user++)
	   {
             /* mBMC doesn't support more than 1 user */
	     if (fmBMC && (user > 1)) break;
	     /* IPMI 2.0 has >= 4 users */
	     requestData[0] = chan;  
	     requestData[1] = user;  
	     rlen = sizeof(rData);
	     status = ipmi_cmdraw(GET_PAYLOAD_ACCESS, NETFN_APP, 
			BMC_SA,PUBLIC_BUS,BMC_LUN,
			requestData,2,rData, &rlen, &ccode, fdebug);
             if ((status != 0) || (ccode != 0)) {
	       printf("SOL Payload Access(%d,%d) error %d, ccode = %x\n",
				chan,user,status,ccode);
	       if (status == 0) status = ccode;
             } else {  /*success*/
	       if (fcanonical) {
		 printf("Channel %d SOL Payload Access(user%d)%s",chan,user,
			pspace1);
	       } else {
		 printf("SOL Payload Access(%d,%d): ",chan,user);
		 for (i = 0; i < rlen; i++) printf("%02x ",rData[i]);
               }  
	       if ((rData[0] & 0x02) != 0) printf("%c enabled\n",bdelim);
	       else printf("%c disabled\n",bdelim);
             }
           }  /*end user loop*/
        }

	return(status);
} /*end GetSerialOverLan */

/*
ECHO SOL Config Enable
CMDTOOL 20 30 21 %1 01 01
 
ECHO SOL Authentication (Administrator)
CMDTOOL 20 30 21 %1 02 04
 
ECHO SOL Accumlate Interval and threshold
CMDTOOL 20 30 21 %1 03 06 14
 
ECHO SOL Retry Interval and threshold
CMDTOOL 20 30 21 %1 04 06 14
 
ECHO SOL non-volatile baud rate
CMDTOOL 20 30 21 %1 05 07
 
ECHO SOL volatile baud rate
CMDTOOL 20 30 21 %1 06 07
 
ECHO Set user Payload Access for user 1
CMDTOOL 20 18 4c %1 01 02 00 00 00
 */
int SetupSerialOverLan( int benable )
{
	uchar requestData[24];
	uchar responseData[MAX_BUFFER_SIZE];
	int responseLength = MAX_BUFFER_SIZE;
	int status;
	uchar completionCode;
	uchar enable_parm, auth_parm, baud_parm;
	ushort setsolcmd;
	ushort getsolcmd;
        uchar bchan;

        if (fIPMI20 && fSOL20) {
	   setsolcmd = SET_SOL_CONFIG2;
	   getsolcmd = GET_SOL_CONFIG2;
	   enable_parm = SOL_ENABLE_PARAM;
	   auth_parm   = SOL_AUTHENTICATION_PARAM;
	   baud_parm   = SOL_BAUD_RATE_PARAM;
           bchan = lan_ch;
	} else {
	   setsolcmd = SET_SOL_CONFIG;
	   getsolcmd = GET_SOL_CONFIG;
	   enable_parm = SOL_ENABLE_PARAM;
	   auth_parm   = SOL_AUTHENTICATION_PARAM;
	   baud_parm   = SOL_BAUD_RATE_PARAM;
           bchan = 0x00;  /*override chan for IPMI 1.5*/
	}
	memset(requestData, 0, sizeof(requestData));  /* zero-fill */
	requestData[0] = bchan;
	requestData[1] = enable_parm;
	if (benable == 0)
	   requestData[2] = SOL_DISABLE_FLAG;
	else 
	   requestData[2] = SOL_ENABLE_FLAG;
	responseLength = MAX_BUFFER_SIZE;
        status = ipmi_cmd(setsolcmd, requestData,3,responseData,
                        &responseLength, &completionCode, fdebug); 
	if (status == ACCESS_OK) {
		switch( completionCode ) {
		   case 0x00: /* success */
			break;
		   case 0xC1: /* unsupported command */
			SELprintf("SetupSerialOverLan: SOL not available on this platform\n");
			return 0;
		   default: /* other error */
			SELprintf("SetupSerialOverLan: SOL_ENABLE_PARAM ccode=%x\n",
					completionCode);
			return -1;
			break;
		}
	} else {
		SELprintf( "SET_SOL_CONFIG, enable SOL failed\n" );
	 	return -1;
 	}
	if (benable == 0) return 0;

	requestData[0] = bchan; /* channel */
	requestData[1] = auth_parm;
	requestData[2] = 0x00; /* set selector */
	requestData[3] = 0x00; /* block selector */
	responseLength = MAX_BUFFER_SIZE;
        status = ipmi_cmd(getsolcmd, requestData,4,responseData,
                        &responseLength, &completionCode, fdebug); 
	if (status == ACCESS_OK) {
		if( completionCode ) {
			SELprintf("SetupSerialOverLan: GET_SOL_AUTHENTICATION_PARAM code=%x\n",
				completionCode);

			return -1;
		}
	} else {
		SELprintf( "SOL_CONFIG, get SOL authentication failed\n" );
	 	return -1;
 	}

	requestData[0] = bchan;
	requestData[1] = auth_parm;
	requestData[2] = SOL_PRIVILEGE_LEVEL_USER | ( responseData[1] & 0x80 );
	responseLength = MAX_BUFFER_SIZE;
	status = ipmi_cmd(setsolcmd, requestData,3,responseData,
			&responseLength, &completionCode, fdebug);
	if (status == ACCESS_OK) {
		if( completionCode ) {
			SELprintf("SET_SOL_AUTHENTICATION_PARAM code=%x\n",
				completionCode);

			return -1;
		}
	} else {
		SELprintf( "SET_SOL_CONFIG, set SOL authentication failed\n" );
	 	return -1;
 	}

	requestData[0] = bchan;
	requestData[1] = SOL_ACC_INTERVAL_PARAM;
	requestData[2] = sol_accum[0]; //0x04;
	requestData[3] = sol_accum[1]; //0x32;
	responseLength = MAX_BUFFER_SIZE;
        if (fdebug) SELprintf("Setting SOL AccumInterval\n");
	status = ipmi_cmd(setsolcmd, requestData,4,responseData,
			&responseLength, &completionCode, fdebug);
	if (status != ACCESS_OK || completionCode) {
	   SELprintf("SET SOL AccumInterval ret=%d ccode=%x\n", 
			status,completionCode);
	   return -1;
        }

	/* Some BMCs return sporadic errors for SOL params (e.g. Kontron)*/
        // if (vend_id == VENDOR_KONTRON) ; 
	// else
	{
	   requestData[0] = bchan;
	   requestData[1] = SOL_RETRY_PARAM;
	   requestData[2] = sol_retry[0]; //0x06;
	   requestData[3] = sol_retry[1]; //0x14;
	   responseLength = MAX_BUFFER_SIZE;
           if (fdebug) SELprintf("Setting SOL RetryInterval\n");
	   status = ipmi_cmd(setsolcmd, requestData,4,responseData,
			   &responseLength, &completionCode, fdebug);
	   if (status != ACCESS_OK || completionCode) {
	      SELprintf("SET SOL RetryInterval ret=%d ccode=%x\n", 
			status,completionCode);
	      return -1;
           }
        }

        if (fRomley) ;  /* skip SOL BAUD */ 
	else {  /* else SOL BAUD is used, so set it. */
          if (fnewbaud == 0) {  /* no user-specified SOL baud */
	    /* if sol_bvalid, sol_baud was set to existing value above */
	    if (!sol_bvalid) {
               status = GetSerEntry(7, (LAN_RECORD *)&responseData);
               if (status == 0) {  /* use Serial baud for SOL */
                sol_baud = responseData[1];
                if (fdebug) SELprintf("Serial Baud is %s\n",Baud2Str(sol_baud));
               }
            }
          }
	  requestData[0] = bchan;
	  requestData[1] = baud_parm;
	  requestData[2] = sol_baud;
	  responseLength = MAX_BUFFER_SIZE;
          if (fdebug) SELprintf("Setting SOL BAUD to %s\n",Baud2Str(sol_baud));
	  status = ipmi_cmd(setsolcmd, requestData,3,responseData,
			  &responseLength, &completionCode, fdebug);
	  if (status != ACCESS_OK || completionCode) {
	     SELprintf("SET SOL BAUD ret=%d ccode=%x\n", status,completionCode);
	     return -1;
          }

	  requestData[0] = bchan;
	  requestData[1] = SOL_VOL_BAUD_RATE_PARAM;
	  requestData[2] = sol_baud;
	  responseLength = MAX_BUFFER_SIZE;
          if (fdebug) 
              printf("Setting SOL vol BAUD to %s\n",Baud2Str(sol_baud));
	  status = ipmi_cmd(setsolcmd, requestData,3,responseData,
			&responseLength, &completionCode, fdebug);
	  if (status != ACCESS_OK || completionCode) {
	    printf("SET SOL vol BAUD ret=%d ccode=%x\n",status,completionCode);
	    return -1;
          }
        }

        if (fIPMI20 && fSOL20) {
	   if (vend_id == VENDOR_KONTRON && lan_user == 1) {
              if (fdebug) SELprintf("Skipping SOL Payload Access for user %d\n",
				lan_user);
	   } else {
              if (fdebug) SELprintf("Setting SOL Payload Access for user %d\n",
				lan_user);
	      requestData[0] = bchan;  
	      requestData[1] = lan_user;  /*enable this user*/
	      requestData[2] = 0x02;      /*enable std 2.0 SOL*/
	      requestData[3] = 0;
	      requestData[4] = 0;
	      requestData[5] = 0;
	      responseLength = MAX_BUFFER_SIZE;
	      status = ipmi_cmdraw(SET_PAYLOAD_ACCESS, NETFN_APP, 
			BMC_SA,PUBLIC_BUS,BMC_LUN,
			requestData,6,responseData, &responseLength, 
			&completionCode, fdebug);
	      if (status != ACCESS_OK || completionCode) {
	         SELprintf("SET SOL Payload Access ret=%d ccode=%x\n",
			   status,completionCode);
	         return -1;
              }
           }
        }
	return 0;
}  /*end SetupSerialOverLan */

static char *PefDesc(int idx, uchar stype)
{
   char *pdesc, *p;
   static char mystr[60];
   int mylen = sizeof(mystr);
   pdesc = &mystr[0];
   if (pefdesc != NULL) strcpy(pdesc,pefdesc[idx]); /* if Intel, pre-defined */
   else strcpy(pdesc,"reserved");             /* else set default to detect */
   if ((stype != 0) && (strcmp(pdesc,"reserved") == 0)) {
      /* Dynamically set the pef desc string from the sensor type */
      switch(stype) {  
         case 0x01: strcpy(pdesc,"Temperature");    break;
         case 0x02: strcpy(pdesc,"Voltage");  break;
         case 0x04: strcpy(pdesc,"Fan");      break;
         case 0x05: strcpy(pdesc,"Chassis");  break;
         case 0x07: strcpy(pdesc,"BIOS");     break;
         case 0x08: strcpy(pdesc,"Power Supply");   break;
         case 0x09: strcpy(pdesc,"Power Unit");   break;
         case 0x0c: strcpy(pdesc,"Memory");   break;
         case 0x0f: strcpy(pdesc,"Boot");     break;
         case 0x12: strcpy(pdesc,"System Restart"); break;
         case 0x13: strcpy(pdesc,"NMI"); break;
         case 0x23: strcpy(pdesc,"Watchdog"); break;
         case 0x20: strcpy(pdesc,"OS Critical Stop"); break;
         default:   
#ifdef METACOMMAND
		p = get_sensor_type_desc(stype); 
		if (p != NULL) { 
		   strncpy(pdesc,p,mylen);
		   mystr[mylen-1] = 0; /*stringify*/
		}
#else
		sprintf(pdesc,"Other[%02x]",stype);
#endif
		break;
      }
      if (pef_array[idx-1][4] == PEF_SEV_OK) strcat(pdesc," OK");
   }
   return(pdesc);
}


#ifdef METACOMMAND
int i_lan(int argc, char **argv)
#else
#ifdef WIN32
int __cdecl
#else
int
#endif
main(int argc, char **argv)
#endif
{
   int ret;
   PEF_RECORD PefRecord;
   LAN_RECORD LanRecord;
   int i, idx, j;
   int c;
   char *pstr;
   uchar bset;
   int ndest = 4;
   int idest;
   char mystr[80];
   char fpefok = 1;
   uchar * pc; int sz; 

   // progname = argv[0];
   printf("%s ver %s \n",progname,progver);
   j = 0; freadonly = FLAG_INIT;
   idx = argc;  /*getopt loop counter*/
   /* available opt chars: y O Q + = ~ _ */
   while ((c = getopt(argc, argv,"a:b:cdef:gh:i:j:klm:n:op:q:rstu:v:w:xy:z#::A:B:C:DEF:G:H:I:J:K:L:M:N:P:Q:R:S:T:U:V:X:YZ:?")) != EOF) {
      switch(c) {
          case 'a':      /* alert dest number (usu 1 thru 4) */
		    alertnum = atob(optarg);
		    if (alertnum > alertmax) alertnum = 1;
		    j++;
		    break;
          case 'b': bAuth = htoi(optarg); j++; break; /*undocumented*/
          case 'c': fcanonical = 1; bdelim = BDELIM; break;
          case 'd': fenable = 0; fdisable = 1; freadonly = 0; break;
          case 'e': fenable = 1; fdisable = 0; freadonly = 0; break;
          case 'f': i = atoi(optarg);    /*set arp_ctl*/
		    if (i < 0 || i > 3) printf("Invalid ARP control %d\n",i);
		    else {
			arp_ctl = i;
			fsetarp = 1;
		 	j++;
		    }
		    break;
          case 'l': fpefenable = 0;  fenable = 2; 
                    fdisable = 0; freadonly = 0; break;
	  case 'h':      /* VLAN ID */
		i = atoi(optarg);
		if (i > 4095) vlan_enable = 0;
		else {
		   vlan_enable = 1;
		   vlan_id = (ushort)i;
		}
		j++;
		break;
	  case 'y':      /* Intel LAN Failover enable/disable */
		i = atoi(optarg);
		if (i == 1) failover_enable = 1;
		else failover_enable = 0;
		j++;
		break;
	  case 'Q':      /* VLAN Priority */
		i = atoi(optarg);
		if (i > 7 || i < 0) vlan_enable = 0;
		else {
		   vlan_enable = 1;
		   vlan_prio = (uchar)i;
		}
		j++;
		break;
	  case 'i':      /* eth interface (ifname) */
          	fsetifn = 1;
		i = sizeof(ifname);
		if (strlen(optarg) > (uint)i) optarg[i] = 0;
		strcpy(ifname,optarg);
                if (fdebug) printf("ifname = %s\n",ifname);
		j++;
		break;
          case 'j': fCustomPEF = 1;     /*custom 10 PEF bytes */
                    fpefenable = 1;   /* PEF is implied here */
                    freadonly = 0; 
		    memset(custPEF,0,sizeof(custPEF));
                    custPEF[0] = htoi(&optarg[0]);  /*action  */
                    custPEF[1] = htoi(&optarg[2]);  /*policy  */
                    custPEF[2] = htoi(&optarg[4]);  /*severity*/
                    custPEF[3] = htoi(&optarg[6]);  /*genid1  */
                    custPEF[4] = htoi(&optarg[8]);  /*genid2  */
                    custPEF[5] = htoi(&optarg[10]); /*sensor_type*/
                    custPEF[6] = htoi(&optarg[12]); /*sensor_num */
                    custPEF[7] = htoi(&optarg[14]); /*evt_trigger*/
                    custPEF[8] = htoi(&optarg[16]); /*data1offset*/
                    custPEF[9] = htoi(&optarg[18]); /*data1mask  */
		    if (optarg[20] != 0) {  
			/* optionally get 8 extra PEF entry bytes */
                        custPEF[10] = htoi(&optarg[20]); /*data1cmp1 */
                        custPEF[11] = htoi(&optarg[22]); /*data1cmp2 */
                        custPEF[12] = htoi(&optarg[24]); /*data2mask */
                        custPEF[13] = htoi(&optarg[26]); /*data2cmp1 */
                        custPEF[14] = htoi(&optarg[28]); /*data2cmp2 */
                        custPEF[15] = htoi(&optarg[30]); /*data3mask */
                        custPEF[16] = htoi(&optarg[32]); /*data3cmp1 */
                        custPEF[17] = htoi(&optarg[34]); /*data3cmp2 */
		    }
		    j++;
		    break;
          case 'k': fSetPEFOks = 1; j++; break;  /*configure PEF OK rules */
          case 'm': set_max_kcs_loops(atoi(optarg)); break;
          case 'n':      /* number/index in PEF table to insert new entry */
                fpefenable = 1;
		pefnum = atob(optarg);
		if (pefnum >= MAXPEF) {
                   pefnum = MAXPEF - 1;
                   fAdjustPefNum = 1;
                } else fUserPefNum = 1;
		j++;
		break;
          case 'o': fdisableSOL = 1;    /*disable SOL only*/
                    fpefenable = 0;   /*no change to PEF*/
                    freadonly = 0; 
		    break;  
          case 'r': freadonly = 1; fenable = 0; break;
          case 's': fgetser = 1;   break;
          case 't': ftestonly = 1; freadonly = 1;  break;
          case 'v':      /* user access privilege level */
		i = atoi(optarg);
		if (valid_priv(i)) lan_access = i & 0x0f;
		else printf("Invalid privilege -v %d, using Admin\n",i);
		j++;
		break;
          case 'w': i = atoi(optarg);  /*set grat arp interval, in #sec*/
		    if (i >= 0 && i < 256) arp_interval = i * 2;
		    else printf("Invalid arp interval -w %d, skipping\n",i);
		    break;
          case 'x': fdebug = 1;     break;
          case 'z': flanstats = 1;     break;
          case 'D': lan_dhcp = 1; j++;  break;
          case 'I':      /* My BMC IP Address */
		fset_ip |= MYIP;
		atoip(rgmyip,optarg);
		j++;
		break;
          case 'M':      /* My BMC MAC Address */
		atomac(rgmymac,optarg);
		j++;
		break;
          case 'S':      /* Subnet IP Address */
		atoip(rgsubnet,optarg);
		j++;
		break;
          case 'G':      /* Gateway IP Address */
		fset_ip |= GWYIP;
		atoip(rggwyip,optarg);
		j++;
		break;
          case 'g':      /* Secondary Gateway IP Address */
		fset_ip |= GWYIP;
		atoip(rggwy2ip,optarg);
		j++;
		break;
          case 'H':      /* Gateway MAC Address */
		atomac(rggwymac,optarg);
		j++;
		break;
          case 'B':      /* SOL Baud rate */
                fnewbaud = 1;
                sol_baud = Str2Baud(optarg);
		j++;
		break;
          case 'A':      /* Alert Dest IP Address */
		fset_ip |= DESTIP;
		/* allow name or ip here via Get_Mac() ? */
		atoip(rgdestip,optarg);
                fpefenable = 1;   /* PEF is implied here */
		j++;
		break;
          case 'X':      /* Alert Dest MAC Address */
		atomac(rgdestmac,optarg);
                fpefenable = 1;   /* PEF is implied here */
		j++;
		break;
          case 'K':      /* Kontron IPMI hostname */
		i = sizeof(rghostname);  /*usu 18*/
		if (strlen(optarg) > (uint)i) optarg[i] = 0;
		strcpy(rghostname,optarg);
		j++;
		break;
          case 'C':      /* Community String */
		fsetcommunity = 1;
		i = sizeof(rgcommunity);  /*usu 18*/
		if (strlen(optarg) > (uint)i) optarg[i] = 0;
		strcpy(rgcommunity,optarg);
                fpefenable = 1;   /* PEF is implied here */
		j++;
		break;
	  case 'u': 	 /* username to set */
		myuser = strdup_(optarg);  /*remote username */
		j++;
		break;
	  case 'p':      /* password to set */
		fpassword = 1;
		if (strlen(optarg) > PSW_MAX) optarg[PSW_MAX] = 0;
		strcpy(passwordData,optarg);
                if (fdebug) printf("Password = %s\n",passwordData);
		/* Hide password from 'ps' */
	        memset(optarg, ' ', strlen(optarg));	
		j++;
		break;
          case 'q':
          case '#':
                usernum = atob(optarg);
                if (usernum > 15) usernum = 0;  /*MAX_IPMI_USERS = 15*/
		j++;
                break;
          case 'L': 
		lan_ch_parm = atob(optarg);
		if (lan_ch_parm > MAXCHAN) lan_ch_parm = PARM_INIT; /*invalid*/
		break;
          case 'V':    /* priv level */
		fprivset = 1;
          case 'N':    /* nodename */
          case 'U':    /* remote username */
          case 'P':    /* remote password */
          case 'R':    /* remote password */
          case 'E':    /* get password from IPMI_PASSWORD environment var */
          case 'F':    /* force driver type */
          case 'T':    /* auth type */
          case 'J':    /* cipher suite */ 
          case 'Y':    /* prompt for remote password */
          case 'Z':    /* set local MC address */
                parse_lan_options(c,optarg,fdebug);
                break;
	  default:
             printf("Usage: %s [-abcdefghijklmnopq#rstuvwxyzBDQK]\n",progname);
             printf("         \t [-a alertnum -i eth1 -n pefnum ]\n");
             printf("         \t [-I ipadr -M macadr -S subnet ]\n");
             printf("         \t [-G gwyip -H gwymac -L lan_channel_num]\n");
             printf("         \t [-A alertip -X alertmac -C community ]\n");
             printf("         \t [-g 2nd_gwyip  -v priv  -B sol_baud ]\n");
             printf("         \t [-j 10_bytes_custom_pef -b authmask ]\n");
             printf("where -c  shows Canonical, simpler output format\n");
             printf("      -d  Disables BMC LAN & PEF\n");
             printf("      -e  Enables BMC LAN & PEF\n");
             printf("      -f  set ARP Control to 1=grat, 2=resp, 3=both\n");
             printf("      -g  secondary Gateway IP (-G=primary_gwy_ip)\n");
             printf("      -h  VLAN ID (>=4096 to disable)\n");
	     printf("      -j  specify custom PEF rule (10 or 18 hex bytes)\n");
	     printf("      -k  add PEF oK rules, if PEF enable\n");
             printf("      -l  Enables BMC LAN only, not PEF\n");
             printf("      -o  disable Only SOL\n");
             printf("      -p  password to set \n");
             printf("   -q/-#  User number of LAN username_to_set\n");
             printf("      -r  Read-only BMC LAN & PEF settings\n");
             printf("      -s  Show some Serial settings also \n");
             printf("      -t  Test if BMC LAN is already configured\n");
             printf("      -u  username to set \n");
             printf("      -v  access priVilege: 4=Admin,3=Operator,2=User\n");
             printf("      -w  set Grat ARP Interval to specified # seconds\n");
             printf("      -x  Show eXtra debug messages\n");
             printf("      -y  Intel LAN Failover (1=enable,0=disable)\n");
             printf("      -z  Show IPMI LAN statistics\n");
             printf("      -B  Baud for SerialOverLan (19.2K,115.2K,...)\n");
             printf("      -D  Use DHCP instead of static IP (-I for server)\n");
             printf("      -K  (Kontron) IPMI hostname to set\n");
             printf("      -Q  VLAN Priority (default =0)\n");
	     print_lan_opt_usage();
	     ret = ERR_USAGE;
             goto do_exit;
      } /*end switch*/
      nopts++;
   } /*end while*/

   if ((freadonly == FLAG_INIT) && (j > 0)) {
      /* got some options implying set, but no -e -l -d option specified. */
      foptmsg = 1;    /*show warning message later*/
      freadonly = 1;  /*assume read only*/
   }
   fipmilan = is_remote();
   if (fipmilan && !fprivset) 
	parse_lan_options('V',"4",0); /*even if freadonly request admin*/
   if ((fsetarp == 0) && ostype == OS_WINDOWS) 
		arp_ctl = 0x03;  /*grat arp & arp resp enabled */

   ret = GetDeviceID( &LanRecord);
   if (ret != 0) {
	goto do_exit;
   } else {  /* success */
      uchar ipmi_maj, ipmi_min;
      ipmi_maj = LanRecord.data[4] & 0x0f;
      ipmi_min = LanRecord.data[4] >> 4;
      show_devid( LanRecord.data[2],  LanRecord.data[3], ipmi_maj, ipmi_min);
      if (ipmi_maj == 0)  fIPMI10 = 1;
      else if (ipmi_maj == 1 && ipmi_min < 5) fIPMI10 = 1; 
      else  fIPMI10 = 0;    /* >= IPMI 1.5 is ok */
      if (ipmi_maj >= 2) fIPMI20 = 1;
      if (fIPMI20) show_users = 5;
      else show_users = 3;
      if (fIPMI10) {
         printf("This IPMI v%d.%d system does not support PEF records.\n",
			 ipmi_maj,ipmi_min);
	 /* Wont handle PEF, but continue and look for BMC LAN anyway */
	 // fIPMI10 = 1;
	 // ipmi_close_();
	 // exit(1);  
         }
      prod_id = LanRecord.data[9] + (LanRecord.data[10] << 8);
      vend_id = LanRecord.data[6] + (LanRecord.data[7] << 8) 
			 	  + (LanRecord.data[8] << 16);
      /* check Device ID response for Manufacturer ID = 0x0322 (NSC) */
      if (vend_id == VENDOR_NSC) {         /* NSC = 0x000322 */
	 fmBMC = 1;  /*NSC miniBMC*/
	 if (pefnum == 12) pefnum = 10;  /* change CritStop pefnum to 0x0a */
	 pefdesc = &pefdesc2[0];  /*mini-BMC PEF*/
	 pefmax = 30;
         fsharedMAC = 1;  /* shared MAC with OS */
      } else if (vend_id == VENDOR_LMC) {  /* LMC (on SuperMicro) = 0x000878 */
	 pefdesc = NULL;  /* unknown, see PefDesc() */
	 if (pefnum == 12) pefnum = 15;  /* change CritStop pefnum */
	 pefmax  = 16;
         fsharedMAC = 0;  /* not-shared BMC LAN port */
      } else if (vend_id == VENDOR_INTEL) {  /* Intel = 0x000157 */
	 pefdesc = &pefdesc1[0];  /*default Intel PEF*/
	 pefmax  = 20;            /*default Intel PEF*/
         switch(prod_id) {
         case 0x4311:  /* Intel NSI2U w SE7520JR23 */
 	   fmBMC = 1;  /* Intel miniBMC*/
	   if (pefnum == 12) pefnum = 14;  /* change CritStop pefnum */
	   pefdesc = &pefdesc2[0];  /*mini-BMC PEF*/
	   pefmax = 30;
           fsharedMAC = 1;  /* shared-MAC BMC LAN port, same MAC */
           break;
         case 0x0022:  /* Intel TIGI2U w SE7520JR23 +IMM*/
           fsharedMAC = 1;  /* shared-MAC BMC LAN port, same MAC */
           gcm_ch = 3;      /* IMM GCM port, dedicated MAC */
	   show_users = 4;
	   break;
	 case 0x000C:  /*TSRLT2*/
	 case 0x001B:  /*TIGPR2U*/
	   /* fmBMC=0; Intel Sahalee BMC*/
           fsharedMAC = 1;  /* shared-MAC BMC LAN port, same MAC */
           break;
         case 0x0026:  /*S5000 Bridgeport*/
         case 0x0028:  /*S5000PAL Alcolu*/
         case 0x0029:  /*S5000PSL StarLake*/
         case 0x0811:  /*S5000PHB TIGW1U */
	   /* fmBMC=0;   Intel Sahalee ESB2 BMC*/
           fsharedMAC = 0;  /* not-shared BMC LAN port, separate MAC */
           gcm_ch = 3;
	   parm7 = &iparm7[0]; /*TTL=30*/
           break;
         case 0x003E:  /*NSN2U or CG2100 Urbanna*/
	   fiBMC = 1;  /* Intel iBMC */
           fsharedMAC = 0;  /* not-shared BMC LAN port, separate MAC */
           // gcm_ch = 3;
	   parm7 = &iparm7[0]; /*TTL=30*/
	   if (fsetarp == 0) 
	      arp_ctl = 0x02;    /*grat arp disabled, arp resp enabled */
	   arp_interval = 0x00;  /*0 sec, since grat arp disabled */
	   sol_accum[0] = 0x0c;  /*Intel defaults*/
	   sol_accum[1] = 0x60;  /*Intel defaults*/
	   sol_retry[0] = 0x07;  /*Intel defaults*/
	   sol_retry[1] = 0x32;  /*Intel defaults*/
           set_max_kcs_loops(URNLOOPS); /*longer for SetLan cmds (default 300)*/
           break;
         case 0x0107:  /* Intel Caneland*/
           fsharedMAC = 0;  /* not-shared BMC LAN port, separate MAC */
           gcm_ch = 3;
           break;
         case 0x0100:  /*Tiger2 ia64*/
	   /* for ia64 set chan_pefon, chan_pefoff accordingly*/
	   chan_pefon  = CHAN_ACC_PEFON64;
	   chan_pefoff = CHAN_ACC_PEFOFF64;
	   /* fall through */
         default:      /* else other Intel */
	   /* fmBMC = 0;  * Intel Sahalee BMC*/
           if (fIPMI20) fsharedMAC = 0;  /* recent, not-shared BMC MAC */
	   else fsharedMAC = 1;  /* usu IPMI 1.x has shared BMC MAC */
           break;
         } /*end switch*/
	 if (is_romley(vend_id,prod_id)) { 
	    fRomley = 1;
	    fiBMC = 1;  /* Intel iBMC */
            fsharedMAC = 0;  /* not-shared BMC LAN port, separate MAC */
            set_max_kcs_loops(URNLOOPS); /*longer for SetLan (default 300)*/
	    fipv6 = 1;
	    if (fsetarp == 0) arp_ctl = 0x03; /*default to both for Romley*/
	 }
      } else {  /* else other vendors  */
         if (fIPMI20) fsharedMAC = 0;  /* recent, not-shared BMC MAC */
	 else fsharedMAC = 1;  /* usu IPMI 1.x has shared BMC MAC */
	 pefdesc = NULL;  /* unknown, see PefDesc() */
	 if (pefnum == 12) pefnum = 15;  /* change CritStop pefnum to 15? */
	 pefmax  = 20;
         if (!fUserPefNum) fAdjustPefNum = 1;
      }
      if (fmBMC) show_users = 1; /* mBMC doesn't support more than 1 user */
   }

   ret = GetPefCapabilities(&bset);
   if ((ret == 0) && (bset <= MAXPEF)) pefmax = bset;

   /* Get the BMC LAN channel & match it to an OS eth if. */
   i = GetBmcEthDevice(lan_ch_parm);
   if (i == -2) {  /* no lan channels found (see lan_ch) */
	if (lan_ch_parm == PARM_INIT)
	   printf("This system does not support IPMI LAN channels.\n");
	else  /*specified a LAN channel*/
	   printf("BMC channel %d does not support IPMI LAN.\n",lan_ch_parm);
	ret = LAN_ERR_NOTSUPPORT;
	goto do_exit;
   } else if (i < 0) {  /* mac not found, use platform defaults */
        i = 0;   /* default to eth0, lan_ch set already. */
        if (vend_id == VENDOR_INTEL) {
           if ((prod_id == 0x001B) || (prod_id == 0x000c)) {
              /* Intel TIGPR2U or TSRLT2 defaults are special */
              if (lan_ch_parm == 6)
                   { i = 0; lan_ch = 6; }
              else { i = 1; lan_ch = 7; }
              ser_ch = 1;
           }
        }
   }
   if ((i == gcm_ch) && (gcm_ch != PARM_INIT) && (lan_ch_parm == PARM_INIT)) {
	/* Has a GCM, defaulted to it, and user didn't specify -L */
	/* Need this to avoid picking channel 3, the IMM/RMM GCM channel. */
	lan_ch = 1;  /*default BMC LAN channel*/
	// i = 0;       /*default eth0 (was eth1) */
   }
   if (fsetifn == 0) { /*not user specified, use the detected one*/
       // if (lan_ch == gcm_ch) strcpy(ifname,"gcm");
       sprintf(ifname,"%s%d",ifpattn,i); /*eth%d*/
   }
   if (fdebug) printf("lan_ch = %d, ifname = %s\n",lan_ch,ifname);

   /* set the lan_user appropriately */
   if (myuser == NULL) lan_user = 1;   /*use default user if no -u param*/
   else if (usernum != 0) lan_user = usernum;  /*use -q specified usernum*/
   /* else use default lan_user (=2) if -u and not -q */  

   if (ftestonly) {  /*test only if BMC LAN is configured or not */
      /* TODO: test gcm also, if present */
      ret = GetLanEntry(4, 0, &LanRecord);  /*ip addr src*/
      if (ret == 0) {
         if ((LanRecord.data[0] == SRC_BIOS) ||
             (LanRecord.data[0] == SRC_DHCP)) ret = 0; /* DHCP, so ok */ 
         else {  /*static IP*/
            ret = GetLanEntry(3, 0, &LanRecord); /* ip address */
            if (ret == 0) {
	       if (!IpIsValid(LanRecord.data)) {
		  printf("invalid BMC IP address\n");
		  ret = 1; /* invalid ip */
               } else ret = GetLanEntry(12, 0, &LanRecord); /*gateway ip*/
               if (ret == 0) {
	          if (!IpIsValid(LanRecord.data)) {
		     printf("invalid gateway ip\n");
		     ret = 2; /*invalid gwy ip*/
		  } else ret = GetLanEntry(13, 0, &LanRecord);
                  if (ret == 0) {
                     if (!MacIsValid(&LanRecord.data[0])) {
			printf("invalid gateway mac\n");
			ret = 3; /*invalid gwy mac */
		     }
                  }
               }
	    }
         }
      } /*endif GetLanEntry ok*/
      if (ret == 0) printf("BMC LAN already configured\n");
      else printf("BMC LAN not configured\n");
      goto do_exit;
   } /*endif ftestonly*/

   memset(SessInfo,0,sizeof(SessInfo));
   ret = GetSessionInfo(SessInfo,sizeof(SessInfo)); 
   // rlen = sizeof(SessInfo)); ret = get_session_info(0,0,SessInfo,&rlen); 
   if (fdebug) printf("GetSessionInfo ret=%d, data: %02x %02x %02x %02x \n",
			ret,SessInfo[0],SessInfo[1],SessInfo[2],SessInfo[3]);
   if (!freadonly && fipmilan) {  /* setting LAN params, and using IPMI LAN */
      if (SessInfo[2] > 1) { /* another session is active also */
	 printf("Another session is also active, cannot change IPMI LAN settings now.\n");
         ret = ERR_NOT_ALLOWED;
         goto do_exit;
      }
   }

   if (!fIPMI10) {
      if (fcanonical) 
      {  /* canonical/simple output */
       ret = GetPefEntry(0x01, 0,(PEF_RECORD *)&LanRecord);  
       if (ret != 0) ndest = 0;
       else {   /*success*/
         j = LanRecord.data[0];
         mystr[0] = 0;
         if (j == 0) strcat(mystr,"none ");
	 else {
            if (j & 0x01) strcat(mystr,"PEFenable ");
            if (j & 0x02) strcat(mystr,"DoEventMsgs ");
            if (j & 0x04) strcat(mystr,"Delay ");
            if (j & 0x08) strcat(mystr,"AlertDelay ");
	 }
	 printf("PEF Control %s%c %s\n",pspace4,bdelim,mystr);
       } 
      } else {  /* normal/full output */
       ret = GetPefEntry(0x01, 0,(PEF_RECORD *)&LanRecord);  
       if (ret == 0 && (LanRecord.data[0] != 0)) {
	   fpefok = 1;
           bmcpefctl = LanRecord.data[0];
       } else {   /* skip PEF rules/params if disabled */
	 printf("PEF Control %s%c %s\n",pspace4,bdelim,"none ");
	 ndest = 0;
	 fpefok = 0; 
       }
       
       if (fpefok) {
        printf("%s, GetPefEntry ...\n",progname);
        for (idx = 1; idx <= pefmax; idx++)
        {
         ret = GetPefEntry( 0x06, (ushort)idx, &PefRecord);
         if (ret == 0) {    // Show the PEF record
            char *pa;
            pc = (uchar *)&PefRecord;
            sz = 21;        // sizeof(PEF_RECORD) = 21
	    if (PefRecord.sensor_type == 0) {
	      if (idx <= pefnum) 
                 printf("PEFilter(%02d): empty\n",idx);
              memcpy(pef_array[idx-1], &PefRecord, sz);
              if (fAdjustPefNum) pefnum = (char)idx;
	    } else {
              memcpy(pef_array[idx-1], &PefRecord, sz);
	      if (PefRecord.fconfig & 0x80) pc = "enabled";
	      else pc = "disabled";
	      i = PefRecord.rec_id;
              switch(PefRecord.action) {
		 case 0x01: pa = "alert";    break;
		 case 0x02: pa = "poweroff"; break;
		 case 0x04: pa = "reset";    break;
		 case 0x08: pa = "powercycle"; break;
		 case 0x10: pa = "OEMaction";  break;
		 case 0x20: pa = "NMI";  break;
                 default:   pa = "no action"; 
              }
              printf("PEFilter(%02d): %02x %s event - %s for %s\n",
		     idx, PefRecord.sensor_type, 
                     PefDesc(i,PefRecord.sensor_type), pc,pa);
	    }
	    if (fdebug) {  /* show raw PEFilter record */
		pc = &PefRecord.rec_id;
		printf("raw PEF(%.2d):  ",pc[0]);
		for (i = 0; i < sz; i++) printf("%02x ",pc[i]);
		printf("\n");
	    }
         } else {
            printf("GetPefEntry(%d), ret = %d\n",idx,ret);
	    if (ret == 0xC1) {  /*PEF is not supported, so skip the rest. */
		fpefok = 0;
		ndest = 0; /* if no PEF, no alerts & no alert dest */
		break;
	    }
	 }
        }
       } /*endif fpefok*/
       if (fpefok) {  
        if (fdebug) ShowPef();
        ret = GetPefEntry(0x01, 0,(PEF_RECORD *)&LanRecord);  
        if (ret == 0) {
           j = LanRecord.data[0];
           mystr[0] = 0;
           if (j & 0x01) strcat(mystr,"PEFenable ");
           if (j & 0x02) strcat(mystr,"DoEventMsgs ");
           if (j & 0x04) strcat(mystr,"Delay ");
           if (j & 0x08) strcat(mystr,"AlertDelay ");
	   printf("PEF Control: %02x : %s\n",j, mystr);
        }
        ret = GetPefEntry(0x02, 0,(PEF_RECORD *)&LanRecord);
        if (ret == 0) {
           j = LanRecord.data[0];
           mystr[0] = 0;
           if (j & 0x01) strcat(mystr,"Alert ");
           if (j & 0x02) strcat(mystr,"PwrDn ");
           if (j & 0x04) strcat(mystr,"Reset ");
           if (j & 0x08) strcat(mystr,"PwrCyc ");
           if (j & 0x10) strcat(mystr,"OEM ");
           if (j & 0x20) strcat(mystr,"DiagInt ");
	   printf("PEF Actions: %02x : %s\n",j, mystr);
        }
        ret = GetPefEntry(0x03, 0,(PEF_RECORD *)&LanRecord);
        if (ret == 0) printf("PEF Startup Delay: %02x : %d sec\n",
			   LanRecord.data[0],LanRecord.data[0]);
        if (!fmBMC) {
	   ret = GetPefEntry(0x04, 0,(PEF_RECORD *)&LanRecord);
	   if (ret == 0) printf("PEF Alert Startup Delay: %02x: %d sec\n",
			   LanRecord.data[0],LanRecord.data[0]);
	   /* fmBMC gets cc=0x80 here */
        }
        /* note that ndest should be read from lan param 17 below. */
        for (i = 1; i <= ndest; i++)
        {
           ret = GetPefEntry(0x09, (ushort)i,(PEF_RECORD *)&LanRecord);
           if (ret == 0) {
	    mystr[0] = 0;
            j = LanRecord.data[2];
            if (LanRecord.data[1] & 0x08) {
               sprintf(mystr,"Chan[%d] Dest[%d] ",((j & 0xf0) >> 4),(j & 0x0f));
               strcat(mystr,"Enabled ");
            } else strcpy(mystr,"Disabled ");
	    printf("PEF Alert Policy[%d]: %02x %02x %02x %02x : %s\n",i,
				LanRecord.data[0], LanRecord.data[1], 
				LanRecord.data[2], LanRecord.data[3],mystr);
           }
        } /*endfor ndest*/
       } /*endif fpefok*/
     } /*endif not canonical*/

     if (fpefenable && !freadonly) { /* fenable or fdisable */
       if (fSetPEFOks) pefadd = 5;
       else pefadd = 2;
       sz = (pefnum - 1) + pefadd + fCustomPEF;
       printf("\n%s, SetPefEntry(1-%d) ...\n",progname,sz);
       if (fdebug) printf("pefnum = %d, pefmax = %d\n",pefnum,pefmax);
       for (idx = 1; idx <= pefmax; idx++)
       {
	 // Set & Enable all PEF records
         memset(&PefRecord.rec_id,0,sizeof(PEF_RECORD));
         PefRecord.rec_id  = (uchar)idx; /* next record, or user-specified */
	 if (idx < pefnum) {  /* pefnum defaults to 12.(0x0c) */
	    if (pef_array[idx-1][7] == 0) /*empty pef record, set to default*/
               memcpy(&PefRecord.rec_id,pef_defaults[idx-1],sizeof(PEF_RECORD));
	    else  { /* set config however it was previously */
               memcpy(&PefRecord.rec_id,pef_array[idx-1],sizeof(PEF_RECORD));
               if (PefRecord.severity == 0) 
                  PefRecord.severity = pef_defaults[idx-1][4];
            }
	 } else if ((idx == pefnum) &&  /* new OS Crit Stop entry */
	            (PefRecord.sensor_type == 0)) {
            // Set PEF values for 0x20, OS Critical Stop event 
            PefRecord.severity      = PEF_SEV_CRIT;
            PefRecord.genid1        = 0xff;
            PefRecord.genid2        = 0xff;
            PefRecord.sensor_type   = 0x20; /* OS Critical Stop */
            PefRecord.sensor_no     = 0xff;
            PefRecord.event_trigger = 0x6f;
            PefRecord.data1         = 0xff;
            PefRecord.mask1         = 0x00;
	 } else if ((idx == pefnum+1) &&  /* new Power Redundancy entry */
	            (PefRecord.sensor_type == 0)) {
            // Set PEF values for 0x09/0x02/0x0b/0x41, Power Redundancy Lost 
            PefRecord.severity      = PEF_SEV_WARN;
            PefRecord.genid1        = 0xff;
            PefRecord.genid2        = 0xff;
            PefRecord.sensor_type   = 0x09;  /* Power Unit */
            PefRecord.sensor_no     = 0xff;  /* usu 01 or 02 */
            PefRecord.event_trigger = 0x0b;  /* event trigger */
            PefRecord.data1         = 0x02;  /* 02 -> 41=Redundancy Lost */
            PefRecord.mask1         = 0x00;
	 } else if (fSetPEFOks && idx == (pefnum+2)) {
            PefRecord.severity      = PEF_SEV_OK;
            PefRecord.genid1        = 0xff;
            PefRecord.genid2        = 0xff;
            PefRecord.sensor_type   = 0x09;  /* Power Unit, Redund OK */
            PefRecord.sensor_no     = 0xff;  /* usu 01 or 02 */
            PefRecord.event_trigger = 0x0b;  /* event trigger */
            PefRecord.data1         = 0x01;  /* 01 -> 40=Redundancy OK */
            PefRecord.mask1         = 0x00;
	 } else if (fSetPEFOks && idx == (pefnum+3)) {
            PefRecord.severity      = PEF_SEV_OK;
            PefRecord.genid1        = 0xff;
            PefRecord.genid2        = 0xff;
            PefRecord.sensor_type   = 0x01;  /* Temp OK */
            PefRecord.sensor_no     = 0xff;  /* usu 01 or 02 */
            PefRecord.event_trigger = 0x81;  /* event trigger */
            PefRecord.data1         = 0x95;  /* 95 -> 50(NC),52(Crit) match */
            PefRecord.mask1         = 0x0a;
	 } else if (fSetPEFOks && idx == (pefnum+4)) {
            PefRecord.severity      = PEF_SEV_OK;
            PefRecord.genid1        = 0xff;
            PefRecord.genid2        = 0xff;
            PefRecord.sensor_type   = 0x02;  /* Voltage OK */
            PefRecord.sensor_no     = 0xff;  /* usu 01 or 02 */
            PefRecord.event_trigger = 0x81;  /* event trigger */
            PefRecord.data1         = 0x95;  /* 95 -> 50(NC),52(Crit) match */
            PefRecord.mask1         = 0x0a;
	 } else if (fCustomPEF && idx == (pefnum+pefadd)) {
            /* user entered 10 or 18 PEF entry bytes */
            PefRecord.action        = custPEF[0];
            PefRecord.policy        = custPEF[1];
            PefRecord.severity      = custPEF[2];
            PefRecord.genid1        = custPEF[3];
            PefRecord.genid2        = custPEF[4];
            PefRecord.sensor_type   = custPEF[5];
            PefRecord.sensor_no     = custPEF[6];
            PefRecord.event_trigger = custPEF[7];
            PefRecord.data1         = custPEF[8];
            PefRecord.mask1         = custPEF[9];
	    memcpy(&PefRecord.action,custPEF,18); 
	 } else {
            memcpy(&PefRecord.rec_id,pef_array[idx-1],sizeof(PEF_RECORD));
            if (PefRecord.sensor_type == 0) continue; /* if reserved, skip it */
         }
	 if (fdebug && (PefRecord.rec_id != idx)) {
	    /* memcpy from pef_defaults or pef_array clobbered rec_id */
	    printf("Warning: SetPef idx=%d, rec_id=%d\n",idx,PefRecord.rec_id);
            PefRecord.rec_id  = (uchar)idx; /*fix it*/
	 }
         if (fdisable) {
            /* Disable all PEF rules */
	    if (idx >= pefnum) PefRecord.fconfig = 0x00; /*disabled, software*/
	    else PefRecord.fconfig = 0x40;               /*disabled, preset */
            PefRecord.action   = 0x00;
            PefRecord.policy   = 0x00;
	 } else {    /*fenable*/
            if (PefRecord.sensor_type != 0) { /* not an empty PEF entry */
              /* Enable all non-empty PEF rules */
	      if (fCustomPEF && (idx == (pefnum+pefadd))) {
                 PefRecord.action   = custPEF[0];
                 PefRecord.policy   = custPEF[1];
              } else {
                 PefRecord.action   = 0x01;  /*Alert*/
                 PefRecord.policy   = 0x01;  /*see Alert Policy #1*/
              }
	      if (idx < pefnum) { /* special handling for presets, 1 thru 11 */
	          PefRecord.fconfig  = 0x80;    /* enabled, software */
                  ret = SetPefEntry(&PefRecord);
                  if (fdebug) 
                     printf("SetPefEntry(%d/80) ret=%d\n",PefRecord.rec_id,ret);
		  // if (ret != 0) { nerrs++; lasterr = ret; }
		  // else ngood++;
		  PefRecord.fconfig  = 0xC0;     /* enabled, preset */
	      } else {
	          PefRecord.fconfig  = 0x80;         /* enabled, software */
	      }
	    }  /*endif not empty*/
	 }
         {  // Show the new PEF record before setting it.
            pc = (uchar *)&PefRecord;
            sz = 21;
            printf("PEFilter(%d): ",PefRecord.rec_id);
            for (i = 0; i < sz; i++) printf("%02x ",pc[i]);
                  printf("\n");
         } 
         ret = SetPefEntry(&PefRecord);
         if (fdebug) 
             printf("SetPefEntry(%d) ret = %d\n", PefRecord.rec_id,ret); 
	 if (ret != 0) { nerrs++; lasterr = ret; }
	 else ngood++;
       }  /*end for*/
      }
     }  /*end if not fIPMI10*/

     if (!fcanonical) 
        printf("\n%s, GetLanEntry for channel %d ...\n",progname,lan_ch);
     idest = 1;
     for (idx = 0; idx < NLAN; idx++)
     {
	 int ival;
	 if (fcanonical && (canon_param[idx] == 0)) continue;
         if (idx == 8 || idx == 9) continue;	  /* not implemented */
	 ival = lanparams[idx].cmd;
         if (ival >= 96 && ival <= 98) continue;  /* not implemented */
	 if (ival >= 102 && ival <= 108) { /*custom IPv6 parameters*/
	     if (fipv6 == 0) continue;  /*skip these*/
	 }
	 if (ival == 194 && vend_id == VENDOR_KONTRON) { /*oem hostname parm*/
	     lanparams[idx].sz = 36;
	     strcpy(lanparams[idx].desc,"IPMI Hostname");
	 } else if (ival >= 192 && ival <= 194) { /*custom DHCP parameters*/
	     if (vend_id != VENDOR_INTEL) continue;
	     if (fmBMC || fiBMC || fcanonical) continue;  /*skip these*/
	 }
	 if (ival >= 20 && ival <= 25) {
            if (!fIPMI20) continue;  /*VLAN params 20-25, fIPMI20 only/opt*/
	 }
	 if ((ndest == 0) && (ival >= 18 && ival <= 19)) continue; /*skip dest*/
         if (ival == 14 || ival == 15) {  /*secondary gateway is optional*/
	    if (vend_id == VENDOR_KONTRON) continue;
	 }
         if (ival == 201) {  /*Get Channel Access*/
             ret = ShowChanAcc(lan_ch);
	 } else {
	     if (ival == 18 || ival == 19) {  /*dest params*/
		if (ndest == 0) continue;  /*skip if ndest==0 */
		bset = (uchar)idest;  /* dest id = 1 thru n */
	     } else bset = 0;
             ret = GetLanEntry((uchar)ival, bset, &LanRecord);
	 }
         if (ret == 0) {    // Show the LAN record
            pc = (uchar *)&LanRecord;
            sz = lanparams[idx].sz; 
	    if (ival == 201) ;  /* did it above */
            else {
		if (fcanonical) {
		   if ((ival == 19) && (idest > 1)) ; /*skip it*/
		   else {
			j = strlen(lanparams[idx].desc);
			// (ival < 7) || (ival == 19) || ival == 102)
			if (j <= 12) pstr = pspace3;
			else pstr = pspace2; 
			printf("Channel %d %s %s%c ",lan_ch,
				lanparams[idx].desc,pstr,bdelim);
		   }
		} else
		   printf("Lan Param(%d) %s: ",ival,lanparams[idx].desc);
	    }
	    if (ival == 1) {
		authmask = pc[0]; /* auth type support mask */
		/* if (fmBMC) authmask is usually 0x15, else 0x14 */
            } else if (ival == 3) {
                if (IpIsValid(pc)) memcpy(bmcmyip,pc,4);
	    } else if (ival == 5) {
		if (MacIsValid(pc)) memcpy(bmcmymac,pc,MAC_LEN);
	    } else if (ival == 6) {
		if (SubnetIsValid(pc)) memcpy(bmcsubnet,pc,4);
		/* else if invalid, leave default as 255.255.255.0 */
	    //} else if (ival == 7) { 
	    //   if (pc[0] >= 30) memcpy(bparm7,pc,3);
	    } else if (ival == 17)  {  /* num dest */
		ndest = pc[0];  /* save the number of destinations */
	    } else if (ival == 19)  {  /* dest addr */
                if (IpIsValid(&pc[3])) memcpy(bmcdestip,&pc[3],4);
		if (MacIsValid(&pc[7])) memcpy(bmcdestmac,&pc[7],MAC_LEN);
	    }
	    /* now start to display data */
	    if (ival == 16) { printf("%s \n",pc);      /* string */
	    } else if (ival == 194 && vend_id == VENDOR_KONTRON) { 
		printf("%s \n",pc);      /* string */
	    } else if (ival == 201) {  ;      /* did it above */
	    } else {  /* print results for all other ival's */
	      pstr = ""; /*interpreted meaning*/
	      if (fcanonical) {
		switch(ival) {
		  case 4:   /*param 4, ip src*/
		   if (pc[0] == SRC_STATIC) pstr = "Static";  /*0x01*/
		   else if (pc[0] == SRC_DHCP) pstr = "DHCP"; /*0x02*/
		   else if (pc[0] == SRC_BIOS) pstr = "BIOS"; /*0x03*/
		   else  pstr = "Other"; 
		   printf("%s\n",pstr);
		   break;
		  case 5:   /*param 5, mac addr*/
		  case 13:  /*param 6, def gwy mac*/
		   printf("%02x:%02x:%02x:%02x:%02x:%02x\n", 
			pc[0], pc[1], pc[2], pc[3], pc[4], pc[5]);
		   break;
		  case 3:   /*param 4, ip address*/
		  case 6:   /*param 6, subnet mask*/
		  case 12:  /*param 6, def gwy ip*/
		   printf("%d.%d.%d.%d\n",pc[0], pc[1], pc[2], pc[3]);
		   break;
		  case 19:  /*param 19, dest address*/
		   if (idest == 1) {
		      printf("IP=%d.%d.%d.%d "
				"MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", 
				pc[3], pc[4], pc[5], pc[6],
				pc[7], pc[8], pc[9], pc[10], pc[11], pc[12]);
		   }
		   break;
		  case 102:  /*param 102, IPv6 enable*/
 		   if (pc[0] == 0x01) printf("enabled\n");
		   else printf("disabled\n");
		   break;
		  default:
		   printf("%02x \n",pc[0]);
		   break;
		}
	      } else {  /*not canonical */
                for (i = 0; i < sz; i++) {
		  /* print in hex, decimal, or string, based on ival */
	  	  if (ival == 3 || ival == 6 || ival == 12 || ival == 14 ||
		      ival == 192) {
		     printf("%d ",pc[i]);      /* IP addresses in dec */
		  } else if (ival == 1)  {   /* Auth type support */
		     pstr = &mystr[0];
		     getauthstr(authmask,pstr);
		     printf("%02x ",authmask);
		  } else if (ival == 4)  {   /* IP addr source */
		     if (pc[i] == SRC_STATIC) pstr = "Static";  /*0x01*/
		     else if (pc[i] == SRC_DHCP) pstr = "DHCP"; /*0x02*/
		     else if (pc[i] == SRC_BIOS) pstr = "BIOS"; /*0x03*/
		     else  pstr = "Other"; 
		     printf("%02x ",pc[i]);
		  } else if (ival == 10)  {   /* grat ARP */
                     mystr[0] = 0;
		     if (pc[i] == 0) strcat(mystr,"ARP disabled ");
		     else if (pc[i] & 0x01) strcat(mystr,"Grat-ARP enabled");
		     else strcat(mystr,"Grat-ARP disabled");
		     if (pc[i] & 0x02) strcat(mystr,", ARP-resp enabled");
		     pstr = &mystr[0];
		     printf("%02x ",pc[i]);
		  } else if (ival == 11)  {   /* grat ARP interval */
		     float f;
		     f = (float)pc[i] / (float)2; /*500msec increments*/
		     sprintf(mystr,"%.1f sec",f);
		     pstr = &mystr[0];
		     printf("%02x ",pc[i]);
		  } else if (ival == 19)  {  /* dest addr */
		     if (i > 2 && i < 7) {
			char *sepstr;
		        if (i == 3) printf("[");
			if (i == 6) sepstr = "] ";
			else sepstr = " ";
		      printf("%d%s",pc[i],sepstr);  /* IP address in dec */
		      }
		      else printf("%02x ",pc[i]);  /* show mac/etc. in hex */
		   }
	 	   else printf("%02x ",pc[i]);  /* show in hex */
	        }  /*end for*/
		if (ival == 2) {  /*Auth type enables*/
		     pstr = &mystr[0];
		     i = 0;
		     if (lan_ch > 0) i = lan_ch - 1; 
		     getauthstr(pc[i],pstr);
		}
	        if (pstr[0] != 0) printf(": %s\n",pstr);
	        else printf("\n");
	      }  /*end-else not canonical*/
	    }  /*end-else others*/
	    if (ival == 18 || ival == 19) {
		if (idest < ndest) {
		   idest++;
		   idx--;  /* repeat this param*/
		} else idest = 1;
	    }
         } else {  /* ret != 0 */
	    if (ival >= 20 && ival <= 25) { /*if errors, optional*/
	       if (fdebug) printf("GetLanEntry(%d), ret = %d\n",ival,ret);
	    } else  
	       printf("GetLanEntry(%d), ret = %d\n",ival,ret);
	    if (ival == 17)  ndest = 0;  /*error getting num dest*/
	 }
     }  /*end for*/
     if (fRomley) {  /*get LAN Failover param*/
	 uchar b;
         ret = lan_failover_intel(0xFF,(uchar *)&b);
         if (ret != 0) 
            printf("Intel Lan Failover, ret = %d\n",ret);
	 else {
	    if (b == 1) pstr = "enabled";
	    else pstr = "disabled";
	    if (fcanonical) 
                 printf("Intel Lan Failover  %s%c %s\n",
			pspace3, bdelim,pstr);
	    else printf("Intel Lan Failover %s%c %02x %c %s\n",
			pspace2, bdelim,b,bdelim,pstr);
	 }
     }
     // if (fmBMC) lan_access = 0x04;  /*Admin*/
     // else lan_access = 0x04; /*Admin*/
     if (!fIPMI10) {  /* Get SOL params */
	ret = GetSerialOverLan(lan_ch,0,0);
	if (ret != 0) printf("GetSOL error %d\n",ret);
     }
     for (i = 1; i <= show_users; i++)
	   GetUser((uchar)i);

     if (fgetser && !fcanonical) {
       printf("\n%s, GetSerEntry ...\n",progname);
       if (fmBMC)   /* mBMC doesn't support serial */
	  printf("No serial channel support on this platform\n");	
       else
       for (idx = 0; idx < NSER; idx++) {
   	 int ival;
         // if (idx == 9) continue; /* not implemented */
	 ival = serparams[idx].cmd;
         if (ival == 201) {
             ret = GetChanAcc(ser_ch, 0x40, &LanRecord);
	 } else {
             ret = GetSerEntry((uchar)ival, &LanRecord);
	 }
         if (ret == 0) {    // Show the SER record
            pc = (uchar *)&LanRecord;
            sz = serparams[idx].sz; 
            printf("Serial Param(%d) %s: ",ival,serparams[idx].desc);
            if (idx == 10) {  /* modem init string */
                pc[sz] = 0;
                printf("%02x %s\n",pc[0],&pc[1]);
                }
            else if ((idx >= 11 && idx <= 13) || idx == 15) {  /* strings */
                printf("%s\n",pc);
                }
            else {
              for (i = 0; i < sz; i++) {
		printf("%02x ",pc[i]);  /* show in hex */
		}
              printf("\n");
	    } /*end else*/
	 }
       }  /*end for*/
      }  /*endif fgetser*/

      if (!freadonly)  /* Set IPMI LAN enable/disable params. */
      {
       if (fipmilan)  /* Sets not valid via ipmi_lan if same channel. */
         printf("\nWarning: Setting LAN %d params while using a LAN channel.\n",		lan_ch);

       {   
         if (fenable && (fsharedMAC==0) && !lan_dhcp) { 
	    /* must have an IP from -I option */
 	    if (!IpIsValid(rgmyip)) {  /* if not user-specified */
               if (IpIsValid(bmcmyip)) {
                  memcpy(rgmyip,bmcmyip,4);
                  if (fdebug) printf("Using current IP %d.%d.%d.%d\n",
					bmcmyip[0], bmcmyip[1],
					bmcmyip[2], bmcmyip[3]);
               } else {
                  printf("\nNot shared BMC LAN, must specify a unique "
                      "IP address via -I\n");
		  ret = ERR_BAD_PARAM;
                  goto do_exit;
               }
            }
         }
	 /* Set LAN parameters.  fenable or fdisable */
         printf("\n%s, SetLanEntry for channel %d ...\n",progname,lan_ch);
	 /* use ifname to resolve MAC addresses below */
         if (fdisable) {
	     if (!fIPMI10) {
                ret = DisablePef(alertnum);
                printf("DisablePef, ret = %d\n",ret);
	        if (ret != 0) { nerrs++; lasterr = ret; }
		else ngood++;
	     }
             if (lan_user != 0) {
	        j = DisableUser(lan_user); /*disable this lan user*/
                printf("DisableUser(%d), ret = %d\n",lan_user,j);
	        if (j != 0) { nerrs++; lasterr = j; }
		else ngood++;
             }
	    LanRecord.data[0] = 0x01;    /* static IP address source */
            ret = SetLanEntry(4, &LanRecord, 1);
            printf("SetLanEntry(4), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
	    /* clear the BMC IP address */
	    memset(&LanRecord,0,4);
            ret = SetLanEntry(3, &LanRecord, 4);
            printf("SetLanEntry(3), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
	    /* clear the gateway IP address */
	    memset(&LanRecord,0,4);
            ret = SetLanEntry(12, &LanRecord, 4);
            printf("SetLanEntry(12), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
	    /* clear the gateway MAC address */
	    memset(&LanRecord,0,6);
	    ret = SetLanEntry(13, &LanRecord, 6);
            printf("SetLanEntry(13), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
         } else if (fdisableSOL) {
	    ret = SetupSerialOverLan(0); /*disable*/
	    SELprintf("SetupSerialOverLan: ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
	 } else {  /*fenable*/
	     uchar chanctl;
	     if (bmcpefctl != 0) chanctl = chan_pefon; /*previously on*/
	     else chanctl = chan_pefoff;
             ret = SetChanAcc(lan_ch, 0x80, chanctl);
             if (fdebug) printf("SetChanAcc(lan/active), ret = %d\n",ret);
	     if (ret != 0) { nerrs++; lasterr = ret; }
	     else ngood++;
             ret = SetChanAcc(lan_ch, 0x40, chanctl);
             if (fdebug) printf("SetChanAcc(lan/nonvol), ret = %d\n",ret);
	     if (ret != 0) { nerrs++; lasterr = ret; }
	     else ngood++;
	     ret = SetUser(lan_user,myuser,passwordData);
             printf("SetUser(%d), ret = %d\n",lan_user,ret);
	     if (ret != 0) { nerrs++; lasterr = ret; }
	     else ngood++;
	 }

	 if (fdisable || fdisableSOL) { 
		// if (nerrs > 0) printf("Warning: %d errors occurred\n",nerrs);
                goto do_exit;
	 }

	 if (authmask == 0) authmask = 0x17; /*if none from GetLanEntry(2)*/
	 LanRecord.data[0] = (bAuth & authmask); /*Callback level*/
	 LanRecord.data[1] = (bAuth & authmask); /*User level    */
	 LanRecord.data[2] = (bAuth & authmask); /*Operator level*/
	 LanRecord.data[3] = (bAuth & authmask); /*Admin level   */
	 LanRecord.data[4] = 0;         /*OEM level*/
	 if (fdebug) printf("SetLanEntry(2): %02x %02x %02x %02x %02x\n",
	 		LanRecord.data[0],LanRecord.data[1],LanRecord.data[2],
	 		LanRecord.data[3],LanRecord.data[4]);
         ret = SetLanEntry(2, &LanRecord, 5);
	 printf("SetLanEntry(2), ret = %d\n",ret);
	 if (ret != 0) { nerrs++; lasterr = ret; }
	 else ngood++;

         /* Get the values to use from Linux eth0, etc. */
         ret = Get_IPMac_Addr();
	 if (lan_dhcp) {  /* use DHCP */
	    LanRecord.data[0] = SRC_DHCP;   /* BMC running DHCP */
                /* = SRC_BIOS;  * address source = BIOS using DHCP */
            ret = SetLanEntry(4, &LanRecord, 1);
            printf("SetLanEntry(4), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
            if (MacIsValid(rgmymac)) {
	       memcpy(&LanRecord,rgmymac,6);
               ret = SetLanEntry(5, &LanRecord, 6);
               if (ret == 0x82) {   /*BMC may not allow the MAC to be set*/
                  if (fdebug) 
		     printf("SetLanEntry(5), ret = %x cannot modify MAC\n",ret);
               } else {
		  printf("SetLanEntry(5), ret = %d\n",ret);
	          if (ret != 0) { nerrs++; lasterr = ret; }
	          else ngood++;
	       }
            }

	    /* DHCP also relates to OEM LAN params 192, 193, 194 */
	    if ((vend_id == VENDOR_INTEL) && !fmBMC && !fiBMC) 
	    {   /*DHCP params 192-194 are Intel only*/
	       if (IpIsValid(rgmyip)) 
	       {
	          /* Set DHCP Server IP in param 192 from -I param. */
	  	  memcpy(&LanRecord,rgmyip,4);
		  ret = SetLanEntry(192, &LanRecord, 4);
		  printf("SetLanEntry(192), ret = %d\n",ret);
	          if (!MacIsValid(rgdhcpmac))  /* if MAC not set yet */
                     ret = Get_Mac(rgmyip,rgdhcpmac,NULL);
	          if (ret == 0) {
	             memcpy(&LanRecord,rgdhcpmac,MAC_LEN);
                     ret = SetLanEntry(193, &LanRecord, MAC_LEN);
                     printf("SetLanEntry(193), ret = %d\n",ret);
	          } 
	       } 
	       LanRecord.data[0] = 0x01;  /*enable DHCP*/
               ret = SetLanEntry(194, &LanRecord, 1);
               printf("SetLanEntry(194), ret = %d\n",ret);
	       if (ret != 0) { nerrs++; lasterr = ret; }
	       else ngood++;
            }
	 } else {    /* use static IP */
          printf("LAN%d (%s)\tip=%d.%d.%d.%d mac=%02x:%02x:%02x:%02x:%02x:%02x\n",
		lan_ch,ifname, rgmyip[0], rgmyip[1], rgmyip[2], rgmyip[3], 
		rgmymac[0], rgmymac[1], rgmymac[2], rgmymac[3], 
		rgmymac[4], rgmymac[5]);
	  if (IpIsValid(rgmyip)) {
	    if (lan_ch != gcm_ch) {  /*skip if gcm*/
	       LanRecord.data[0] = 0x00; /*disable grat arp while setting IP*/
               ret = SetLanEntry(10, &LanRecord, 1);
	       if (fdebug) printf("SetLanEntry(10,0), ret = %d\n",ret);
	       if (ret != 0) { nerrs++; lasterr = ret; }
	    }
	    LanRecord.data[0] = 0x01;    /* static IP address source */
            ret = SetLanEntry(4, &LanRecord, 1);
            printf("SetLanEntry(4), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
	    memcpy(&LanRecord,rgmyip,4);
            ret = SetLanEntry(3, &LanRecord, 4);
            printf("SetLanEntry(3), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
            if (MacIsValid(rgmymac)) {
	       memcpy(&LanRecord,rgmymac,6);
               ret = SetLanEntry(5, &LanRecord, 6);
               if (ret == 0x82) {
		  /* Do not show anything, not an error if BMC does not
		     allow the BMC MAC to be changed. */
                  if (fdebug) 
		     printf("SetLanEntry(5), ret = %x cannot modify MAC\n",ret);
               } else {
		  printf("SetLanEntry(5), ret = %d\n",ret);
	          if (ret != 0) { nerrs++; lasterr = ret; }
	          else ngood++;
	       }
            }
            if (!SubnetIsValid(rgsubnet))  /* not specified, use previous */
		memcpy(rgsubnet,bmcsubnet,4);
	    memcpy(&LanRecord,rgsubnet,4);
            ret = SetLanEntry(6, &LanRecord, 4);
            printf("SetLanEntry(6), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
	    if (vend_id != VENDOR_PEPPERCON) {
		/* may want to check bparm7 here */
		LanRecord.data[0] = parm7[0]; /*IPv4 header, TTL */
		LanRecord.data[1] = parm7[1]; /*IPv4 header, Flags */
		LanRecord.data[2] = parm7[2]; /*IPv4 hdr, Precedence/Service */
		ret = SetLanEntry(7, &LanRecord, 3);
		printf("SetLanEntry(7), ret = %d\n",ret);
		if (ret != 0) { nerrs++; lasterr = ret; }
	        else ngood++;
	    }
            /* if lan_ch == 3, gcm gets error setting grat arp (ccode=0xCD) */
	    if (lan_ch != gcm_ch) {  /*skip if gcm*/
	       /* 01=enable grat arp, 02=enable arp resp, 03=both */
	       LanRecord.data[0] = arp_ctl;        /*grat arp*/
               ret = SetLanEntry(10, &LanRecord, 1);
	       printf("SetLanEntry(10,%x), ret = %d\n",arp_ctl,ret);
	       if (ret != 0) { nerrs++; lasterr = ret; }
	       else ngood++;
	    }
	    LanRecord.data[0] = arp_interval;   /*grat arp interval*/
            ret = SetLanEntry(11, &LanRecord, 1);
	    printf("SetLanEntry(11), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    if ((vend_id == VENDOR_INTEL) && !fmBMC && !fiBMC) {
	       LanRecord.data[0] = 0x00;    /*disable DHCP*/
               ret = SetLanEntry(194, &LanRecord, 1);
               printf("SetLanEntry(194), ret = %d\n",ret);
	       if (ret != 0) { nerrs++; lasterr = ret; }
	       else ngood++;
	    }
	  } else {      /* error, don't continue */
            printf("Missing IP Address, can't continue. Use -I to specify\n");
            ret = ERR_BAD_PARAM;
            goto do_exit;
	  }
	  if (vend_id == VENDOR_KONTRON && rghostname[0] != 0) {
	    /* set the IPMI Hostname if specified */
	    sz = strlen(rghostname);
	    /* LanRecord is larger than rghostname, bounds ok */
	    strncpy((char *)&LanRecord.data,rghostname,sz);
            ret = SetLanEntry(194, &LanRecord, sz);
            printf("SetLanEntry(194), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
            else {
	       LanRecord.data[0] = 0x31; 
               ret = SetLanEntry(195, &LanRecord, 1); /*re-read hostname*/
               // printf("SetLanEntry(195), ret = %d\n",ret);
	       // if (ret != 0) { nerrs++; lasterr = ret; }
	    }
	  }
          if (IpIsValid(rggwyip)) { 
	    if (!MacIsValid(rggwymac)) /* if gwy MAC not set by user */
               ret = Get_Mac(rggwyip,rggwymac,NULL);
            printf("gateway \tip=%d.%d.%d.%d mac=%02x:%02x:%02x:%02x:%02x:%02x\n",
		rggwyip[0], rggwyip[1], rggwyip[2], rggwyip[3],
		rggwymac[0], rggwymac[1], rggwymac[2], rggwymac[3], 
		rggwymac[4], rggwymac[5]);
	    if (!SubnetIsSame(rgmyip,rggwyip,rgsubnet)) 
               printf("WARNING: IP Address and Gateway are not on the same subnet.\n");

	    /* Set the Default Gateway IP & MAC */
	    memcpy(&LanRecord,rggwyip,4);
            ret = SetLanEntry(12, &LanRecord, 4);
            printf("SetLanEntry(12), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
	    if (!MacIsValid(rggwymac)) { /* if gwy MAC not resolved */
		printf("  Warning: Gateway MAC address was not resolved! "
			"Check %s interface, use -i ethN, or use -H gwymac.\n",
			ifname);
	    } else {
		memcpy(&LanRecord,rggwymac,6);
		ret = SetLanEntry(13, &LanRecord, 6);
		printf("SetLanEntry(13), ret = %d\n",ret);
	        if (ret != 0) { nerrs++; lasterr = ret; }
	        else ngood++;
	    }
	  }
          if (IpIsValid(rggwy2ip)) { 
	    if (!MacIsValid(rggwy2mac)) /* if gwy2 MAC not set by user */
               ret = Get_Mac(rggwy2ip,rggwy2mac,NULL);
	    /* Set the Secondary Gateway IP & MAC */
	    memcpy(&LanRecord,rggwy2ip,4);
            ret = SetLanEntry(14, &LanRecord, 4);
            printf("SetLanEntry(14), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
	    memcpy(&LanRecord,rggwy2mac,6);
            ret = SetLanEntry(15, &LanRecord, 6);
	    printf("SetLanEntry(15), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
	  }
	 } /* end-else static IP */
	 ret = SetupSerialOverLan(1); /*enable*/
	 SELprintf("SetupSerialOverLan: ret = %d\n",ret);
	 if (ret != 0) { nerrs++; lasterr = ret; }
	 else ngood++;
	 if (!IpIsValid(rgdestip) && IpIsValid(bmcdestip)) {
            memcpy(rgdestip,bmcdestip,4);
            if (fdebug) printf("Using current dest IP %d.%d.%d.%d\n",
					bmcdestip[0], bmcdestip[1],
					bmcdestip[2], bmcdestip[3]);
         }
	 if (ndest == 0) {
	    if (fdebug) printf("ndest==0, anum=%d rgdestip=%d.%d.%d.%d\n",
		alertnum, rgdestip[0], rgdestip[1], rgdestip[2], rgdestip[3]);
            printf("alert dest \tnot supported\n");
	 } else if (!IpIsValid(rgdestip)) {
            printf("alert dest \taddress not specified\n");
	 } else {   /* valid alert dest ip */
	    if (!MacIsValid(rgdestmac)) /* if dest MAC not set by user */
               ret = Get_Mac(rgdestip,rgdestmac,NULL); /*try to resolve MAC */
	    if (!MacIsValid(rgdestmac)) { /* if dest MAC not resolved */
		printf("  Warning: Alert mac address was not resolved!"
			" Check %s interface or use -i.\n",ifname);
		/* use existing BMC alert dest mac (as best guess) */
		memcpy(rgdestmac,bmcdestmac,6);
	    }
	    /* show destination data */
            printf("alert dest %d\tip=%d.%d.%d.%d mac=%02x:%02x:%02x:%02x:%02x:%02x\n",
		alertnum, rgdestip[0], rgdestip[1], rgdestip[2], rgdestip[3],
		rgdestmac[0], rgdestmac[1], rgdestmac[2], rgdestmac[3], 
		rgdestmac[4], rgdestmac[5]);
            printf("snmp community \t%s\n",rgcommunity);
	    /* Only need the SNMP community if there is an Alert Destination */
	    memset(&LanRecord.data[0], 0, 18);  /* make sure zero-filled */
	    strcpy(&LanRecord.data[0],rgcommunity);
            ret = SetLanEntry(16, &LanRecord, 18);  
            printf("SetLanEntry(16), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
	    /* Set Alert Destination Type */
	    LanRecord.data[0] = alertnum; /* dest id = 1 */
	    LanRecord.data[1] = 0x00;     /* dest type = PET, no ack */
	    LanRecord.data[2] = 0x01;     /* ack timeout / retry interval */
	    LanRecord.data[3] = 0x00;     /* no retries */
	    // LanRecord.data[4] = 0x69; 
            ret = SetLanEntry(18, &LanRecord, 4);
            printf("SetLanEntry(18), ret = %d\n",ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	    else ngood++;
	    { 
		/* Set the Alert Destination IP & MAC (param 19) */
		LanRecord.data[0] = alertnum; /* dest id = 1 */
		LanRecord.data[1] = 0x00; 
		LanRecord.data[2] = 0x00; 
		memcpy(&LanRecord.data[3],rgdestip,4);
		memcpy(&LanRecord.data[7],rgdestmac,6);
		ret = SetLanEntry(19, &LanRecord, 13);
		printf("SetLanEntry(19), ret = %d\n", ret);
	        if (ret != 0) { nerrs++; lasterr = ret; }
	        else ngood++;
	    }
	 } /*endif valid alert*/

	 /* Now enable PEF since we have an Alert destination. */
	 if (!fdisable && !fIPMI10 && fpefenable) { /*fpefenable*/
              ret = EnablePef(alertnum);
              printf("EnablePef, ret = %d\n",ret);
	      if (ret != 0) { nerrs++; lasterr = ret; }
	      else ngood++;
              /* ChanAcc changed, so show it again */
	      j = ShowChanAcc(lan_ch);
	 }

	 if ((vlan_enable != PARM_INIT) && (fIPMI20)) {
	    if (vlan_enable == 0) {  /*disable vlan*/
		LanRecord.data[0] = 0x00;
		LanRecord.data[1] = 0x00;
		ret = SetLanEntry(20, &LanRecord, 2);
		printf("SetLanEntry(20,disable) ret = %d\n", ret);
	        if (ret != 0) { nerrs++; lasterr = ret; }
	        else ngood++;
	    } else {  /*vlan_enable == 1, enable vlan with id */
		LanRecord.data[0] = (vlan_id & 0x00ff);
		LanRecord.data[1] = ((vlan_id & 0x0f00) >> 8) | 0x80; 
		ret = SetLanEntry(20, &LanRecord, 2);
		printf("SetLanEntry(20,%d), ret = %d\n", vlan_id,ret);
	        if (ret != 0) { nerrs++; lasterr = ret; }
	        else ngood++;
		LanRecord.data[0] = vlan_prio;
		ret = SetLanEntry(21, &LanRecord, 1);
		printf("SetLanEntry(21), ret = %d\n", ret);
	        if (ret != 0) { nerrs++; lasterr = ret; }
	        else ngood++;
	    }
	 }
	 if ((failover_enable != PARM_INIT) && (fRomley)) {
            ret = lan_failover_intel(failover_enable,(uchar *)&i);
            printf("Set Intel Lan Failover (%d), ret = %d\n",
			failover_enable,ret);
	    if (ret != 0) { nerrs++; lasterr = ret; }
	 }
       } /*end-else not ipmi_lan*/
      }  /*endif not readonly*/

      if (flanstats) 
      {  /* get BMC LAN Statistics */
#ifdef METACOMMAND
	j = get_lan_stats(lan_ch);
#else
        uchar idata[2];
        uchar rdata[20];
        int rlen;
	uchar cc;
	idata[0] = lan_ch;
	idata[1] = 0x00;  /*do not clear stats*/
	rlen = sizeof(rdata);
        j = ipmi_cmd(GET_LAN_STATS, idata,2, rdata,&rlen, &cc, fdebug); 
	if (j == 0) {  /*show BMC LAN stats*/
	   ushort *rw;
	   rw = (ushort *)&rdata[0];
	   printf("IPMI LAN channel %d statistics: \n",lan_ch);
	   printf(" \tReceived IP Packets      = %d\n",rw[0]);
	   printf(" \tRecvd IP Header errors   = %d\n",rw[1]);
	   printf(" \tRecvd IP Address errors  = %d\n",rw[2]);
	   printf(" \tRecvd IP Fragments       = %d\n",rw[3]);
	   printf(" \tTransmitted IP Packets   = %d\n",rw[4]);
	   printf(" \tReceived UDP Packets     = %d\n",rw[5]);
	   printf(" \tReceived Valid RMCP Pkts = %d\n",rw[6]);
	   printf(" \tReceived UDP Proxy Pkts  = %d\n",rw[7]);
	   printf(" \tDropped UDP Proxy Pkts   = %d\n",rw[8]);
	}
#endif
      }

do_exit:
   ipmi_close_();
   if (foptmsg) {
      if (fset_ip != 0) 
	printf("WARNING: IP address options were specified, but no -e,-l,-d option.\n");
      else 
        printf("WARNING: %d options were specified, but no -e,-l,-d option.\n",
		nopts);
      printf("Read-only usage assumed.\n");
   }
   if (nerrs > 0) {
	printf("Warning: %d ok, %d errors occurred, last error = %d\n",ngood,nerrs,lasterr);
	ret = lasterr;
   }
   // show_outcome(progname,ret); 
   return(ret);
}  /* end main()*/

/* end ilan.c */
