From: Georgios Kontaxis Date: Sun, 21 Jun 2026 20:08:12 +0000 (+0000) Subject: etherwake: wait for the interface to come up before transmitting X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=3c2aa9faf5ed42856b6ce2c7c1febb7dfe23186b;p=openwrt-packages.git etherwake: wait for the interface to come up before transmitting Transmitting WOL packages without checking the status of the outgoing interface, especially during system boot, risks the packages getting lost because the interface isn't up yet. We wait between zero and 'interface_timeout' seconds before either transmitting or giving up. Signed-off-by: Georgios Kontaxis --- diff --git a/net/etherwake/files/etherwake.config b/net/etherwake/files/etherwake.config index cf025dcad..4847aa1d1 100644 --- a/net/etherwake/files/etherwake.config +++ b/net/etherwake/files/etherwake.config @@ -1,17 +1,27 @@ config 'etherwake' 'setup' # interface to use, defaults to 'eth0' #option 'interface' 'eth0' + + # maximum wait during system boot for the interface to be up + # - defaults to 10 seconds + # - 0 seconds means no wait or check that the interface is up + #option 'interface_timeout' '10' + # send wake-up packet to the broadcast address, defaults to off #option 'broadcast' 'off' config 'target' # name for the target #option 'name' 'example' + # mac address of the machine to wake up #option 'mac' '00:11:22:33:44:55' + # (optional) 6-byte secureOn password in ethernet hex format #option 'secureon' 'aa:bb:cc:dd:ee:ff' + # (optional) 4-byte secureOn password in dotted decimal format #option 'secureon' '170.187.204.221' + # wake up on system start, defaults to off #option 'wakeonboot' 'off' diff --git a/net/etherwake/files/etherwake.init b/net/etherwake/files/etherwake.init index 1ca4cc6e6..ba94c73fc 100644 --- a/net/etherwake/files/etherwake.init +++ b/net/etherwake/files/etherwake.init @@ -2,107 +2,180 @@ # Copyright (C) 2009 OpenWrt.org NAME='etherwake' -START=60 +START=99 PROGRAM='/usr/bin/etherwake' -start() -{ - local value='' +boot() { + etherwake_boot & +} + +etherwake_boot() { + etherwake_load_config_setup + + local iface="${ETHERWAKE_CONFIG_SETUP_IFACE}" + local timeout="${ETHERWAKE_CONFIG_SETUP_TIMEOUT}" + + if [ "${timeout}" != "0" ] && + ! etherwake_wait_for_iface "${iface}" "${timeout}"; then + logger -t "${NAME}" \ + "Interface '${iface}' did not come up within ${timeout} seconds" + return 1 + fi + + start +} + +ETHERWAKE_CONFIG_LOADED='0' +ETHERWAKE_CONFIG_SETUP_IFACE='' +ETHERWAKE_CONFIG_SETUP_TIMEOUT=1 +ETHERWAKE_CONFIG_SETUP_BROADCAST='0' + +etherwake_load_config_setup() { + [ "${ETHERWAKE_CONFIG_LOADED}" != "0" ] && return config_load "${NAME}" - # interface - config_get value 'setup' 'interface' 'eth0' - append PROGRAM "-i ${value}" + config_get ETHERWAKE_CONFIG_SETUP_IFACE 'setup' 'interface' 'eth0' + + config_get ETHERWAKE_CONFIG_SETUP_TIMEOUT 'setup' 'interface_timeout' + case "${ETHERWAKE_CONFIG_SETUP_TIMEOUT}" in + ''|*[!0-9]*) + ETHERWAKE_CONFIG_SETUP_TIMEOUT=10 + ;; + esac - # broadcast - config_get_bool value 'setup' 'broadcast' '0' - [ "${value}" -ne 0 ] && append PROGRAM '-b' + config_get_bool ETHERWAKE_CONFIG_SETUP_BROADCAST 'setup' 'broadcast' '0' - # wake up targets - config_foreach etherwake_start target $* + ETHERWAKE_CONFIG_LOADED=1 } -etherwake_start() -{ - local section="$1" - shift +# etherwake_wait_for_iface [] +# +# wait up to 'timeout' seconds for interface 'iface' to come up. +# - when 'timeout' is set to 0 the function returns immediately +# without checking the status of the interface +# - default 'timeout' is 1 +etherwake_wait_for_iface() { + local iface="$1" + local timeout="${2:-1}" + + [ -n "${iface}" ] || return 1 + + local interval=1 + local elapsed=0 + + while [ "${elapsed}" -lt "${timeout}" ]; do + if [ "$(ubus call network.interface."${iface}" status 2> /dev/null | + jsonfilter -e '@.up' 2> /dev/null)" = "true" ]; then + logger -t "${NAME}" \ + "Interface '${iface}' is up after ${elapsed} seconds" + return 0 + fi + + sleep "${interval}" + elapsed=$((elapsed + interval)) + done + + return 1 +} - local names="$*" +ETHERWAKE_LAST_ERROR=0 + +start() { + etherwake_load_config_setup + + ETHERWAKE_LAST_ERROR=0 + + config_foreach etherwake_start target \ + "${ETHERWAKE_CONFIG_SETUP_IFACE}" \ + "${ETHERWAKE_CONFIG_SETUP_BROADCAST}" "$@" + + return ${ETHERWAKE_LAST_ERROR} +} + +# etherwake_start
[ ...] +etherwake_start() { + local section="$1"; shift + local iface="$1"; shift + local broadcast="$1"; shift local value='' - local target='' + local filter='' - if [ -z "${names}" ] - then - # check if boot target + # are we focusing on all targets that should wake up when this script runs + # or specific names? + if [ $# -eq 0 ]; then config_get_bool value "${section}" 'wakeonboot' '0' [ "${value}" -eq 0 ] && return 0 - # wake up target - do_etherwake "${section}" - return $? - else - # name - config_get value "${section}" 'name' - [ -z "${value}" ] && return 0 - - for target in ${names} - do - [ "${value}" != "${target}" ] && continue - - # wake up target - do_etherwake "${section}" - return $? - done + do_etherwake "${section}" "${iface}" "${broadcast}" || ETHERWAKE_LAST_ERROR=$? + return 0 fi + + config_get value "${section}" 'name' + [ -z "${value}" ] && return 0 + + for filter in "$@"; do + [ "${value}" != "${filter}" ] && continue + + do_etherwake "${section}" "${iface}" "${broadcast}" || ETHERWAKE_LAST_ERROR=$? + break + done + + return 0 } # execute etherwake command for target -do_etherwake() -{ +do_etherwake() { local section="$1" - local value='' - local password='' - local args='' + local iface="$2" + local device='' + local broadcast="$3" + local section_name='' + local mac='' + local password='' + local secureon='' + + . /lib/functions/network.sh + network_get_device device "${iface}" || device="${iface}" + + config_get section_name "${section}" 'name' "${section}" + + config_get mac "${section}" 'mac' + [ -z "${mac}" ] && { + logger -t "${NAME}" "Target '${section_name}' has no 'mac' address" + return 1 + } # password (legacy option) - config_get value "${section}" 'password' - [ -n "${value}" ] && { - password=$(etherwake_password "${value}") + config_get password "${section}" 'password' + [ -n "${password}" ] && { + password=$(etherwake_password "${password}") } - # secureOn password - config_get value "${section}" 'secureon' - if [ -n "${value}" ]; then - append args "-p ${value}" + config_get secureon "${section}" 'secureon' + + set -- + [ -n "${device}" ] && set -- "$@" -i "${device}" + [ "${broadcast}" = "1" ] && set -- "$@" -b + if [ -n "${secureon}" ]; then + set -- "$@" -p "${secureon}" elif [ -n "${password}" ]; then - append args "-p ${password}" + set -- "$@" -p "${password}" fi + set -- "$@" "${mac}" - # name - config_get section_name "${section}" 'name' - [ -z "${section_name}" ] && section_name="${section}" + logger -t "${NAME}" "Waking up '${section_name}' via ${PROGRAM} $*" - # mac address - config_get value "${section}" 'mac' - [ -z "${value}" ] && { - echo "Target '${section_name}' has no 'mac' address"; return 1; } - append args "${value}" + "${PROGRAM}" "$@" - # execute command - echo "Waking up '${section_name}' via ${PROGRAM}${args:+ ${args}}" - ${PROGRAM} ${args} return $? } - -# prepare hex password (support legacy option) -etherwake_password() -{ +# make string look like ethernet hex format (support legacy password option) +etherwake_password() { local delimiter=':' - local password=`echo "$1" | sed "s/../&${delimiter}/g"` + local password=$(echo "$1" | sed "s/../&${delimiter}/g") echo "${password%${delimiter}}" - return }