]> git.99rst.org Git - openwrt-packages.git/commitdiff
etherwake: wait for the interface to come up before transmitting
authorGeorgios Kontaxis <redacted>
Sun, 21 Jun 2026 20:08:12 +0000 (20:08 +0000)
committerGeorgios Kontaxis <redacted>
Fri, 31 Jul 2026 07:26:41 +0000 (07:26 +0000)
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 <redacted>
net/etherwake/files/etherwake.config
net/etherwake/files/etherwake.init

index cf025dcad91374a649f2fd52bab1775e923b67c0..4847aa1d139e86b68a49e531389aa2d2ea26d78f 100644 (file)
@@ -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'
index 1ca4cc6e672cbf3eaa312e55c46ef8ae65357a0f..ba94c73fcc0df0402bad3210d4e05453abd50a58 100644 (file)
 # 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 <interface> [<timeout>]
+#
+# 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 <section> <interface> <broadcast> [<name> ...]
+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
 }
git clone https://git.99rst.org/PROJECT