You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

688 lines
18 KiB
Bash

#!/bin/sh /etc/rc.common
# we must run after S95done because jffs2 overlay must be ready for writing to /lib/firmware/plc
START=96
STOP=10
USE_PROCD=1
if [ -f /lib/ar71xx.sh ]; then
PLATFORM=ar71xx
. /lib/ar71xx.sh
elif [ -f /lib/ipq806x.sh ]; then
PLATFORM=ipq806x
. /lib/ipq806x.sh
fi
board=$(${PLATFORM}_board_name)
. /lib/functions/system.sh
. /lib/functions/leds.sh
. /lib/firmware/plc/$board/fwconfig
config_load plc
config_get PLCIF plc interface 'br-lan'
config_get INMK plc individual_nmk '0'
config_get LED_SCHEME plc led_scheme 'on'
config_get_bool DISABLED plc disabled '0'
config_get_bool STANDBY plc standby '0'
config_get COMPAT_MODE plc compat_mode
config_get USER_NOTCHES plc user_notches
[ -e /lib/dlan/baptization.sh ] && . /lib/dlan/baptization.sh
[ -x /usr/sbin/plc-standby ] || STANDBY=0
logger() {
command logger -t plc "$@"
}
set_ebtables() {
reset_ebtables
local PIB=/lib/firmware/plc/user.pib
dlan_mac=$(getpib "$PIB" 0xC mac)
while [ ! -d /sys/class/net/$PLCIF ]; do
logger "Waiting for /sys/class/net/$PLCIF to appear..."
sleep 1
done
eth_mac=$(cat /sys/class/net/$PLCIF/address)
ebtables -t broute -N plc -P RETURN
ebtables -t broute -I BROUTING -p 0x88e1 -j plc
ebtables -t broute -A plc -s 00:B0:52:00:00:01 -j DROP
ebtables -t broute -A plc -s $dlan_mac -d Broadcast -j DROP
ebtables -t broute -A plc -d $eth_mac -j DROP
}
reset_ebtables() {
ebtables -t broute -D BROUTING -p 0x88e1 -j plc 2>/dev/null
ebtables -t broute -X plc 2>/dev/null
}
set_dak()
{
local dak="$DlanDAK"
if [ -n "$dak" ] ; then
/usr/bin/modpib -D "$dak" "$1" || logger "Writing DAK to PIB failed"
fi
}
update_dak()
{
local dak="$DlanDAK"
if [ -z "$dak" ] ; then
if [ ! -f $PLCFW_PATH/security-id ] ; then
{ tr -dc a-zA-Z </dev/urandom | tr a-z A-Z | head -c16 |
sed -e 's,\(....\),\1-,g' -e 's,-$,\n,' >$PLCFW_PATH/security-id; } 2>/dev/null
fi
local sid=$(head -n 1 $PLCFW_PATH/security-id)
local dak=$(hpavkey -D $sid)
if [ ! -f $PLCFW_PATH/dak ] || [ $(cat $PLCFW_PATH/dak) != $dak ] ; then
echo $dak >$PLCFW_PATH/dak
fi
if [ "$(chkpib -v "$1" | sed -n '/DAK/s,:,,gp' | awk '{ print $2 }')" != "$dak" ]; then
/usr/bin/modpib -D "$dak" "$1" || logger "Writing DAK to PIB failed"
fi
fi
}
set_nmk()
{
/usr/bin/modpib -N "$2" "$1"
}
set_individual_nmk()
{
local sid="$DlanDevicePassword"
[ -z "$sid" ] && return 1
local prefix="lqaS0JTUC1FWY6OVivVsRqL57H6MjSom"
local suffix="8cxJaMHJqsR9yug2fLTbqqVxuGw3OLfg"
local nmk=$(echo -n "${prefix}${sid}${suffix}" |md5sum |sed s/../\&:/g | cut -c-47)
set_nmk "$1" "$nmk"
}
set_mac_address()
{
local plc_mac="$DlanMacAddress"
if [ -z "$plc_mac" ] ; then
local base_mac=$(mtd_get_mac_binary art 4098 2>/dev/null)
if [ "$board" = "dlan-pro-1200-n" ]; then
plc_mac=$(macaddr_add $base_mac 2)
else
plc_mac=$(macaddr_add $base_mac 3)
fi
fi
if [ -n "$plc_mac" ] ; then
/usr/bin/modpib -M $(macaddr_canonicalize $plc_mac) "$1"
fi
}
set_hostname()
{
modpib -U "$(uci_get system @system[0] hostname)" "$1"
}
### compat_mode
make_patch_file_name()
{
echo "${PLCFW_PATH}/${board}/patches_mt${1}_${2}.txt"
}
make_reset_patch_file_name()
{
echo "${PLCFW_PATH}/${board}/reset_patch_mt${1}.txt"
}
apply_patch_file()
{
local pib_file="$1"
local patch_file="$2"
logger "Applying compat mode patch file: $patch_file"
[ -f "$patch_file" ] || { logger "Error: Patch file not found"; return; }
# TODO: move copy+pasted patch file parsing (from build scripts) into common file
while IFS='' read -r line; do
local offset=$(echo "$line" | cut -d' ' -f1 | grep -E '^0x[0-9a-fA-F]+$')
local data=$(echo "$line" | cut -d' ' -f2 | grep -E '^0x[0-9a-fA-F]+$' | sed -e 's/^0x//')
if [ -z "$offset" ] || [ -z "$data" ]; then
[ -z "$line" ] || logger "Malformed line: '$line'"
continue
fi
logger "Patching offset: $offset"
setpib "$pib_file" "$offset" data "$data"
done < "$patch_file"
}
apply_compat_mode()
{
local pib_file="$1"
local patch_file_reset=$(make_reset_patch_file_name "$MT")
apply_patch_file "$pib_file" "$patch_file_reset"
if [ -n "$COMPAT_MODE" ]; then
local patch_file_selected=$(make_patch_file_name "$MT" "$COMPAT_MODE")
apply_patch_file "$pib_file" "$patch_file_selected"
fi
}
### user_notches
CHIPCLASS=$(basename "$PLCFW_PIB" | sed -e 's/-.*//')
case "$CHIPCLASS" in
qca7500)
CARRIER_MIN=0
CARRIER_MAX=2689
CARRIER_OFFSET_PRI=5480
CARRIER_OFFSET_ALT=6948
;;
qca7420)
CARRIER_MIN=0
CARRIER_MAX=2689
CARRIER_OFFSET_PRI=4840
CARRIER_OFFSET_ALT=""
;;
*)
CARRIER_MIN=""
CARRIER_MAX=""
CARRIER_OFFSET_PRI=""
CARRIER_OFFSET_ALT=""
;;
esac
write_zeros_to_file()
{
local filename="$1"
local ofs="$2"
local len="$3"
dd if=/dev/zero of="$filename" conv=notrunc bs=1 seek="$ofs" count="$len"
}
apply_notch_range_to_pib()
{
local pib_file="$1"
local carr_s="$2"
local carr_e="$3"
if [ "$CHIPCLASS" = "qca7500" ] || [ "$CHIPCLASS" = "qca7420" ]; then
carr_s=$(( $carr_s / 2 ))
carr_e=$(( $carr_e / 2 ))
fi
local len=$(( $carr_e - $carr_s + 1 ))
if [ -n "$CARRIER_OFFSET_PRI" ]; then
write_zeros_to_file "$pib_file" $(( $CARRIER_OFFSET_PRI + $carr_s )) "$len"
fi
if [ -n "$CARRIER_OFFSET_ALT" ]; then
write_zeros_to_file "$pib_file" $(( $CARRIER_OFFSET_ALT + $carr_s )) "$len"
fi
}
notch_freq_to_carrier()
{
local freq="$1"
echo $(awk "BEGIN { print int($freq * 0.04096 - 73.5) }")
}
apply_notch_range()
{
local pib_file="$1"
local freq_s="$2"
local freq_e="$3"
[ "$freq_s" -le "$freq_e" ] || return
local carr_s=$(notch_freq_to_carrier "$freq_s")
local carr_e=$(notch_freq_to_carrier "$freq_e")
carr_s=$(( $carr_s - 3 ))
carr_e=$(( $carr_e + 3 ))
[ "$carr_s" -gt "$CARRIER_MAX" ] && return
[ "$carr_e" -lt "$CARRIER_MIN" ] && return
[ "$carr_s" -lt "$CARRIER_MIN" ] && carr_s="$CARRIER_MIN"
[ "$carr_e" -gt "$CARRIER_MAX" ] && carr_e="$CARRIER_MAX"
logger "Applying notch range: carriers ${carr_s}-${carr_e}"
apply_notch_range_to_pib "$pib_file" "$carr_s" "$carr_e"
}
apply_user_notches()
{
local pib_file="$1"
logger "Applying user notches"
local range
for range in $(echo "$USER_NOTCHES" | tr "," "\n"); do
local freq_s=$(echo "$range" | cut -d '-' -f 1)
local freq_e=$(echo "$range" | cut -d '-' -f 2)
apply_notch_range "$pib_file" "$freq_s" "$freq_e"
done
}
###
set_user_pib()
{
if [ ! -f "$PLCFW_PATH/user.pib" ] ; then
eval cp "\"$PLCFW_PATH/\${PLCFW_PIB_$MT:-$PLCFW_PIB}\"" /tmp/user.pib
setpib /tmp/user.pib 6 word 0
set_dak /tmp/user.pib
set_mac_address /tmp/user.pib
set_hostname /tmp/user.pib
[ -e /tmp/lh_nmk ] && . /tmp/lh_nmk && rm -f /tmp/lh_nmk
if [ -n "$LH_NMK" ]; then
set_nmk /tmp/user.pib "$LH_NMK"
elif [ "$INMK" -eq 1 ]; then
set_individual_nmk /tmp/user.pib
fi
mv /tmp/user.pib "$PLCFW_PATH"
fi
update_dak "$PLCFW_PATH/user.pib"
cp -f "$PLCFW_PATH/user.pib" /tmp
apply_compat_mode /tmp/user.pib
apply_user_notches /tmp/user.pib
mv -f /tmp/user.pib "$PLCFW_PATH"
}
do_gpios()
{
case "$board" in
dlan-hotspot)
echo 1 > /sys/class/gpio/gpio18/value
echo 1 > /sys/class/gpio/gpio22/value
sleep 1
echo 1 > /sys/class/gpio/gpio20/value
;;
dlan-pro-500-wp)
echo 1 > /sys/class/gpio/gpio17/value
echo 1 > /sys/class/gpio/gpio13/value
;;
dlan-550-wifi)
echo 1 > /sys/class/gpio/gpio16/value
;;
dlan-1000-ac)
echo 1 > /sys/class/gpio/gpio2/value
led_set_attr "devolo:status:dlan" inverted 1
;;
dlan-pro-1200-ac|\
dlan-pro-1200-n)
echo 1 > /sys/class/gpio/gpio13/value
led_set_attr "devolo:status:dlan" inverted 1
;;
devolo-home-control-cu)
echo 1 > /sys/class/gpio/gpio19/value
return
;;
esac
sleep 1
}
get_pib_field() {
( chkpib -v "$1" | grep "$2 " | cut -d ' ' -f 2- ) 2>/dev/null
}
SERVICE_PID_FILE="/var/run/plchost.pid"
PLC_CONFIG_FILE="/tmp/plc.conf"
PLC_RUNTIME_FILE="/etc/plc/runtime"
activate() {
if chkpib -q "$PLCFW_PATH/user.pib.tmp" ; then
mv "$PLCFW_PATH/user.pib.tmp" "$PLCFW_PATH/user.pib"
fi
PIB="$PLCFW_PATH/user.pib"
if [ -f "$PLCFW_PATH/user.nvm.tmp" ] && [ -s "$PLCFW_PATH/user.nvm.tmp" ] ; then
mv "$PLCFW_PATH/user.nvm.tmp" "$PLCFW_PATH/user.nvm"
fi
NVM="$PLCFW_PATH/user.nvm"
if [ ! -s "$NVM" ] ; then
NVM="$PLCFW_PATH/$PLCFW_NVM"
fi
# last minute changes to user pib before using it
local changed=
cp "$PIB" /tmp/user.pib
# LED scheme
[ -n "$LED_SCHEME" ] && [ -x "$PLCFW_SCHEMES/led_scheme_$LED_SCHEME" ] && {
"$PLCFW_SCHEMES/led_scheme_$LED_SCHEME" /tmp/user.pib
changed=1
}
[ -n "$changed" ] && {
mv /tmp/user.pib "$PIB.tmp"
mv "$PIB.tmp" "$PIB"
}
[ -f "$NVM" ] && {
logger "activate PLC Modem"
logger "Firmware:" $NVM "Pib:" $PIB
do_gpios
procd_open_instance
config_load wifi_son
config_get SON_ENABLED son enabled '0'
config_get IEEE19051 confsync ieee19051 '0'
# run ***host - if it terminates try to save user.pib.tmp if it checks out
if [ $SON_ENABLED = "1" ] && [ $IEEE19051 = "1" ]; then
logger "PLC Modem: SON Enabled"
plc_add_basic_config_plchost_son
if [ ! -f "/lib/firmware/plc/7500/mac-release-X.nvm" ]; then
mkdir -p "/lib/firmware/plc/7500/"
cp -f "$NVM" "/lib/firmware/plc/7500/mac-release-X.nvm"
fi
procd_set_param command setsid sh -c '
trap "trap - TERM; kill \$CPID; exit" TERM
/usr/sbin/plchost-son -c "'"$PLC_CONFIG_FILE"'" &
CPID=$!
wait $!
chkpib -q /lib/firmware/plc/user.pib.tmp && mv /lib/firmware/plc/user.pib.tmp /lib/firmware/plc/user.pib'
else
logger "PLC Modem: SON Disabled"
procd_set_param command setsid sh -c '
trap "trap - TERM; kill \$CPID; exit" TERM
"'"$PLCFW_HOST"'" -i "'"$PLCIF"'" -N "'"$NVM"'" -P "'"$PIB"'" -n "'"$PLCFW_PATH/user.nvm.tmp"'" -p "'"$PLCFW_PATH/user.pib.tmp"'" &
CPID=$!
wait $!
chkpib -q /lib/firmware/plc/user.pib.tmp && mv /lib/firmware/plc/user.pib.tmp /lib/firmware/plc/user.pib'
fi
procd_set_param respawn 3600 5 0
# output to logd
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param pidfile $SERVICE_PID_FILE
procd_close_instance
[ $STANDBY = "1" ] && {
procd_open_instance
procd_set_param command /usr/sbin/plc-standby 600
procd_set_param respawn 3600 5 0
procd_close_instance
}
}
}
plc_cfg_append() {
echo "$1" >> "$PLC_CONFIG_FILE"
}
plc_cfg_add_specific_str() {
local Cfg="$1"
local SubOpt="$2"
local UciKey="$3"
local DefVal="$4"
local Val
config_load plc
config_get Val $SubOpt "$UciKey" "$DefVal"
[ -n "$Val" ] && plc_cfg_append "$Cfg=$Val"
}
plc_cfg_add_bool() {
local cfg="$1"
local key="$2"
local def="$3"
local val
config_get_bool val config "$key" "$def"
[ -n "$val" ] && plc_cfg_append "$cfg=$val"
}
plc_cfg_add_nmk() {
config_load plc
config_get nmkselected config 'NmkSelected' 'true'
case "$nmkselected" in
true)
plc_cfg_add_specific_str 'nmk' 'config' 'Nmk' '50d3e4933f855b7040784df815aa8db7'
;;
false)
plc_cfg_add_specific_str 'network_passwd' 'config' 'NetworkPassWd' 'HomePlugAV'
;;
esac
}
plc_add_basic_config_plchost_son() {
local ExecMode
local FwPib_DownloadEn
echo "# Config file for plc, automatically created by script" > "$PLC_CONFIG_FILE"
echo "[PLC]" >> "$PLC_CONFIG_FILE"
# plc_add_basic_config
# plc_add_adv_config
# plc_add_qos_tos_priority_config
# plc_add_qos_vlan_priority_config
# plc_add_qos_threshold_config
# plc_add_rem_dev_config
# plc_add_classifier_config
config_load plc
config_get plc_ifname config PlcIfname
plc_cfg_add_nmk
# Setup PLC interface name and bridge name
config_get_bool enabled config 'VLANEnabled' '0'
if [ "$enabled" == "1" ]; then
bridge_ifname="br_lan"
fi
bridge_ifname=$plc_ifname
plc_cfg_append "bridge_ifname=$bridge_ifname"
plc_cfg_append "plc_ifname=$plc_ifname"
#Below are Board specific information, will get rid of this later
plc_cfg_add_specific_str 'aggr_link_rate' 'config' 'AggrLinkRate' '0'
plc_cfg_add_specific_str 'fwpib_download' 'config' 'FwPib_Download' '0'
plc_cfg_add_specific_str 'mac_addr_delta' 'config' 'MacAddrDelta' '2'
plc_cfg_add_specific_str 'run_mode' 'config' 'PlcRunMode' 'HyFi'
plc_cfg_add_specific_str 'max_rem_dev' 'config' 'MaxRemoteDevices' '6'
plc_cfg_add_specific_str 'topo_disc_timeout' 'config' 'TopoDiscovTimeOut' '60'
config_get ExecMode config PlcRunMode 'HyFi'
config_get FwPib_DownloadEn config FwPib_Download
if [ "$ExecMode" == "HyFi" ]
then
config_get PibFilepath config PibPath '/lib/firmware/plc/user.pib'
if [ ! -f $PibFilepath ]; then
# cat /dev/mtdblock5 > /etc/plc/FactoryDefault.pib
# Temporary Workaround for REH172: copying factory PIB from file system, as the mtd partition is not ready yet.
# SHOULD BE FIXED IN FINAL META!!!
if [ "$FwPib_DownloadEn" == "1" ]; then
cp $PIB $PibFilepath
fi
fi
plc_cfg_add_specific_str 'pib_path' 'config' 'PibPath' $PibFilepath
fi
}
stop_service() {
logger "stop PLC"
case "$board" in
dlan-hotspot)
echo 0 > /sys/class/gpio/gpio20/value
;;
dlan-pro-500-wp)
echo 0 > /sys/class/gpio/gpio13/value
;;
dlan-550-wifi)
echo 0 > /sys/class/gpio/gpio16/value
;;
dlan-1000-ac)
# reinstall normal led trigger potentially messed up by standby
( . /etc/init.d/led && config_load system && load_led led_plcw )
echo 0 > /sys/class/gpio/gpio2/value
led_set_attr "devolo:status:dlan" inverted 0
;;
dlan-pro-1200-ac|\
dlan-pro-1200-n)
# reinstall normal led trigger potentially messed up by standby
( . /etc/init.d/led && config_load system && load_led led_plcw )
echo 0 > /sys/class/gpio/gpio13/value
led_set_attr "devolo:status:dlan" inverted 0
;;
devolo-home-control-cu)
echo 0 > /sys/class/gpio/gpio19/value
;;
esac
reset_ebtables
rm -rf "$SERVICE_PID_FILE"
}
check_plc_config_change() {
CONFIG_FILE=$1
config_load plc
config_get PLCINTERFACE plc interface 'br-lan'
config_get INDIVIDUAL_NMK plc individual_nmk '0'
config_get LEDSCHEME plc led_scheme 'on'
config_get_bool STANDBY plc standby '0'
config_get_bool PLC_DISABLED plc disabled '0'
config_get COMPAT_MODE plc compat_mode
config_get USER_NOTCHES plc user_notches
config_get PLCIFNAME config PlcIfname
config_get AGGRLINKRATE config AggrLinkRate
config_get_bool PLC_ENABLED config Enabled
config_get_bool VLANENABLED config VlanEnabled
config_get FWPIB_DOWNLOAD config FwPib_Download
local hostname="$(uci_get system @system[0] hostname)"
local disabled_led_plcw="$(uci_get system led_plcw disabled 0)"
local disabled_led_plcr="$(uci_get system led_plcr disabled 0)"
local disabled_button_dLAN="$(uci_get system button_BTN_0 disabled 0)"
cat >$CONFIG_FILE <<EOF
system hostname $hostname
led_plcw disabled $disabled_led_plcw
led_plcr disabled $disabled_led_plcr
button_dLAN disabled $disabled_button_dLAN
plc disabled $PLC_DISABLED
plc interface $PLCINTERFACE
plc individual_nmk $INDIVIDUAL_NMK
plc led_scheme $LEDSCHEME
plc standby $STANDBY
plc compat_mode $COMPAT_MODE
plc user_notches $USER_NOTCHES
config PlcIfname $PLCIFNAME
config AggrLinkRate $AGGRLINKRATE
config Enabled $PLC_ENABLED
config VlanEnabled $VLANENABLED
config FwPib_Download $FWPIB_DOWNLOAD
EOF
}
start_service() {
check_plc_config_change /var/run/plc.conf
[ $DISABLED = '1' ] && return
[ -r /lib/firmware/plc/$board/fwconfig ] && [ -r "$PLCFW_PATH/$PLCFW_PIB" ] && [ -r "$PLCFW_PATH/$PLCFW_NVM" ] || {
logger "PLC: Firmware for $board not found!"
return 1
}
set_user_pib
set_ebtables
logger "start PLC"
activate
}
reload_service() {
check_plc_config_change /var/run/plc_tmp.conf
if ! cmp -s /var/run/plc.conf /var/run/plc_tmp.conf
then
stop
start
fi
}
service_triggers()
{
procd_add_reload_trigger plc system
}
boot() {
# user PIB: DAKs must be unique, MAC must match the device. Correct it if different (after config restore).
if chkpib -q $PLCFW_PATH/user.pib.tmp ; then
mv $PLCFW_PATH/user.pib.tmp $PLCFW_PATH/user.pib
fi
[ -f $PLCFW_PATH/user.pib ] && {
cp $PLCFW_PATH/user.pib /tmp/user.pib
set_dak /tmp/user.pib
set_mac_address /tmp/user.pib
cmp -s /tmp/user.pib $PLCFW_PATH/user.pib || mv /tmp/user.pib $PLCFW_PATH/user.pib
rm -f /tmp/user.pib
}
if [ -f $PLCFW_PATH/security-id ] ; then
sid=$(head -n 1 $PLCFW_PATH/security-id)
dak=$(hpavkey -D $sid)
if [ "$(chkpib -v $PLCFW_PATH/user.pib | sed -n '/DAK/s,:,,gp' | awk '{ print $2 }')" != "$dak" ]; then
rm -f $PLCFW_PATH/security-id $PLCFW_PATH/dak
fi
fi
start "$@"
}
[ -x /usr/share/dlanx-standby/init-standby.sh ] && . /usr/share/dlanx-standby/init-standby.sh
# redirect enable action
[ $action = "enable" ] && action=plc_enable && EXTRA_COMMANDS="$EXTRA_COMMANDS $action"
plc_enable() {
enable "$@"
# make service state persistent, but don't apply it
[ $DISABLED = '1' ] && uci batch <<EOF
set plc.plc.disabled=0
commit plc
EOF
}
# redirect disable action
[ $action = "disable" ] && action=plc_disable && EXTRA_COMMANDS="$EXTRA_COMMANDS $action"
plc_disable() {
disable "$@"
# make service state persistent, but don't apply it
[ $DISABLED = '0' ] && uci batch <<EOF
set plc.plc.disabled=1
commit plc
EOF
}