diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh index db1ba231f3..3b88af4679 100644 --- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh +++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh @@ -889,7 +889,6 @@ wpa_supplicant_init_config() { wpa_supplicant_add_interface() { local ifname="$1" local mode="$2" - local hostapd_ctrl="$3" local prev _wpa_supplicant_common "$ifname" @@ -903,7 +902,6 @@ wpa_supplicant_add_interface() { json_add_string config "$_config" json_add_string macaddr "$macaddr" [ -n "$network_bridge" ] && json_add_string bridge "$network_bridge" - [ -n "$hostapd_ctrl" ] && json_add_string hostapd_ctrl "$hostapd_ctrl" [ -n "$wds" ] && json_add_boolean 4addr "$wds" json_add_boolean powersave "$powersave" [ "$mode" = "mesh" ] && mac80211_add_mesh_params @@ -978,7 +976,7 @@ mac80211_setup_supplicant() { wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan" fi - wpa_supplicant_add_interface "$ifname" "$mode" "$hostapd_ctrl" + wpa_supplicant_add_interface "$ifname" "$mode" return 0 } diff --git a/package/network/services/hostapd/files/hostapd.uc b/package/network/services/hostapd/files/hostapd.uc index f9f0c31bab..384c5c2eb0 100644 --- a/package/network/services/hostapd/files/hostapd.uc +++ b/package/network/services/hostapd/files/hostapd.uc @@ -31,7 +31,7 @@ function iface_remove(cfg) wdev_remove(bss.ifname); } -function iface_gen_config(phy, config) +function iface_gen_config(phy, config, start_disabled) { let str = `data: ${join("\n", config.radio.data)} @@ -45,12 +45,69 @@ channel=${config.radio.channel} str += ` ${type}=${bss.ifname} ${join("\n", bss.data)} +`; + if (start_disabled) + str += ` +start_disabled=1 `; } return str; } +function iface_freq_info(iface, config, params) +{ + let freq = params.frequency; + if (!freq) + return null; + + let sec_offset = params.sec_chan_offset; + if (sec_offset != -1 && sec_offset != 1) + sec_offset = 0; + + let width = 0; + for (let line in config.radio.data) { + if (!sec_offset && match(line, /^ht_capab=.*HT40/)) { + sec_offset = null; // auto-detect + continue; + } + + let val = match(line, /^(vht_oper_chwidth|he_oper_chwidth)=(\d+)/); + if (!val) + continue; + + val = int(val[2]); + if (val > width) + width = val; + } + + if (freq < 4000) + width = 0; + + return hostapd.freq_info(freq, sec_offset, width); +} + +function iface_add(phy, config, phy_status) +{ + let config_inline = iface_gen_config(phy, config, !!phy_status); + + let bss = config.bss[0]; + let ret = hostapd.add_iface(`bss_config=${bss.ifname}:${config_inline}`); + if (ret < 0) + return false; + + if (!phy_status) + return true; + + let iface = hostapd.interfaces[bss.ifname]; + if (!iface) + return false; + + let freq_info = iface_freq_info(iface, config, phy_status); + + return iface.start(freq_info) >= 0; +} + function iface_restart(phy, config, old_config) { iface_remove(old_config); @@ -65,11 +122,18 @@ function iface_restart(phy, config, old_config) let err = wdev_create(phy, bss.ifname, { mode: "ap" }); if (err) hostapd.printf(`Failed to create ${bss.ifname} on phy ${phy}: ${err}`); - let config_inline = iface_gen_config(phy, config); let ubus = hostapd.data.ubus; + let phy_status = ubus.call("wpa_supplicant", "phy_status", { phy: phy }); + if (phy_status && phy_status.state == "COMPLETED") { + if (iface_add(phy, config, phy_status)) + return; + + hostapd.printf(`Failed to bring up phy ${phy} ifname=${bss.ifname} with supplicant provided frequency`); + } + ubus.call("wpa_supplicant", "phy_set_state", { phy: phy, stop: true }); - if (hostapd.add_iface(`bss_config=${bss.ifname}:${config_inline}`) < 0) + if (!iface_add(phy, config)) hostapd.printf(`hostapd.add_iface failed for phy ${phy} ifname=${bss.ifname}`); ubus.call("wpa_supplicant", "phy_set_state", { phy: phy, stop: false }); } @@ -295,7 +359,6 @@ function iface_load_config(filename) } - let main_obj = { reload: { args: { @@ -344,34 +407,10 @@ let main_obj = { return 0; } - let freq = req.args.frequency; - if (!freq) + if (!req.args.frequency) return libubus.STATUS_INVALID_ARGUMENT; - let sec_offset = req.args.sec_chan_offset; - if (sec_offset != -1 && sec_offset != 1) - sec_offset = 0; - - let width = 0; - for (let line in config.radio.data) { - if (!sec_offset && match(line, /^ht_capab=.*HT40/)) { - sec_offset = null; // auto-detect - continue; - } - - let val = match(line, /^(vht_oper_chwidth|he_oper_chwidth)=(\d+)/); - if (!val) - continue; - - val = int(val[2]); - if (val > width) - width = val; - } - - if (freq < 4000) - width = 0; - - let freq_info = hostapd.freq_info(freq, sec_offset, width); + let freq_info = iface_freq_info(iface, config, req.args); if (!freq_info) return libubus.STATUS_UNKNOWN_ERROR; diff --git a/package/network/services/hostapd/files/wpa_supplicant.uc b/package/network/services/hostapd/files/wpa_supplicant.uc index 50da7f14ff..f8a3fcb525 100644 --- a/package/network/services/hostapd/files/wpa_supplicant.uc +++ b/package/network/services/hostapd/files/wpa_supplicant.uc @@ -43,6 +43,11 @@ function iface_cb(new_if, old_if) return; } + if (new_if && old_if) + wpas.printf(`Update configuration for interface ${old_if.config.iface}`); + else if (old_if) + wpas.printf(`Remove interface ${old_if.config.iface}`); + if (old_if) iface_stop(old_if); } @@ -106,6 +111,41 @@ let main_obj = { return 0; } }, + phy_status: { + args: { + phy: "" + }, + call: function(req) { + if (!req.args.phy) + return libubus.STATUS_INVALID_ARGUMENT; + + let phy = wpas.data.config[req.args.phy]; + if (!phy) + return libubus.STATUS_NOT_FOUND; + + for (let ifname in phy.data) { + try { + let iface = wpas.interfaces[ifname]; + if (!iface) + continue; + + let status = iface.status(); + if (!status) + continue; + + if (status.state == "INTERFACE_DISABLED") + continue; + + status.ifname = ifname; + return status; + } catch (e) { + continue; + } + } + + return libubus.STATUS_NOT_FOUND; + } + }, config_set: { args: { phy: "", @@ -116,6 +156,7 @@ let main_obj = { if (!req.args.phy) return libubus.STATUS_INVALID_ARGUMENT; + wpas.printf(`Set new config for phy ${req.args.phy}`); try { if (req.args.config) set_config(req.args.phy, req.args.config); diff --git a/package/network/services/hostapd/src/src/ap/ucode.c b/package/network/services/hostapd/src/src/ap/ucode.c index f0b4ce4eb8..0326f6fc82 100644 --- a/package/network/services/hostapd/src/src/ap/ucode.c +++ b/package/network/services/hostapd/src/src/ap/ucode.c @@ -362,6 +362,7 @@ out: int ret; hapd->started = 1; + hapd->conf->start_disabled = 0; hostapd_set_freq(hapd, conf->hw_mode, iface->freq, conf->channel, conf->enable_edmg,