#!/bin/bash
#
# vpd_patch - patch the contents of VPD for Pharos prototypes
#
#   only for early prototypes that didn't go through the orthodox
#   factory initialization

TFILE=/tmp/vpd.$$.txt

function vpd_write {
  /fabos/share/vpdWrite -tfile $TFILE
}

function vpd_read {
  /fabos/share/vpdRead -offset $1 -size $2 |
  sed -e 's/^....: //' -e '/embeddedVpdRead/d'
}

function hex_from_wwn {
  wwn | tr ':' ' '
}

function do_wwn {
  WWN=`hex_from_wwn`

  cat > $TFILE << End_Of_VPD
0640: 01
0641: $WWN
0649: 00 00 00 00 00 00 00
0650: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0660: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0670: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
End_Of_VPD

  vpd_write
}

function fpga_read {
  reg_ms=${1:0:1}
  reg_ls=${1:1:1}
  fpga_row="0x11f80000${reg_ms}0:"
  declare -i fpga_col=0x${reg_ls}+2
  grep "${fpga_row}" /proc/system/fpga | tr -s [:blank:] | cut -d' ' -f$fpga_col
}

function hex_from_mac {
  ip link show eth$1 | sed '1d' | sed 's/^ *//' | cut -d' ' -f2 | tr ':' ' '
}

function do_mac {
  declare -i B6=0x`fpga_read b6`
  declare -i testIObit
  let "testIObit = B6 & 1"
  if [ $testIObit = "0" ]
  then
    MAC0=`hex_from_mac 0`
    MAC1=`hex_from_mac 1`
  else
    MAC0=`hex_from_mac 1`
    MAC1=`hex_from_mac 0`
  fi

  cat > $TFILE << End_Of_VPD
006f: $MAC0
0075: $MAC0
007b: $MAC1
0081: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
End_Of_VPD

  vpd_write
}

function crc32 {
  declare -i crc=0
  declare -i polynomial=0x4c11db7
  for x
  do
    declare -i n=0x$x
    declare -i j
    for ((j = 0; j < 8; ++j))
    do
      declare -i bit
      let "bit = ((crc >> 31) & 1) ^ ((n >> (7 - j)) & 1)"
      if [ $bit -eq 0 ]
      then
        let "crc = (crc << 1)"
      else
        let "crc = (crc << 1) ^ polynomial"
      fi
    done
  done
  declare -i crc0 crc1 crc2 crc3
  let "crc0 = (crc >> 24) & 0xff"
  let "crc1 = (crc >> 16) & 0xff"
  let "crc2 = (crc >> 8) & 0xff"
  let "crc3 = crc & 0xff"
  printf "%.2x %.2x %.2x %.2x\n" $crc0 $crc1 $crc2 $crc3
}

function do_crc {
  DATA=$(vpd_read 0 3fc)
  CRC=$(crc32 $DATA)
  echo "03fc: $CRC" > $TFILE
  vpd_write
}

function check_crc {
  DATA=$(vpd_read 0 400)
  CRC=$(crc32 $DATA)
  echo "$CRC"
}

function pad {
  declare -i first=0x$1
  padbyte=$2
  declare -i nbytes=$3
  declare -i x
  for ((x=0; x<nbytes; ++x))
  do
  if [ $((x%16)) = "0" ]
  then
    if [ $x -gt 0 ]
    then
      printf "\n"
    fi
    printf "%x:" $first
    let "first += 16"
  fi
  printf " $padbyte"
  done
  printf "\n"
}

function hex_from_string {
  MAXLEN=$1
  shift
  echo "$*" | awk -F'	' -v MAXLEN=$MAXLEN '
  BEGIN {
    hex[" "] = 0x20
    chars = "()*+,-./0123456789:;<=>?@"
    chars = chars "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    chars = chars "[\\]^_`"
    chars = chars "abcdefghijklmnopqrstuvwxyz"
    chars = chars "{|}~"
    n = length(chars)
    for (i = 1; i <= n; ++i)
      hex[substr(chars,i,1)] = 0x27 + i
  }
  { string = $1
    string_len = length($1)
    if (string_len > MAXLEN)
      string = substr($1,1,MAXLEN)
    else if (string_len < MAXLEN)
      for (i = string_len + 1; i <= MAXLEN; ++i)
        string = string " "
    n = length(string)
    for (i = 1; i <= n; ++i)
      printf "%x ", hex[substr(string,i,1)]
  }'
}

function do_init {
IBM_PARTNUMBER=`hex_from_string 12 "88Y6376"`
IBM_FRUNUMBER=`hex_from_string 12 "88Y6377"`
IBM_PROD_NAME_SHORT=`hex_from_string 31 "Brocade 6547"`
IBM_PROD_NAME_LONG=\
`hex_from_string 96 "Brocade 16Gb Fibre Channel Switch Module for IBM <Beacon>"`

cat > $TFILE << End_Of_VPD
0000: 03 fe 02 02 03 fc 00 00 01 35 00 00 00 11 00 00
0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0030: 00 00 00 00 00 00 00 00 00 00 00 00
003c: $IBM_PARTNUMBER
0048: $IBM_FRUNUMBER
; %%UUTDATA SN:0054:17,6:2:H
0054: 30 31 32 33 34 35
005a: 59 30 35 30 55 5A
0060: 42 52 43 44 00 00 00 00 00 00 00
; %%UUTDATA WOY:006B::2
006b: 00 00 00 00
007b: 00 00 00 00 00
0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
; %%UUTDATA UUID:009f:::D
009f: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
00af: 90
00b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00c0: 00 00 00 00 00 00 00 00 04 00 08 00 0c 00 10 00
00d0: 14 00 18 00 1c 00 00 50 00 00 4f 4d 01 49 00 00
00e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00f0: 00 64 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0100: 42 52 43 44 00 00 00 00 00 00 00 00 00 00
010e: $IBM_PROD_NAME_SHORT
012d: 3a
012e: $IBM_PROD_NAME_LONG
$(pad 018e 00 242)
$(pad 0280 00 192)
$(pad 0340 00 128)
$(pad 03c0 00 64)
0400: 00 00 03 fe 01 00
$(pad 0406 20 36)
$(pad 042a 20 36)
$(pad 044e 20 36)
$(pad 0472 20 36)
$(pad 0496 20 36)
$(pad 04ba 20 36)
04de: 0a 5a 5a 5a ff ff ff 00 00 00 00 00
$(pad 04ea 00 12)
$(pad 04f6 00 12)
$(pad 0502 00 12)
050e: 01
$(pad 050f 00 12)
$(pad 051b 00 12)
$(pad 0527 00 12)
$(pad 0533 00 12)
053f: 00
$(pad 0540 00 32)
0560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
$(pad 0570 00 33)
$(pad 0591 00 31)
05b0: 00 00 02 01
$(pad 05b4 00 12)
05c0: 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
05d0: 20 10 20 10 20 10 20 10 20 10 20 10 20 10 20 10
05e0: 20 10 20 10 20 10 20 10 20 10 20 10 20 10 20 10
05f0: 20 10 20 10 20 10 20 10 20 10 20 10 20 10 20 10
0600: 20 10 20 10 20 10 20 10 00 00 00 00 00 00 00 00
0610: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0620: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0630: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
$(pad 0640 00 64)
$(pad 0680 00 32)
06a0: 87 B1 00 00 00 00 00 00 FD 46 AC 00 00 00 00 00
06b0: 00 00 00 00 40 00 00 00 1c 00 00 00 00 00 00 00
06c0: 00 00 00
$(pad 06c3 00 6)
$(pad 06c9 00 7)
$(pad 06d0 00 16)
$(pad 06e0 00 4)
06e4: 00 00 00 00 00 00 00 00 00 00 00 00
06f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 e8
$(pad 0700 00 256)
0800: 00 00 03 fe 02 00 00
$(pad 0807 00 48)
$(pad 0837 00 16)
0847: 00 02 01
$(pad 084a 00 16)
$(pad 085a 20 150)
$(pad 08f0 20 16)
$(pad 0900 00 7)
0907: 00
$(pad 0908 20 416)
$(pad 0aa8 00 8)
$(pad 0ab0 00 4)
$(pad 0ab8 00 4)
0abc: 00 00
$(pad 0abe 00 322)
0c00: 00 00 03 fe 03 00
$(pad 0c06 00 250)
$(pad 0da0 00 96)
$(pad 0e00 00 512)
1000: 00 00 03 fe 04 00
$(pad 1006 00 1018)
1400: 00 00 03 fe 05 00
$(pad 1406 00 1018)
1800: 00 00 03 fe 06 00
$(pad 1806 00 1018)
1c00: 00 00 03 fe 07 00
$(pad 1c06 00 1018)
End_Of_VPD

vpd_write
}

function do_mm_mac {
  echo "abe: ${1//:/ }" > $TFILE
  vpd_write
}

function do_passwd {
  echo "883: $@" > $TFILE
  vpd_write
}

function do_sec_level {
  echo "f2f: $1" > $TFILE
  vpd_write
}

function do_sec_port {
  declare -i port=$1
  let "p0 = 0xff & (port >> 8)"
  let "p1 = 0xff & port"
  printf "f30: %x %x" $p0 $p1 > $TFILE
  vpd_write
}

function do_sec_secret {
  declare secret="$1"
  echo "f32: $secret" > $TFILE
  vpd_write
}

SCRIPT=${0##*/}
function usage {
  printf "usage:\n"
  printf "%s -[m|w|c|C|h]\n" $SCRIPT
  printf "  -m  patch Ethernet MAC addresses\n"
  printf "  -w  patch WWN\n"
  printf "  -h  print this usage message and exit\n"
  printf " Unit test and debug options:\n"
  printf "  -M xx:xx:xx:xx:xx:xx  patch MM MAC Address\n"
  printf "  -P xx xx xx xx xx xx xx xx xx xx xx xx  patch authentication password \n"
  printf "  -L xx    patch assigned security level, \"xx\" is a hex byte\n"
  printf "  -T port  patch security server TCP port, \"port\" is a number\n"
  printf "  -S scrt  patch security shared secret, a sequence of 16 hex bytes in quotes\n"
  exit 1
}

if [ $# -eq 0 ]
then
  usage
fi

declare OPTION
while getopts "mwahM:P:L:T:S:" OPTION
do
  case $OPTION in
  m)  do_mac ;;
  w)  do_wwn ;;
  M)  do_mm_mac $OPTARG ;;
  P)  do_passwd $OPTARG ;;
  L)  do_sec_level $OPTARG ;;
  T)  do_sec_port $OPTARG ;;
  S)  do_sec_secret $OPTARG ;;
  h)  usage ;;
  \?) usage ;;
  *)  usage ;;
  esac
done
