#!/bin/sh
#------------------------------------------------------------------
#
# Nolan fixup startup script
#
# May 2017 Joel Aller
#
# Copyright (c) 2017 by cisco Systems, Inc.
# All rights reserved.
#------------------------------------------------------------------
#set -x

. modulefunc.sh
. platformfunc.sh

EM_DETECT_FNAME=/var/platform/detected_em
EM_IF_FNAME=/var/platform/em0

explict_enable()
{
    local rel_public_key="/etc/ssl/nolan_xm_pub_key.pem"
    local dev_public_key="/etc/ssl/nolan_xm_DEV_pub_key.pem"

    /usr/bin/openssl dgst -sha256 -verify $rel_public_key \
        -signature /sys/class/nolan/xm.0/signature \
        /sys/class/nolan/xm.0/cookie
    if [ $? -eq 0 ]; then
        authentic="yes"
    elif [ -e $dev_public_key ]; then
        # Try DEV public key
        /usr/bin/openssl dgst -sha256 -verify $dev_public_key \
            -signature /sys/class/nolan/xm.0/signature \
            /sys/class/nolan/xm.0/cookie
        if [ $? -eq 0 ]; then
            authentic="yes"
        fi
    fi

    if [ "$authentic" == "yes" ]; then
        echo 1 > /sys/class/nolan/xm.0/enable
        echo 0 > /sys/class/nolan/xm.0/reset
    else
        echo; echo "Detected expansion module is NOT athentic!"; echo
    fi
}

is_em_authentic()
{
    local rel_public_key="/etc/ssl/nolan_xm_pub_key.pem"
    local dev_public_key="/etc/ssl/nolan_xm_DEV_pub_key.pem"

    /usr/bin/openssl dgst -sha256 -verify $rel_public_key \
        -signature /sys/class/nolan/xm.0/signature \
        /sys/class/nolan/xm.0/cookie
    if [ $? -eq 0 ]; then
        return 1
    elif [ -e $dev_public_key ]; then
        # Try DEV public key
        /usr/bin/openssl dgst -sha256 -verify $dev_public_key \
            -signature /sys/class/nolan/xm.0/signature \
            /sys/class/nolan/xm.0/cookie
        if [ $? -eq 0 ]; then
            return 1
        fi
    fi

    # Very old HDK might not been signed properly.
    local EM_PID=`cat /sys/class/nolan/xm.0/pid`
    if [ "$EM_PID" == "0x00000010" ]; then
        return 1
    fi

    return 0
}

# $1 - Cookie file
write_cookie()
{
    local EEPROM_DEV=/sys/bus/i2c/devices/1-0050/eeprom
    local COOKIE="$1"
    local STATUS=1

    if [ ! -f $COOKIE ]; then
        echo "ERROR: Cookie $COOKIE not found"
        return 1
    fi
    echo "Auto-Upgrading expanssion module cookie..."

    # Power up the module
    echo 1 > /sys/class/nolan/xm.0/enable
    echo 0 > /sys/class/nolan/xm.0/reset
    sleep 1 # Give module some time to get its i2c bus ready

    # Instantiate EEPROM device
    echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-1/new_device
    head -c 1 $EEPROM_DEV 2> /dev/null
    if [ $? -eq 0 ]; then
        for idx in `seq 3`; do 
            dd if=$COOKIE of=$EEPROM_DEV bs=1 obs=1 2> /dev/null
            STATUS=$?
            if [ $STATUS -eq 0 ]; then
                echo "Cookie upgrade successful"
                break
            else
                echo "Retrying cookie upgrade..."
            fi
            sleep 1
            echo 0x50 >  /sys/bus/i2c/devices/i2c-1/delete_device
            echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-1/new_device
        done
    else
        echo "ERROR: EEPROM not ready"
    fi

    # Cleanup
    echo 0x50 >  /sys/bus/i2c/devices/i2c-1/delete_device
    echo 0 > /sys/class/nolan/xm.0/enable
    echo 1 > /sys/class/nolan/xm.0/reset

    return $STATUS 
}

# Upgrade older HDK cookie
fixup_hdk_em()
{
    local EM_VERSION=`cat /sys/class/nolan/xm.0/version`

    if [ "$EM_VERSION" == "0x0001" ] || [ "$EM_VERSION" == "0x0000" ]; then
        write_cookie /lib/firmware/hdk_em_eeprom.bin
        return $?
    elif [ "$EM_VERSION" == "0x0002" ] || [ "$EM_VERSION" == "0x0201" ]; then
        write_cookie /lib/firmware/hdk_rev2_em_eeprom.bin
        return $?
    fi
    return 1
}

# Upgrade older Volcano cookie
fixup_volcano_em()
{
    local EM_VERSION=`cat /sys/class/nolan/xm.0/version`
    local EM_MAXPOWER=`cat /sys/class/nolan/xm.0/max_power`

    if [ "$EM_MAXPOWER" != "2700" ]; then
        if [ "$EM_VERSION" == "0x0000" ] || [ "$EM_VERSION" == "0xffff" ]; then
            write_cookie /lib/firmware/volcano_vFFFF_em_eeprom.bin
            return $?
        elif [ "$EM_VERSION" == "0x0001" ]; then
            write_cookie /lib/firmware/volcano_v01_em_eeprom.bin
            return $?
        fi
    fi
    return 1
}

# $1 - retry count
wait_for_em() {
    # Wait for the driver to fully load the modules and read the EEPROM
    for idx in `seq $1`; do
        if [ -f /sys/class/nolan/xm.0/enable ]; then
            break;
        fi
        sleep 1
    done
}

cookie_fixup() {
    EM_PID=`cat /sys/class/nolan/xm.0/pid`
    case "$EM_PID" in
        0x00000010)
            fixup_hdk_em && RELOAD_EEPROM="yes"
            ;;
        0x00000011)
            fixup_volcano_em && RELOAD_EEPROM="yes"
            ;;
    esac

    if [ "$RELOAD_EEPROM" == "yes" ]; then
        echo "Reloading XM driver..."
        # Reload XM driver for the new EEPROM data
        rmmod nolan_xm_device
        insmod /lib/modules/nolan_xm_device.ko
        wait_for_em 3
    fi
}

power_needed_with_em()
{
    local max_power=`cat /sys/class/nolan/xm.0/max_power`

    if [ ! -z $max_power ]; then
        local pid=`cat /COOKIE_PID | sed -e 's/AIR-//' | cut -d '-' -f 1`
        case "$pid" in
            AP3802*)
                if [ $max_power -gt 18000 ]; then
                    # Unsupported module
                    plat_set_em_power_level 4
                elif [ $max_power -gt 9000 ]; then
                    plat_set_upoe_required
                    # Tweaked for resulting PSE=45.7W on 4-wires uPoE
                    plat_set_upoe_power_max 387
                    plat_set_em_power_level 3
                elif [ $max_power -gt 6000 ]; then
                    plat_set_upoe_required
                    # Tweaked for resulting PSE=36W on 4-wires uPoE
                    plat_set_upoe_power_max 305
                    plat_set_em_power_level 2
                elif [ $max_power -gt 2700 ]; then
                    plat_set_upoe_required
                    # Tweaked for resulting PSE=31.8W on 4-wires uPoE
                    plat_set_upoe_power_max 269
                    plat_set_em_power_level 1
                else
                    plat_set_em_power_level 0
                fi
                ;;
            # TBD: Baffin
        esac
    fi
}

case "$1" in
  start)
    modload /lib/modules/at24.ko
    modload /lib/modules/nolan_xm_driver.ko
    [ -e $EM_IF_FNAME ] && IFNAME=`cat $EM_IF_FNAME`
    if [ ! -z $IFNAME ]; then
        ifrename $IFNAME wiredem
        modload  /lib/modules/nolan_rlan_capability.ko
    fi
    modload /lib/modules/nolan_xm_device.ko

    # For MFG build without CAPWAP, manually run authentication here.
    if [ -d "/usr/bin/mfg" ]; then
        explict_enable
    fi

    wait_for_em 3

    is_em_authentic
    if [ $? -eq 1 ]; then
        plat_set_em_authentic
        cookie_fixup
        power_needed_with_em
    fi

    # Delete no longer needed binary file from rootfs
    rm -f /lib/firmware/*_em_eeprom.bin
    modrm /lib/modules/nolan_xm_device.ko
    modrm /lib/modules/nolan_xm_driver.ko
    modrm /lib/modules/nolan_rlan_capability.ko
    modrm /lib/modules/at24.ko
    ;;
  stop)
    [ -e $EM_IF_FNAME ] && IFNAME=`cat $EM_IF_FNAME`
    if [ ! -z $IFNAME ]; then
        rmmod nolan_rlan_capability
        ifrename wiredem $EM_IF_FNAME
    fi
    rmmod nolan_xm_device
    rmmod nolan_xm_driver
    rmmod at24
    ;;
  *)
    echo "Usage: $0 {start|stop}"
    exit 1
    ;;
esac

exit 0
