import { open, readfile } from "fs";
import { wdev_create, wdev_remove, is_equal, vlist_new, phy_is_fullmac, phy_open } from "common";
-let ubus = libubus.connect();
+let ubus = libubus.connect(null, 60);
hostapd.data.config = {};
+hostapd.data.pending_config = {};
hostapd.data.file_fields = {
vlan_file: true,
return macaddr_list;
}
-function iface_update_supplicant_macaddr(phy, config)
+function __iface_pending_next(pending, state, ret, data)
{
- let macaddr_list = [];
- for (let i = 0; i < length(config.bss); i++)
- push(macaddr_list, config.bss[i].bssid);
- ubus.call("wpa_supplicant", "phy_set_macaddr_list", { phy: phy, macaddr: macaddr_list });
+ let config = pending.config;
+ let phydev = pending.phydev;
+ let phy = pending.phy;
+
+ if (pending.defer)
+ pending.defer.abort();
+ delete pending.defer;
+ switch (state) {
+ case "init":
+ let macaddr_list = [];
+ for (let i = 0; i < length(config.bss); i++)
+ push(macaddr_list, config.bss[i].bssid);
+ pending.call("wpa_supplicant", "phy_set_macaddr_list", { phy: phy, macaddr: macaddr_list });
+ return "create_bss";
+ case "create_bss":
+ let bss = config.bss[0];
+ let err = wdev_create(phy, bss.ifname, { mode: "ap" });
+ if (err) {
+ hostapd.printf(`Failed to create ${bss.ifname} on phy ${phy}: ${err}`);
+ return null;
+ }
+
+ pending.call("wpa_supplicant", "phy_status", { phy: phy });
+ return "check_phy";
+ case "check_phy":
+ let phy_status = data;
+ if (phy_status && phy_status.state == "COMPLETED") {
+ if (iface_add(phy, config, phy_status))
+ return "done";
+
+ hostapd.printf(`Failed to bring up phy ${phy} ifname=${bss.ifname} with supplicant provided frequency`);
+ }
+ pending.call("wpa_supplicant", "phy_set_state", { phy: phy, stop: true });
+ return "wpas_stopped";
+ case "wpas_stopped":
+ if (!iface_add(phy, config))
+ hostapd.printf(`hostapd.add_iface failed for phy ${phy} ifname=${bss.ifname}`);
+ pending.call("wpa_supplicant", "phy_set_state", { phy: phy, stop: false });
+ return null;
+ case "done":
+ default:
+ delete hostapd.data.pending_config[phy];
+ break;
+ }
+}
+
+function iface_pending_next(ret, data)
+{
+ let pending = true;
+ let cfg = this;
+
+ while (pending) {
+ this.next_state = __iface_pending_next(cfg, this.next_state, ret, data);
+ if (!this.next_state) {
+ __iface_pending_next(cfg, "done");
+ return;
+ }
+ pending = !this.defer;
+ }
+}
+
+function iface_pending_abort()
+{
+ this.next_state = "done";
+ this.next();
+}
+
+function iface_pending_ubus_call(obj, method, arg)
+{
+ let ubus = hostapd.data.ubus;
+ let pending = this;
+ this.defer = ubus.defer(obj, method, arg, (ret, data) => { delete pending.defer; pending.next(ret, data) });
+}
+
+const iface_pending_proto = {
+ next: iface_pending_next,
+ call: iface_pending_ubus_call,
+ abort: iface_pending_abort,
+};
+
+function iface_pending_init(phydev, config)
+{
+ let phy = phydev.name;
+
+ let pending = proto({
+ next_state: "init",
+ phydev: phydev,
+ phy: phy,
+ config: config,
+ next: iface_pending_next,
+ }, iface_pending_proto);
+
+ hostapd.data.pending_config[phy] = pending;
+ pending.next();
}
function iface_restart(phydev, config, old_config)
{
let phy = phydev.name;
+ let pending = hostapd.data.pending_config[phy];
+
+ if (pending)
+ pending.abort();
hostapd.remove_iface(phy);
iface_remove(old_config);
bss.bssid = phydev.macaddr_next();
}
- iface_update_supplicant_macaddr(phy, config);
-
- let bss = config.bss[0];
- let err = wdev_create(phy, bss.ifname, { mode: "ap" });
- if (err)
- hostapd.printf(`Failed to create ${bss.ifname} on phy ${phy}: ${err}`);
-
- 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 (!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 });
+ iface_pending_init(phydev, config);
}
function array_to_obj(arr, key, start)
if (is_equal(old_config.bss, config.bss))
return true;
+ if (hostapd.data.pending_config[phy])
+ return false;
+
if (!old_config.bss || !old_config.bss[0])
return false;