#!/bin/bash
#
# Usage -A | -i <interface> [ -f file name | -d dir_name ]
#
# Script to generate equivalent of /proc info previously
# Being generated by network drivers

ioption=0
foption=0
doption=0
Aoption=0
multiport=0
# For test purposes, use junk paths
#INTEL_PROC_DIR=/proc/net/nothing
#BCOM_PROC_DIR=/proc/net/nothing
INTEL_PROC_DIR=/proc/net/PRO_LAN_Adapters
BCOM_PROC_DIR=/proc/net/nicinfo
INTEL_VMWARE_PROC_DIR=/proc/vmware/vmkdev/net/PRO_LAN_Adapters
BCOM_VMWARE_PROC_DIR=/proc/vmware/vmkdev/net/nicinfo

if [ "$ETHTOOL_VER" = "" ]
then
ETHTOOL_VER=1.8
fi

ETHTOOL=${ETHTOOL_PATH:-/opt/compaq/nic/bin/hpethtool}

usage()
{
printf "\n"
echo "Usage: $0 [<switches>]"
printf "\n"
echo "-i <interface>  Specifies the ethernet interface "
echo "-f <file>       Specifies the file into which the output is saved"
echo "-d <dir>        Specified the directory into which file of name"
echo "			ethX.info is saved for each ethernet interface"
echo "			specified through the -i option."
echo "-A		Use all ethernet interfaces on the system"
printf "\n"

echo "Note: -i or -A option should be specified"
echo "Note: -f and -d are mutually Exclusive"
printf "\n"
}

check_for_errors()
{
if [ "$ioption" = "0" -a "$Aoption" = "0" ]
then
	usage
	exit 1
fi

if [ "$ioption" = "1" -a "$Aoption" = "1" ]
then
        echo "Error!! -i and -A options cannot be used together"
	usage
	exit 1
fi

if [ "$foption" = "1" -a "$doption" = "1" ]
then
  echo "Error!! -f and -d options cannot be used together"
  usage
  exit 1
fi

if [ "$foption" = "1" ]
then
  if [ -f $fname -a ! -w $fname ]
  then
   echo "Error!! $fname Exists or Write permission denied. Exiting"
   exit 1
  fi
fi
if [ "$doption" = "1" ]
then
  mkdir -p $dirname
  if [ ! -d $dirname ]
  then
   echo "Error!! Error in creating $dirname. Exiting"
  exit 1
  fi
  if [ ! -w $dirname ]
  then
   echo "Error!! $dirname Exists. Write permission denied. Exiting"
  exit 1
  fi
fi

#Verify for proper interface name

if [ "$ioption" = "1" -a "$Aoption" = "1" ]
then
  echo "Error!! -i and -A options cannot be used together. Exiting"
  exit 1
fi
if [ "$ioption" = "1" ]
then
   echo $iname | egrep "^eth[0-9]" > /dev/null 2>&1
   if [ $? != 0 ]
   then
     echo "Error!! Improper or null interface name $iname. Exiting"
     exit 1
   fi
else
     if [ "$Aoption" != "1" ]
     then
        usage
        exit 1
     fi
fi
}


check_for_ethtool_ver()
{

ls -l $ETHTOOL > /dev/null 2>&1
if [ "$?" != "0" ]
then
  echo "------------------------------------------------------------"
  echo "It appears that the ethtool application is not installed on"
  echo "this system. Please ensure to get ethtool application"
  echo "Version $ETHTOOL_VER from the following URL and install"
  printf "\n"
  echo "http://sourceforge.net/projects/gkernel/"
  echo "------------------------------------------------------------"
  exit 1
fi

ethtool_ver=`strings $ETHTOOL | grep -i "ethtool version" | awk '{print $3}'`
if [ "$ethtool_ver" != "$ETHTOOL_VER" ]
then
  echo "------------------------------------------------------------"
  echo "The required ethtool application version is $ETHTOOL_VER and"
  echo "the installed version is $ethtool_ver. For this script"
  echo "to work properly, please use ethtool version $ETHTOOL_VER which"
  echo "can be downloaded from the following URL"
  printf "\n"
  echo "http://sourceforge.net/projects/gkernel/"
  echo "------------------------------------------------------------"
  exit 1
fi
}

display_entry()
{
variable="$1"
varvalue="$2"

if [ "$variable" = "Speed" ] || [ "$variable" = "Duplex" ] || [ "$variable" = "Link" ]
then
	printf "%-25s %s\n" "$variable" "$varvalue"
	return 0
fi

if [ "$varvalue" = "" ] || [ "$varvalue" = "N/A" ]
then
	return 1
else
	printf "%-25s %s\n" "$variable" "$varvalue"
fi
}

display_static_proc()
{
display_entry "Description" "$descr"
display_entry "Driver_Name" "$drvname"
display_entry "Driver_Version" "$drvversion"
display_entry "PCI_Vendor" "0x$pcivendor"
display_entry "PCI_Device_ID" "0x$pcidevice"
display_entry "PCI_Subsystem_Vendor" "0x$pcisubsys"
display_entry "PCI_Subsystem_ID" "0x$pcisubdev"
display_entry "PCI_Revision_ID" "0x$pcirevid"
display_entry "PCI_Bus" "$busnum"
display_entry "PCI_Slot" "$slotnum"
display_entry "IRQ" "$irq"
display_entry "Part_Number" "$partno"
display_entry "System_Device_Name" "$iname"
display_entry "Current_HWaddr" "$caddr"
display_entry "Permanent_HWaddr" "$phwaddr"
printf "\n"
}


display_dynamic_proc()
{
# Print the Statistics
display_entry "Link" "$link"
display_entry "Speed" "$speed"
display_entry "Duplex" "$duplex"
display_entry "State" "$state"
display_entry "Auto_Negotiate" "$auto_negotiate"
display_entry "Speed_Advertisement" "$speed_advertisement"
printf "\n"
printf "\n"
display_entry "Rx_Packets" "$rxpack"
display_entry "Tx_Packets" "$txpack"
display_entry "Rx_Bytes" "$rxbytes"
display_entry "Tx_Bytes" "$txbytes"
display_entry "Rx_Errors" "$rxerrors"
display_entry "Tx_Errors" "$txerrors"
printf "\n"
printf "\n"
display_entry "Rx_CRC_Errors" "$rx_crc_errors"
display_entry "Tx_Carrier_Errors" "$tx_carrier_errors"
display_entry "Tx_Abort_Excess_Coll" "$tx_abort_excess_coll"
display_entry "Tx_Abort_Late_Coll" "$tx_abort_late_coll"
display_entry "Tx_Deferred_Ok" "$tx_deferred_ok"
display_entry "Tx_Single_Coll_Ok" "$tx_single_coll_ok"
display_entry "Tx_Multi_Coll_Ok" "$tx_multi_coll_ok"
display_entry "Rx_Short_Length_Errors" "$rx_short_length_errors"
display_entry "Rx_Long_Length_Errors" "$rx_long_length_errors"
display_entry "Rx_Align_Errors" "$rx_align_errors"
printf "\n"
printf "\n"
}


# Get the Driver and PCI Related Info First

get_drv_info()
{
$ETHTOOL -i $iname > /tmp/$iname.iopt

drvname=`egrep ^driver /tmp/$iname.iopt | awk -F":" '{print $2}'|sed 's/^[ 	]*//g'`
drvversion=`egrep ^version /tmp/$iname.iopt | awk -F":" '{print $2}'|sed 's/^[ 	]*//g'`
busnum=`grep bus-info /tmp/$iname.iopt | awk -F":" '{print $2}'| sed 's/^[ 	]*0//g'`
slotnum=`grep bus-info /tmp/$iname.iopt | awk -F":" '{print $3}' | awk -F"." '{print $1}'| sed 's/^[ 	]*0//g'`
slotinfo=`grep bus-info /tmp/$iname.iopt | awk '{print $2}'`

get_speed_duplex_link

/bin/rm -rf /tmp/$iname.iopt
}

get_pci_info()
{
pcivendor=`lspci -s $slotinfo -n -m | awk '{print $4}' | sed 's/"//g'`
pcidevice=`lspci -s $slotinfo -n -m | awk '{print $5}' | sed 's/"//g'`
pcisubsys=`lspci -s $slotinfo -n -v | egrep -i subsystem | awk -F":" '{print $2}' | sed 's/"//g' | sed 's/^[ 	]*//g'`
pcisubdev=`lspci -s $slotinfo -n -v | egrep -i subsystem | awk -F":" '{print $3}' | sed 's/"//g' | sed 's/^[ 	]*//g'`
if [ "$pcisubdev" = "00d0" ]
then
 #We have a multiport card here. Read both MAC addresses
 multiport=1
fi
pcirevid=`lspci  -n  -s $busnum:$slotnum.0 | sed 's/[:()]//g' | awk '{print $6}'`
descr=`lspci -s $slotinfo -v | head -1 | awk -F":" '{print $3}'|sed 's/^[ 	]*//g'`
irqstring=`lspci -s $slotinfo -n -v | egrep IRQ `
getnexttoken=0
for i in  `echo $irqstring`
do
	if [ $getnexttoken = 1 ]
	then
        	irq=$i
	break
	fi
	if [ $i = "IRQ" ]
	then
		getnexttoken=1
	fi
done
memory=`lspci -s $slotinfo -n -v | egrep -i "Memory at" | awk '{print $3}' | sed 's/^[ 	]*//g'`

caddr=`ifconfig $iname | grep HWaddr | awk  '{print $5}'`
phwaddr=
partno=
if [ "$pcivendor" = "8086" ]
then
	# We Have an Intel Card. Offset is 0x0
        get_part_no intel
	# For Intel Cards, Permanent MAC Offset ix 0x0
	eeprom_offset="0x0"
	bytes=6
        phwaddr=`$ETHTOOL -e $iname offset $eeprom_offset length $bytes | tail -1 | awk '{printf "%s:%s:%s:%s:%s:%s",$2,$3,$4,$5,$6,$7}'`
	phwaddr=`echo $phwaddr | awk '{printf "%s", toupper($1)}'`
else
        get_part_no broadcom
	# For Broadcom Cards, Permanent MAC Offset ix 0x7c
	eeprom_offset="0x7c"
	bytes=8
	# For Multiport broadcom cards, Second MAC Offset is at 0xcc
	if [ "$multiport" = "1" ]
	then
		eeprom_offset1="0xcc"
	fi
# Now, get the Permanent MAC from the assigned Offsets

        phwaddr=`$ETHTOOL -e $iname offset $eeprom_offset length $bytes | tail -1 | awk '{printf "%s:%s:%s:%s:%s:%s",$4,$5,$6,$7,$8,$9}'`
	phwaddr=`echo $phwaddr | awk '{printf "%s", toupper($1)}'`
	# For Multiport Cards, get second MAC also
	if [ "$multiport" = "1" ]
	then
        phwaddr1=`$ETHTOOL -e $iname offset $eeprom_offset1 length $bytes | tail -1 | awk '{printf "%s:%s:%s:%s:%s:%s",$4,$5,$6,$7,$8,$9}'`
	phwaddr1=`echo $phwaddr1 | awk '{printf "%s", toupper($1)}'`
	fi
fi
}

generate_statistics()
{

 einame=$1
 $ETHTOOL -S $einame > /tmp/$einame.stats

}
get_value()
{
 string=$1
 value=`egrep "^[ 	]*\$string" /tmp/$iname.stats`
 value=${value## *:}
 echo ${value:-"N/A"}

}

get_speed_duplex_link()
{

$ETHTOOL $iname > /tmp/$iname.noopt

links=`egrep "Link" /tmp/$iname.noopt`
links=`echo ${links##*:} | sed 's/[ 	]*//g'`
if [ "$links" = "yes" ]
then
	link="Up"
else
	link="Down"
fi

speedtmp=`egrep "Speed" /tmp/$iname.noopt`
speedtmp=`echo ${speedtmp##*:} | sed 's/[ 	]*//g'`
# Remove the Mb/s at the end of the string
speed=${speedtmp/Mb\/s/}

duplex=`egrep "Duplex" /tmp/$iname.noopt`
duplex=`echo ${duplex##*:} | sed 's/[ 	]*//g'`

echo $speed | egrep -i unknown > /dev/null 2>&1
if [ $? = 0 ]
then
speed="N/A"
fi
echo $duplex | egrep -i unknown > /dev/null 2>&1
if [ $? = 0 ]
then
duplex="N/A"
fi

ifconfig $iname | grep UP > /dev/null 2>&1
if [ $? = 0 ]
then
state=up
else
state=down
link="N/A"
fi

auto_negotiate="N/A"
auto_line=`grep "Advertised auto-negotiation:" /tmp/$iname.noopt 2>&1`

echo $auto_line | grep "Yes" >/dev/null
if [ $? = 0 ]
then
   auto_negotiate="on"
else
   echo $auto_line | grep "No" >/dev/null
   if [ $? = 0 ]
   then
      auto_negotiate="off"
   fi
fi

/bin/rm -rf /tmp/$iname.noopt

}

# Now we need to get the Statistics of the Appropriate interface
# Through the ethtool interface

get_stats()
{
generate_statistics $iname
if [ "$pcivendor" = "8086" ]
then
	rxpack=`get_value rx_packets`
	txpack=`get_value tx_packets`
	txbytes=`get_value tx_bytes`
	rxbytes=`get_value rx_bytes`
	txdrop=`get_value tx_dropped`
	rxdrop=`get_value rx_dropped`
	rxerrors=`get_value rx_errors`
	txerrors=`get_value tx_errors`
	multicast=`get_value multicast`
	collisions=`get_value collisions`
	rx_crc_errors=`get_value rx_crc_errors`
	tx_carrier_errors=`get_value tx_carrier_errors`
	rx_length_errors=`get_value rx_length_errors`
	rx_over_errors=`get_value rx_over_errors`
	rx_frame_errors=`get_value rx_frame_errors`
	rx_fifo_errors=`get_value rx_fifo_errors`
	tx_abort_excess_coll=N/A
	tx_abort_late_coll=`get_value tx_abort_late_coll`
	tx_deferred_ok=`get_value tx_deferred_ok`
	tx_single_coll_ok=`get_value tx_single_coll_ok`
	tx_multi_coll_ok=`get_value tx_multi_coll_ok`
	rx_short_length_errors=`get_value rx_length_errors`
	rx_long_length_errors=0
	rx_align_errors=`get_value rx_frame_errors`
else
	rxupack=`get_value rx_unicast_packets`
	rxmpack=`get_value rx_multicast_packets`
	rxbpack=`get_value rx_broadcast_packets`
	rxpack=`expr $rxupack + $rxmpack + $rxbpack`
	txupack=`get_value tx_unicast_packets`
	txmpack=`get_value tx_multicast_packets`
	txbpack=`get_value tx_broadcast_packets`
	txpack=`expr $txupack + $txmpack + $txbpack`
	txbytes=`get_value tx_bytes`
	rxbytes=`get_value rx_bytes`
	rxerrors=`get_value rx_errors`
	txerrors=`get_value tx_errors`
	rx_crc_errors=`get_value rx_crc_errors`
	tx_carrier_errors=`get_value tx_carrier_errors`
	tx_abort_excess_coll=`get_value tx_excess_collisions`
	tx_abort_late_coll=`get_value tx_late_collisions`
	rx_length_errors=`get_value rx_length_errors`
	rx_over_errors=`get_value rx_over_errors`
	rx_frame_errors=`get_value rx_frame_errors`
	rx_fifo_errors=`get_value rx_fifo_errors`
	tx_deferred_ok=`get_value tx_deferred`
	tx_single_coll_ok=`get_value tx_single_coll_ok`
	tx_multi_coll_ok=`get_value tx_multi_coll_ok`
	rx_short_length_errors=`get_value rx_short_length_errors`
	rx_long_length_errors=`get_value rx_long_length_errors`
	rx_align_errors=`get_value rx_align_errors`
fi
/bin/rm -rf /tmp/$iname.stats
}

get_part_no()
{
if [ "$1" = "intel" ]
then
   count=0
   partno=`$ETHTOOL -e $iname offset 16 length 4 | tail -1 | awk '{printf "%s%s%s-%s", $3,$2,$5,$4}'`
else # For Broadcom Cards partnumber is stored as hex. Convert to ASCII
   partnohex=`$ETHTOOL -e $iname offset 0x84 length 10 | tail -1 | cut -f3`
   partno=`echo "$partnohex" | perl -nle 'print join "", map { chr hex $_ } split " ";'`
fi   

}

#========================================================
# 		Main Program Starts Here
#========================================================
TEMP=`/usr/bin/getopt 'i:f:d:A' "$@" 2>/dev/null`

if [ $? != 0 ] ; then
    usage
    exit 1
fi

eval set -- "$TEMP"
while true ; do
    case "$1" in
        -i) iname="$2" ; ioption=1 ; shift 2 ;;
        -f) fname="$2" ; foption=1 ; shift 2 ;;
        -d) dirname="$2" ; doption=1 ; shift 2 ;;
        -A) Aoption=1 ; shift ;;
         --) shift ; break ;;
         *) shift ; break ;;
    esac
done

# Perform sanity checks
check_for_errors
check_for_ethtool_ver

if [ "$foption" = "1" ]
then
  /bin/touch $fname >/dev/null 2>&1
  if [ "$?" != "0" ]
  then
    echo "Error!! Could not create $fname. Pl. check write permissions"
    exit 1
  else # Zero out the file contents if present
    > $fname
  fi
fi


# Generate Interface list if the user has given the -A option

if [ "$Aoption" = "1" ]
then
   interface_list=
   # Generate the ethX interface list
   for i in `ifconfig -a | egrep "^eth[0-9]*[0-9]" | awk '{print $1}'`
   do
      interface_list="$interface_list $i"
   done
else
      # Check if this device exists on the system
      interface_list=$iname
      /sbin/ifconfig $iname > /dev/null 2>&1
      if [ $? != 0 ]
      then
           echo "Error!! $iname: Device does not exist. Exiting"
           exit 1
      fi
fi


# Now Dump the info either in the file for -f, directory
# For -d or stdout if none

for i in `echo $interface_list`
do
   iname=$i
   if [ "$doption" = "1" ]
   then
      fname=$dirname/$iname.info
      /bin/touch $fname > /dev/null 2>&1
      if [ "$?" != "0" ]
      then
        echo "Warning!! Could not create $fname. Pl. check write permissions"
        continue
      else # Zero out the file contents if present
        > $fname
      fi
   fi
   # If proc entries exist, use them
   # check for vmware proc directories first
   if [ -f $INTEL_VMWARE_PROC_DIR/$iname.info ]
   then
      INTEL_PROC_DIR=$INTEL_VMWARE_PROC_DIR   
   fi
   if [ -f $BCOM_VMWARE_PROC_DIR/$iname.info ]
   then
      BCOM_PROC_DIR=$BCOM_VMWARE_PROC_DIR     
   fi

   if [ "$foption" = "1" -o "$doption" = "1" ]
   then
      # we cannot use copy here since -A with -f will overwrite.
      if [ -f $INTEL_PROC_DIR/$iname.info ]
      then
		cat $INTEL_PROC_DIR/$iname.info >> $fname
		echo -e "\n\n" >> $fname
		continue
      elif [ -f $BCOM_PROC_DIR/$iname.info ]
      then
		cat $BCOM_PROC_DIR/$iname.info >> $fname
		echo -e "\n\n" >> $fname
		continue
      fi
   else  # display to stdout
      if [ -f $INTEL_PROC_DIR/$iname.info ]
      then
		cat $INTEL_PROC_DIR/$iname.info
		continue
      elif [ -f $BCOM_PROC_DIR/$iname.info ]
      then
		cat $BCOM_PROC_DIR/$iname.info
		continue
      fi
   fi
   # 
   # Note that always the get_drv_info
   # needs to be called first
   #
   if [ "$doption" = "1" ]
   then
	staticfname=$dirname/.$iname.sinfo
        if [ ! -f "$staticfname" ]
	then
   		get_drv_info 
   		get_pci_info
	else
		# We still need pcivendor to determine
		# Which card this is.
		pcivendor=`grep -i pci_vendor $staticfname|awk '{print $2}' | sed 's/0x//g'`
	fi
   else
   		get_drv_info 
   		get_pci_info
   fi
   get_speed_duplex_link
   get_stats
   #
   # Re-direct output appropriately
   #
   if [ "$doption" = "1" ]
   then
        if [ -f "$staticfname" ]
	then
          cp $staticfname $fname
          display_dynamic_proc >> $fname 2>&1
	else
          display_static_proc > $staticfname 2>&1
          cp $staticfname $fname
          display_dynamic_proc >> $fname 2>&1
	fi
   elif [ "$foption" = "1" ]
   then
      display_static_proc >> $fname 2>&1
      display_dynamic_proc >> $fname 2>&1
   else
      display_static_proc
      display_dynamic_proc
   fi
done
