2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2012 IPFire Network Development Team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
22 HOSTAPD_CONTROL_INTERFACE_DIR
="/run/hostapd/ctrl"
24 HOSTAPD_SUPPORTED_MODES
="802.11a 802.11a/n 802.11ac 802.11g 802.11g/n"
26 HOSTAPD_SUPPORTED_PAIRWISE_CIPHERS
=(
27 "GCMP-256" # Galois/counter mode protocol with 256 bit key
28 "CCMP-256" # AES in Counter mode with CBC-MAC with 256 bit key
29 "GCMP-128" # Galois/counter mode protocol with 128 bit key
30 "CCMP-128" # AES in Counter mode with CBC-MAC with 128 bit key
33 # This must be supported by all stations on the network and therefore
34 # can effectively only be CCMP
35 HOSTAPD_SUPPORTED_GROUP_CIPHERS
=(
39 hostapd_config_write
() {
46 # Shift the device and file argument.
50 if ! device_exists
"${device}"; then
51 error
"Cannot write hostapd configuration for non-existant device: ${device}"
55 # Get the phy for device
56 local phy
="$(device_get_phy "${device}")"
61 local channel_bandwidth
62 local country_code
="$(wireless_get_reg_domain)"
64 local environment
="${WIRELESS_DEFAULT_ENVIRONMENT}"
70 local wpa2_personal
="off"
71 local wpa3_personal
="off"
73 while [ $# -gt 0 ]; do
76 broadcast_ssid
=$
(cli_get_val
"${1}")
79 channel
=$
(cli_get_val
"${1}")
81 --channel-bandwidth=*)
82 channel_bandwidth
="$(cli_get_val "${1}")"
85 dfs
="$(cli_get_val "${1}")"
88 encryption
=$
(cli_get_val
"${1}")
91 environment
="$(cli_get_val "${1}")"
94 mfp
="$(cli_get_val "${1}")"
97 mode
=$
(cli_get_val
"${1}")
99 if ! isoneof mode
${HOSTAPD_SUPPORTED_MODES}; then
100 error
"Unsupported mode: ${mode}"
105 secret
="$(cli_get_val "${1}")"
108 ssid
=$
(cli_get_val
"${1}")
111 local val
="$(cli_get_val "${1}")"
119 wpa2_personal
="$(cli_get_bool "${1}")"
122 wpa3_personal
="$(cli_get_bool "${1}")"
125 warning_log
"Ignoring unknown argument '${1}'."
131 # Check if mode is set
132 if ! isset mode
; then
133 error
"Mode is not set"
137 assert isset broadcast_ssid
138 assert isbool broadcast_ssid
141 assert isinteger channel
146 # Check wireless environment
147 if ! wireless_environment_is_valid
"${environment}"; then
148 error
"Invalid wireless environment: ${environment}"
152 # With channel 0, ACS must be supported
153 if [ ${channel} -eq 0 ] && ! wireless_supports_acs
"${device}"; then
154 error
"ACS requested, but not supported by ${device}"
158 # Check channel bandwidth for validity
159 if isset channel_bandwidth
&& ! wireless_channel_bandwidth_is_valid
"${mode}" "${channel_bandwidth}"; then
160 error
"Invalid channel bandwidth for ${mode}: ${channel_bandwidth}"
164 # Management Frame Proection
165 if ! isbool mfp
; then
166 error
"Invalid value for --mfp: ${mfp}"
170 # Check if secret is set for personal authentication
171 if ! isset secret
&& (enabled WPA3_PERSONAL || enabled WPA2_PERSONAL
); then
172 error
"Secret not set but personal authentication enabled"
180 local vht_oper_chwidth
="0"
194 ht_caps
="$(wireless_get_ht_caps "${device}")"
206 ht_caps
="$(wireless_get_ht_caps "${device}")"
215 vht_caps
="$(wireless_get_vht_caps "${device}")"
218 ht_caps
="$(wireless_get_ht_caps "${device}")"
220 case "${channel_bandwidth}" in
237 # Get all supported pairwise ciphers
238 local pairwise_ciphers
=()
239 for cipher
in ${HOSTAPD_SUPPORTED_PAIRWISE_CIPHERS[*]}; do
240 if phy_supports_cipher
"${phy}" "${cipher}"; then
241 pairwise_ciphers
+=( "$(hostapd_cipher_name "${cipher}")" )
245 # Get all supported group ciphers
246 local group_ciphers
=()
247 for cipher
in ${HOSTAPD_SUPPORTED_GROUP_CIPHERS[*]}; do
248 if phy_supports_cipher
"${phy}" "${cipher}"; then
249 group_ciphers
+=( "$(hostapd_cipher_name "${cipher}")" )
253 # Create configuration directory.
254 local config_dir
=$
(dirname ${file})
255 mkdir
-p ${HOSTAPD_CONTROL_INTERFACE_DIR} ${config_dir} 2>/dev
/null
257 config_header
"hostapd" > ${file}
259 # Interface configuration
261 print
"# Interface configuration"
262 print
"driver=nl80211"
263 print
"interface=${device}"
267 # Wireless configuration
268 local ignore_broadcast_ssid
269 if enabled broadcast_ssid
; then
270 ignore_broadcast_ssid
="0"
272 ignore_broadcast_ssid
="1"
276 # Advertise country code and maximum transmission power
278 print
"country_code=${country_code}"
280 # Wireless Environment
281 case "${environment}" in
283 print
"country3=0x49"
287 print
"country3=0x4f"
290 print
"country3=0x20"
294 # Always advertise TPC
295 print
"local_pwr_constraint=3"
296 print
"spectrum_mgmt_required=1"
298 # Enable Radar Detection
299 if enabled dfs
&& wireless_supports_dfs
"${device}"; then
307 print
"# Wireless configuration"
308 print
"hw_mode=${hw_mode}"
310 if isset ieee80211ac
; then
311 print
"ieee80211ac=${ieee80211ac}"
314 if isset ieee80211n
; then
315 print
"ieee80211n=${ieee80211n}"
318 print
"channel=${channel}"
319 print
"ignore_broadcast_ssid=${ignore_broadcast_ssid}"
321 print
"ssid2=\"${ssid}\""
324 # Kick stations that are too far away
325 print
"disassoc_low_ack=1"
327 # WMM & WMM-PS Unscheduled Automatic Power Save Delivery
328 print
"wmm_enabled=${wmm}"
329 print
"uapsd_advertisement_enabled=1"
331 # Low Priority / AC_BK = Background
332 print
"wmm_ac_bk_cwmin=4"
333 print
"wmm_ac_bk_cwmax=10"
334 print
"wmm_ac_bk_aifs=7"
335 print
"wmm_ac_bk_txop_limit=0"
336 print
"wmm_ac_bk_acm=0"
337 print
"tx_queue_data3_aifs=7"
338 print
"tx_queue_data3_cwmin=15"
339 print
"tx_queue_data3_cwmax=1023"
340 print
"tx_queue_data3_burst=0"
342 # Normal Priority / AC_BE = Best Effort
343 print
"wmm_ac_be_aifs=3"
344 print
"wmm_ac_be_cwmin=4"
345 print
"wmm_ac_be_cwmax=10"
346 print
"wmm_ac_be_txop_limit=0"
347 print
"wmm_ac_be_acm=0"
348 print
"tx_queue_data2_aifs=3"
349 print
"tx_queue_data2_cwmin=15"
350 print
"tx_queue_data2_cwmax=63"
351 print
"tx_queue_data2_burst=0"
353 # High Priority / AC_VI = Video
354 print
"wmm_ac_vi_aifs=2"
355 print
"wmm_ac_vi_cwmin=3"
356 print
"wmm_ac_vi_cwmax=4"
357 print
"wmm_ac_vi_txop_limit=94"
358 print
"wmm_ac_vi_acm=0"
359 print
"tx_queue_data1_aifs=1"
360 print
"tx_queue_data1_cwmin=7"
361 print
"tx_queue_data1_cwmax=15"
362 print
"tx_queue_data1_burst=3.0"
364 # Highest Priority / AC_VO = Voice
365 print
"wmm_ac_vo_aifs=2"
366 print
"wmm_ac_vo_cwmin=2"
367 print
"wmm_ac_vo_cwmax=3"
368 print
"wmm_ac_vo_txop_limit=47"
369 print
"wmm_ac_vo_acm=0"
370 print
"tx_queue_data0_aifs=1"
371 print
"tx_queue_data0_cwmin=3"
372 print
"tx_queue_data0_cwmax=7"
373 print
"tx_queue_data0_burst=1.5"
376 if isset vht_caps
; then
377 print
"vht_capab=${vht_caps}"
381 print
"ht_capab=${ht_caps}"
384 print
"vht_oper_chwidth=${vht_oper_chwidth}"
388 # 802.11w - Management Frame Protection (MFP)
390 print
"ieee80211w=2" # required
398 print
"# Control interface"
399 print
"ctrl_interface=${HOSTAPD_CONTROL_INTERFACE_DIR}"
400 print
"ctrl_interface_group=0"
404 # Authentication Settings
409 local wpa_strict_rekey
410 local sae_require_mfp
413 if enabled WPA3_PERSONAL
; then
417 # Add WPA key management
418 list_append wpa_key_mgmt
"SAE"
419 sae_password
="${secret}"
427 if enabled WPA2_PERSONAL
; then
431 # Add WPA key management
432 list_append wpa_key_mgmt
"WPA-PSK-SHA256"
433 wpa_passphrase
="${secret}"
435 # Enable WPA strict rekey
439 # Enable RSN ciphers when RSN is enabled
442 if [ "${wpa}" = "2" ]; then
443 rsn_pairwise
="${pairwise_ciphers[*]}"
444 group_cipher
="${group_ciphers[*]}"
448 for var
in wpa wpa_key_mgmt wpa_passphrase sae_password \
449 rsn_pairwise group_cipher wpa_strict_rekeyi sae_require_mfp
; do
450 if [ -n "${!var}" ]; then
451 print
"${var}=${!var}"
455 # Log configuration file
456 file_to_log DEBUG
"${file}"
465 service_start
"hostapd@${device}.service"
468 if [ ${ret} -eq ${EXIT_OK} ]; then
469 log DEBUG
"hostapd has been successfully started on '${device}'"
471 log ERROR
"Could not start hostapd on '${device}': ${ret}"
482 service_stop
"hostapd@${device}.service"
485 hostapd_cipher_name
() {