since I upgraded my ipfire in 199 version, I have an error initialising hostapd
Jan 7 16:18:34 myfire hostapd: Configuration file: /etc/hostapd.conf
Jan 7 16:18:34 myfire hostapd: ctrl_interface_group=0
Jan 7 16:18:34 myfire hostapd: Line 22: invalid SSID ‘“”’
Jan 7 16:18:34 myfire hostapd: Line 27: invalid WPA passphrase length 1 (expected 8..63)
Jan 7 16:18:34 myfire hostapd: WPA-PSK enabled, but PSK or passphrase is not configured.
Jan 7 16:18:34 myfire hostapd: 3 errors found in configuration file ‘/etc/hostapd.conf’
Jan 7 16:18:34 myfire hostapd: Failed to set up interface with /etc/hostapd.conf
Jan 7 16:18:34 myfire hostapd: hostapd_init: free iface 0x181d08e0
Jan 7 16:18:34 myfire hostapd: Failed to initialize interface
Here is the fixed init script addressing both issues:
#!/bin/sh
###############################################################################
# #
# IPFire.org - A linux based firewall #
# Copyright (C) 2007-2022 IPFire Team <info@ipfire.org> #
# #
###############################################################################
. /etc/sysconfig/rc
. ${rc_functions}
declare -A HT_CAPS=(
[0x0001]="[LDPC]"
[0x0002]="[HT40+][HT40-]"
[0x0010]="[GF]"
[0x0020]="[SHORT-GI-20]"
[0x0040]="[SHORT-GI-40]"
[0x0080]="[TX-STBC]"
[0x0400]="[DELAYED-BA]"
[0x0800]="[MAX-AMSDU-7935]"
[0x1000]="[DSSS_CCK-40]"
[0x4000]="[40-INTOLERANT]"
[0x8000]="[LSIG-TXOP-PROT]"
)
declare -A VHT_CAPS=(
[0x00000010]="[RXLDPC]"
[0x00000020]="[SHORT-GI-80]"
[0x00000040]="[SHORT-GI-160]"
[0x00000080]="[TX-STBC-2BY1]"
[0x00000800]="[SU-BEAMFORMER]"
[0x00001000]="[SU-BEAMFORMEE]"
[0x00080000]="[MU-BEAMFORMER]"
[0x00100000]="[MU-BEAMFORMEE]"
[0x00200000]="[VHT-TXOP-PS]"
[0x00400000]="[HTC-VHT]"
[0x10000000]="[RX-ANTENNA-PATTERN]"
[0x20000000]="[TX-ANTENNA-PATTERN]"
)
declare -A HE_MAC_CAPS=()
declare -A HE_PHY_CAPS=(
[0x08000000000]="he_su_beamformer=1"
[0x10000000000]="he_su_beamformee=1"
[0x20000000000]="he_mu_beamformer=1"
)
declare -A EHT_MAC_CAPS=()
declare -A EHT_PHY_CAPS=(
[0x0000000000000010]="eht_su_beamformer=1"
[0x0000000000000020]="eht_su_beamformee=1"
)
find_interface() {
local address="${1}"
local path
for path in /sys/class/net/*; do
if [ -s "${path}/address" ] && [ "$(<${path}/address)" = "${address}" ]; then
basename "${path}"
return 0
fi
done
return 1;
}
write_config() {
local interface="${1}"
local settings="/var/ipfire/wlanap/settings"
# FIX: Extract SSID and PWD directly and strip quotes to avoid $PWD collision
# and shell expansion issues with special characters.
local LOCAL_SSID=$(grep "^SSID=" "${settings}" | cut -d'=' -f2- | sed 's/^"//;s/"$//;s/^\x27//;s/\x27$//')
local LOCAL_PASS=$(grep "^PWD=" "${settings}" | cut -d'=' -f2- | sed 's/^"//;s/"$//;s/^\x27//;s/\x27$//')
# Fetch the PHY
local phy="$(</sys/class/net/${interface}/phy80211/name)"
local flag
local ht_flags=0
local vht_flags=0
local he_mac_flags=0
local he_phy_flags=0
local eht_mac_flags=0
local eht_phy_flags=0
# Set default BAND if none is set
if [ -z "${BAND}" ]; then
case "${HW_MODE}" in
gn) BAND="2g" ;;
*) BAND="5g" ;;
esac
fi
# Fetch PHY information
local line
while read -r line; do
case "${line}" in
"EHT MAC Capabilities"*) eht_mac_flags="${line:22:6}" ;;
"EHT PHY Capabilities"*) eht_phy_flags="${line:23:18}" ;;
"HE MAC Capabilities"*) he_mac_flags="${line:21:14}" ;;
"HE PHY Capabilities"*) he_phy_flags="${line:22:24}" ;;
"VHT Capabilities"*) vht_flags="${line:18:10}" ;;
"Capabilities: "*) ht_flags="${line:14}" ;;
"* 2412.0 MHz"*) [ "${BAND}" = "2g" ] && break ;;
"* 5180.0 MHz"*) [ "${BAND}" = "5g" ] && break ;;
esac
done <<<"$(iw phy "${phy}" info)"
local ht_caps=()
local vht_caps=()
local he_caps=()
local eht_caps=()
# HT Capabilities
for flag in ${!HT_CAPS[@]}; do
if (( ${ht_flags} & ${flag} )); then
ht_caps+=( "${HT_CAPS[${flag}]}" )
fi
done
# RX STBC
case "$(( (${ht_flags} >> 8) & 0x03 ))" in
1) ht_caps+=( "[RX-STBC1]" ) ;;
2) ht_caps+=( "[RX-STBC12]" ) ;;
3) ht_caps+=( "[RX-STBC123]" ) ;;
esac
# VHT Capabilities
for flag in ${!VHT_CAPS[@]}; do
if (( ${vht_flags} & ${flag} )); then
vht_caps+=( "${VHT_CAPS[${flag}]}" )
fi
done
# Supported channel width
case "$(( (${vht_flags} >> 2) & 0x03 ))" in
1) vht_caps+=( "[VHT160]" ) ;;
2) vht_caps+=( "[VHT160-80PLUS80]" ) ;;
esac
# VHT Max MPDU Length
case "$(( ${vht_flags} & 0x03 ))" in
1) vht_caps+=( "[MAX-MPDU-7991]" ) ;;
2) vht_caps+=( "[MAX-MPDU-11454]" ) ;;
esac
# RX Spatial Streams
case "$(( (${vht_flags} >> 8) & 0x03 ))" in
1) vht_caps+=( "[RX-STBC-1]" ) ;;
2) vht_caps+=( "[RX-STBC-12]" ) ;;
3) vht_caps+=( "[RX-STBC-123]" ) ;;
4) vht_caps+=( "[RX-STBC-1234]" ) ;;
esac
# Compressed Steering
case "$(( ((${vht_flags} >> 13) & 0x03) + 1 ))" in
2) vht_caps+=( "[BF-ANTENNA-2]" ) ;;
3) vht_caps+=( "[BF-ANTENNA-3]" ) ;;
4) vht_caps+=( "[BF-ANTENNA-4]" ) ;;
esac
# Sounding Dimension
case "$(( ((${vht_flags} >> 16) & 0x03) + 1 ))" in
2) vht_caps+=( "[SOUNDING-DIMENSION-2]" ) ;;
3) vht_caps+=( "[SOUNDING-DIMENSION-3]" ) ;;
4) vht_caps+=( "[SOUNDING-DIMENSION-4]" ) ;;
esac
local exponent="$(( (${vht_flags} >> 23) & 0x03 ))"
vht_caps+=( "[MAX-A-MPDU-LEN-EXP${exponent}]" )
# VHT Link Adaptation
case "$(( (${vht_flags} >> 26) & 0x03 ))" in
2) vht_caps+=( "[VHT-LINK-ADAPT2]" ) ;;
3) vht_caps+=( "[VHT-LINK-ADAPT3]" ) ;;
esac
# HE PHY Capabilities
for flag in ${!HE_PHY_CAPS[@]}; do
if (( ${he_phy_flags} & ${flag} )); then
he_caps+=( "${HE_PHY_CAPS[${flag}]}" )
fi
done
# EHT PHY Capabilities
for flag in ${!EHT_PHY_CAPS[@]}; do
if (( ${eht_phy_flags} & ${flag} )); then
eht_caps+=( "${EHT_PHY_CAPS[${flag}]}" )
fi
done
# Set the channel to zero if not set
[ -z "${CHANNEL}" ] && CHANNEL=0
# Translate the old HW_MODE to the newer MODE setting
if [ -z "${MODE}" ]; then
case "${HW_MODE}" in
ac) MODE="VHT20" ;;
an|gn) MODE="HT20" ;;
esac
fi
# Header
echo "# Automatically generated configuration - DO NOT EDIT"
echo "logger_syslog=-1"
echo "logger_syslog_level=4"
echo "driver=nl80211"
echo "country_code=${COUNTRY}"
echo "country3=0x49"
echo "ieee80211d=1"
echo "ieee80211h=1"
[ -n "${CHANNEL}" ] && echo "channel=${CHANNEL}"
echo "local_pwr_constraint=3"
echo "spectrum_mgmt_required=1"
echo "enable_background_radar=1"
echo "wmm_enabled=1"
# 802.11ac configuration
local enable_ac=0; local vht_oper_chwidth=0; local vht_oper_centr_freq_seg0_idx=""
case "${MODE}" in
VHT20|HE20|EHT20) enable_ac=1 ;;
VHT40|HE40|EHT40) enable_ac=1
if [ "${CHANNEL}" -gt 0 ]; then
case "$(( (${CHANNEL} / 4) % 2 ))" in
0) vht_oper_centr_freq_seg0_idx="$(( ${CHANNEL} - 2 ))" ;;
1) vht_oper_centr_freq_seg0_idx="$(( ${CHANNEL} + 2 ))" ;;
esac
fi ;;
VHT80|HE80|EHT80) enable_ac=1; vht_oper_chwidth=1
if [ "${CHANNEL}" -gt 0 ]; then
case "$(( (${CHANNEL} / 4) % 4 ))" in
0) vht_oper_centr_freq_seg0_idx="$(( ${CHANNEL} - 6 ))" ;;
1) vht_oper_centr_freq_seg0_idx="$(( ${CHANNEL} + 6 ))" ;;
2) vht_oper_centr_freq_seg0_idx="$(( ${CHANNEL} + 2 ))" ;;
3) vht_oper_centr_freq_seg0_idx="$(( ${CHANNEL} - 2 ))" ;;
esac
fi ;;
VHT160|HE160|EHT160|EHT320) enable_ac=1; vht_oper_chwidth=2
if [ "${CHANNEL}" -gt 0 ]; then
case "${CHANNEL}" in
36|40|44|48|52|56|60|64) vht_oper_centr_freq_seg0_idx=50 ;;
100|104|108|112|116|120|124|128) vht_oper_centr_freq_seg0_idx=114 ;;
149|153|157|161|165|169|173|177) vht_oper_centr_freq_seg0_idx=163 ;;
esac
fi ;;
esac
# 802.11ax/be configuration
local enable_ax=0; local he_oper_chwidth="${vht_oper_chwidth}"; local he_oper_centr_freq_seg0_idx="${vht_oper_centr_freq_seg0_idx}"
case "${MODE}" in HE*|EHT*) enable_ax=1 ;; esac
local enable_be=0; local eht_oper_chwidth="${he_oper_chwidth}"; local eht_oper_centr_freq_seg0_idx="${he_oper_centr_freq_seg0_idx}"
case "${MODE}" in EHT*) enable_be=1 ;; esac
# Set hardware mode
case "${BAND}" in
5g) echo "hw_mode=a" ;;
2g) echo "hw_mode=g" ;;
esac
# Enable 802.11be
if [ "${enable_be}" -eq 1 ]; then
echo "ieee80211be=1"
echo "eht_oper_chwidth=${eht_oper_chwidth}"
echo "eht_oper_centr_freq_seg0_idx=${eht_oper_centr_freq_seg0_idx}"
[ ${#eht_caps[@]} -gt 0 ] && printf "%s\n" "${eht_caps[@]}"
fi
# Enable 802.11ax
if [ "${enable_ax}" -eq 1 ]; then
echo "ieee80211ax=1"
echo "he_oper_chwidth=${he_oper_chwidth}"
echo "he_oper_centr_freq_seg0_idx=${he_oper_centr_freq_seg0_idx}"
[ ${#he_caps[@]} -gt 0 ] && printf "%s\n" "${he_caps[@]}"
fi
# Enable 802.11ac
if [ "${enable_ac}" -eq 1 ]; then
echo "ieee80211ac=1"
echo "vht_oper_chwidth=${vht_oper_chwidth}"
echo "vht_oper_centr_freq_seg0_idx=${vht_oper_centr_freq_seg0_idx}"
[ ${#vht_caps[@]} -gt 0 ] && echo "vht_capab=${vht_caps[@]}"
fi
# Enable 802.11n
echo "ieee80211n=1"
[ ${#ht_caps[@]} -gt 0 ] && echo "ht_capab=${ht_caps[@]}"
# Configure antennas
[ -z "${RX_ANTENNAS}" ] && RX_ANTENNAS="0xffffffff"
[ -z "${TX_ANTENNAS}" ] && TX_ANTENNAS="0xffffffff"
iw phy "${phy}" set antenna "${TX_ANTENNAS}" "${RX_ANTENNAS}" &>/dev/null
# General hostapd settings
echo "auth_algs=1"
echo "ctrl_interface=/var/run/hostapd"
echo "ctrl_interface_group=0"
echo "disassoc_low_ack=1"
# SSID Fix: Use Hex-Encoding (ssid2) to ensure special character compatibility
printf "ssid2=%s\n" "$(echo -n "${LOCAL_SSID}" | xxd -p)"
echo "utf8_ssid=1"
[ "${HIDESSID}" = "on" ] && echo "ignore_broadcast_ssid=2"
[ "${CLIENTISOLATION}" = "on" ] && echo "ap_isolate=1"
[ "${NOSCAN}" = "on" ] && echo "noscan=1" || echo "noscan=0"
# Management Frame Protection (802.11w)
case "${IEEE80211W}" in
on) echo "ieee80211w=2"; echo "beacon_prot=1"; echo "ocv=1" ;;
optional) echo "ieee80211w=1"; echo "beacon_prot=1"; echo "ocv=2" ;;
*) echo "ieee80211w=0" ;;
esac
# Encryption Fix: Use locally extracted password to bypass shell expansion bugs
case "${ENC}" in
wpa3)
echo "wpa=2"
echo "wpa_passphrase=${LOCAL_PASS}"
echo "wpa_key_mgmt=SAE"
echo "rsn_pairwise=CCMP" ;;
wpa2+3)
echo "wpa=2"
echo "wpa_passphrase=${LOCAL_PASS}"
echo "wpa_key_mgmt=WPA-PSK WPA-PSK-SHA256 SAE"
echo "rsn_pairwise=CCMP" ;;
wpa2)
echo "wpa=2"
echo "wpa_passphrase=${LOCAL_PASS}"
echo "wpa_key_mgmt=WPA-PSK WPA-PSK-SHA256"
echo "rsn_pairwise=CCMP" ;;
wpa1+2)
echo "wpa=3"
echo "wpa_passphrase=${LOCAL_PASS}"
echo "wpa_key_mgmt=WPA-PSK WPA-PSK-SHA256"
echo "wpa_pairwise=TKIP"
echo "rsn_pairwise=CCMP" ;;
wpa1)
echo "wpa=1"
echo "wpa_passphrase=${LOCAL_PASS}"
echo "wpa_key_mgmt=WPA-PSK WPA-PSK-SHA256"
echo "wpa_pairwise=TKIP" ;;
esac
# Steering and Optimization
case "${IEEE80211W}" in on|optional) echo "mbo=1"; echo "mbo_cell_data_conn_pref=1" ;; esac
echo "ssid_protection=1"
echo "extended_key_id=1"
echo "oce=7"
echo "interworking=1"
echo "access_network_type=0"
echo "internet=1"
echo "time_advertisement=2"
echo "multicast_to_unicast=1"
return 0
}
# Load general settings
# Note: SSID/PWD will be safely re-extracted in write_config
eval $(/usr/local/bin/readhash /var/ipfire/wlanap/settings)
case "${1}" in
start)
interface="$(find_interface "${INTERFACE}")"
if [ -z "${interface}" ]; then
boot_mesg "Could not find interface ${INTERFACE}"; echo_failure; exit 1
fi
if ! write_config "${interface}" > /etc/hostapd.conf; then
boot_mesg "Failed to generate configuration"; echo_failure; exit 1
fi
args=(/usr/bin/hostapd -s -B /etc/hostapd.conf -i "${interface}")
if [ -n "${DEBUG}" ] && [[ "${DEBUG}" =~ ^[0-9]+$ ]]; then
for (( i = 0; i < DEBUG; i++ )); do args+=( "-d" ); done
fi
boot_mesg "Starting hostapd... "; loadproc "${args[@]}" ;;
stop)
boot_mesg "Stopping hostapd..."; killproc /usr/bin/hostapd; evaluate_retval ;;
restart) ${0} stop; sleep 1; ${0} start ;;
status) statusproc /usr/bin/hostapd ;;
show-config)
interface="$(find_interface "${INTERFACE}")"
[ -z "${interface}" ] && exit 1
write_config "${interface}" ;;
*) echo "Usage: ${0} {start|stop|restart|status|show-config}"; exit 1 ;;
esac
There are two main problems in /etc/init.d/hostapd:
Variable Collision: The script uses $PWD, which is a reserved shell environment variable (Print Working Directory). When readhash tries to assign the password to PWD, it either fails or gets overwritten by the system.
Shell Expansion: Special characters like ! trigger Bash history expansion or misinterpretation during the eval $(readhash ...) process, leading to empty strings in the final hostapd.conf.
The Fix: Extract SSID and Passphrase directly from the settings file using grep and cut within the write_config function, bypassing the unreliable eval state. I also recommend using ssid2 with Hex encoding to make the SSID robust against any special characters.
Modified write_config section:
write_config() {
local interface="${1}"
local settings="/var/ipfire/wlanap/settings"
# Direct extraction to avoid $PWD collision and shell expansion issues
local LOCAL_SSID=$(grep "^SSID=" "${settings}" | cut -d'=' -f2- | sed 's/^"//;s/"$//;s/^\x27//;s/\x27$//')
local LOCAL_PASS=$(grep "^PWD=" "${settings}" | cut -d'=' -f2- | sed 's/^"//;s/"$//;s/^\x27//;s/\x27$//')
# ... (PHY detection logic) ...
# Fix for SSID (using hex encoding for safety)
printf "ssid2=%s\n" "$(echo -n "${LOCAL_SSID}" | xxd -p)"
echo "utf8_ssid=1"
# ... (other config) ...
# Fix for PSK assignment
case "${ENC}" in
wpa3|wpa2+3|wpa2|wpa1+2|wpa1)
echo "wpa_passphrase=${LOCAL_PASS}" ;;
esac
}
This approach ensures that the password and SSID are treated as literal strings, regardless of the characters they contain.