wpa_supplicant_add_interface() {
local ifname="$1"
local mode="$2"
- local hostapd_ctrl="$3"
local prev
_wpa_supplicant_common "$ifname"
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
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
}
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)}
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);
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 });
}
}
-
let main_obj = {
reload: {
args: {
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;
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);
}
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: "",
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);