Skip to content

Instantly share code, notes, and snippets.

@emabrey
Last active December 23, 2025 20:19
Show Gist options
  • Select an option

  • Save emabrey/4c8e21f37c40ea35e1f3a529223732cc to your computer and use it in GitHub Desktop.

Select an option

Save emabrey/4c8e21f37c40ea35e1f3a529223732cc to your computer and use it in GitHub Desktop.
Hotplug script for modifying the logging level of the hostapd daemon on an openWRT device
#! /bin/sh
# SPDX-License-Identifier: GPL-2.0-only
# License available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# Script written by emabrey; based upon a script written by compact21
# Hotplug script for modifying the logging level of the hostapd daemon. This
# is a workaround for the hardcoded OpenWRT logging level not respecting
# modifications to the setting through the usual means (LuCI, UCI, etc.)
# The other non-working methods are available on the openWRT website at:
# https://openwrt.org/docs/guide-developer/debugging
#
# Recommended filename/location: /etc/hotplug.d/net/99-hostapd-log-level
#
# This script requires: hostapd_cli, sort, cut, printf (usually provided via entware packages `hostapd-utils` & `busybox`)
# This script includes enhancements if awk and head are present, but they are not required for basic functionality
# The log level to assign to the hostapd daemon for each wireless interface; should be upper case
# If awk is present then this will be converted to all upper case and checked for validity (see below for valid values)
# The hostapd daemon will only print messages at this level *or higher*
LOG_LEVEL="ERROR"
# write_log <priority pair> <message>
write_log () {
if command -v logger >/dev/null 2>&1; then
# Write to normal openWRT log ringbuffer
logger -t hotplug -p "$1" "$2";
elif command -v printf >/dev/null 2>&1; then
# Write to backup kernel ringbuffer using printf
printf "%s\n" "$1: $2" >> /dev/kmsg;
elif command -v echo >/dev/null 2>&1; then
# Write to backup kernel ringbuffer using echo
# Even though printf is required, we need to be able to log
# that it is missing so echo backup is needed
echo "$1: $2" >> /dev/kmsg;
else
# If you don't have logger, printf, or echo then you've ascended beyond the need for logs
exit 0;
fi
}
# Verify required busybox commands exist
for program in "printf" "cut" "sort"; do
if ! command -v $program >/dev/null 2>&1; then
write_log user.notice "Unable to change hostapd logging level because the $program program was not found";
write_log user.notice "The $program program should be part of openWRT base; is busybox installed?";
write_log user.notice "Running \`opkg update && opkg install busybox\` may fix this issue";
exit 0;
fi;
done;
# Check that we actually have the needed runtime options; should be provided by hotplugd
# but hypothetically a user could call this script directly so lets give them some helptext
if [ -z "${DEVICENAME}" ] || [ -z "${ACTION}" ]; then
printf "%s\n" "$0 - hotplug daemon script which modifies the hostapd log level(s)";
printf "%s\n" "\$DEVICENAME and \$ACTION variables must be set and non-empty; execution skipped"
exit 0;
fi;
# Verify hostapd daemon cli frontend exists
if ! command -v hostapd_cli >/dev/null 2>&1; then
write_log user.notice "Unable to change hostapd logging level because the hostapd_cli program was not found";
write_log user.notice "Please run \`opkg update && opkg install hostapd_utils\` to install the missing program";
exit 0;
fi;
# Ensure that the log level is a valid value (uppercase and present in wpa_debug.h enum)
if command -v awk >/dev/null 2>&1; then
# Make sure log level is upper case
LOG_LEVEL=$(printf "%s" "$LOG_LEVEL" | awk '{print toupper($0)}');
# See https://github.com/digsrc/wpa_supplicant/blob/master/src/utils/wpa_debug.h#L21
# enum {
# MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR
# };
if [ -z "$LOG_LEVEL" ] || [ "$(printf "%s" "$LOG_LEVEL" | awk '/[^(EXCESSIVE|MSGDUMP|DEBUG|INFO|WARNING|ERROR)]/{print $0}')" != "" ]; then
write_log user.notice "Unable to change hostapd logging level because logging level ${LOG_LEVEL-null} is not valid";
write_log user.notice "Potentially valid values include: EXCESSIVE, MSGDUMP, DEBUG, INFO, WARNING, or ERROR";
exit 0;
fi;
fi;
#For each wireless interface by name
for ap_iface in $(printf '%s\n' /sys/class/ieee80211/*/device/net/*/ | cut -d/ -f8 | sort -u); do
#If the current device being hotplugged is one of our interfaces then...
if [ "${DEVICENAME}" = "${ap_iface}" ] && [ "${ACTION}" = "add" ]; then
# Try to log the current logging level, but if not possible this is skipped
if command -v head >/dev/null 2>&1 && command -v awk >/dev/null 2>&1; then
CURRENT_LOG_LEVEL=$(hostapd_cli -i "${DEVICENAME}" log_level | head -n 1 | awk -F" " '{print $NF}');
write_log user.info "Device [${DEVICENAME}]: hostapd initial logging level was ${CURRENT_LOG_LEVEL:-not configured}";
fi;
# Change the log level and exit early to prevent wasted cycles
hostapd_cli -i "${DEVICENAME}" log_level "${LOG_LEVEL}";
write_log user.info "Device [${DEVICENAME}]: hostapd logging level changed to ${LOG_LEVEL}";
break;
fi;
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment