123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- let libubus = require("ubus");
- import { open, readfile } from "fs";
- import { wdev_create, wdev_set_mesh_params, wdev_remove, is_equal, wdev_set_up, vlist_new, phy_open } from "common";
- let ubus = libubus.connect();
- wpas.data.config = {};
- wpas.data.iface_phy = {};
- wpas.data.macaddr_list = {};
- function iface_stop(iface)
- {
- let ifname = iface.config.iface;
- if (!iface.running)
- return;
- delete wpas.data.iface_phy[ifname];
- wpas.remove_iface(ifname);
- wdev_remove(ifname);
- iface.running = false;
- }
- function iface_start(phydev, iface, macaddr_list)
- {
- let phy = phydev.name;
- if (iface.running)
- return;
- let ifname = iface.config.iface;
- let wdev_config = {};
- for (let field in iface.config)
- wdev_config[field] = iface.config[field];
- if (!wdev_config.macaddr)
- wdev_config.macaddr = phydev.macaddr_next();
- wpas.data.iface_phy[ifname] = phy;
- wdev_remove(ifname);
- let ret = wdev_create(phy, ifname, wdev_config);
- if (ret)
- wpas.printf(`Failed to create device ${ifname}: ${ret}`);
- wdev_set_up(ifname, true);
- wpas.add_iface(iface.config);
- iface.running = true;
- }
- function iface_cb(new_if, old_if)
- {
- if (old_if && new_if && is_equal(old_if.config, new_if.config)) {
- new_if.running = old_if.running;
- 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);
- }
- function prepare_config(config)
- {
- config.config_data = readfile(config.config);
- return { config: config };
- }
- function set_config(phy_name, config_list)
- {
- let phy = wpas.data.config[phy_name];
- if (!phy) {
- phy = vlist_new(iface_cb, false);
- wpas.data.config[phy_name] = phy;
- }
- let values = [];
- for (let config in config_list)
- push(values, [ config.iface, prepare_config(config) ]);
- phy.update(values);
- }
- function start_pending(phy_name)
- {
- let phy = wpas.data.config[phy_name];
- let ubus = wpas.data.ubus;
- if (!phy || !phy.data)
- return;
- let phydev = phy_open(phy_name);
- if (!phydev) {
- wpas.printf(`Could not open phy ${phy_name}`);
- return;
- }
- let macaddr_list = wpas.data.macaddr_list[phy_name];
- phydev.macaddr_init(macaddr_list);
- for (let ifname in phy.data)
- iface_start(phydev, phy.data[ifname]);
- }
- let main_obj = {
- phy_set_state: {
- args: {
- phy: "",
- stop: true,
- },
- call: function(req) {
- if (!req.args.phy || req.args.stop == null)
- return libubus.STATUS_INVALID_ARGUMENT;
- let phy = wpas.data.config[req.args.phy];
- if (!phy)
- return libubus.STATUS_NOT_FOUND;
- try {
- if (req.args.stop) {
- for (let ifname in phy.data)
- iface_stop(phy.data[ifname]);
- } else {
- start_pending(req.args.phy);
- }
- } catch (e) {
- wpas.printf(`Error chaging state: ${e}\n${e.stacktrace[0].context}`);
- return libubus.STATUS_INVALID_ARGUMENT;
- }
- return 0;
- }
- },
- phy_set_macaddr_list: {
- args: {
- phy: "",
- macaddr: [],
- },
- call: function(req) {
- let phy = req.args.phy;
- if (!phy)
- return libubus.STATUS_INVALID_ARGUMENT;
- wpas.data.macaddr_list[phy] = req.args.macaddr;
- 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: "",
- config: [],
- defer: true,
- },
- call: function(req) {
- 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);
- if (!req.args.defer)
- start_pending(req.args.phy);
- } catch (e) {
- wpas.printf(`Error loading config: ${e}\n${e.stacktrace[0].context}`);
- return libubus.STATUS_INVALID_ARGUMENT;
- }
- return {
- pid: wpas.getpid()
- };
- }
- },
- config_add: {
- args: {
- driver: "",
- iface: "",
- bridge: "",
- hostapd_ctrl: "",
- ctrl: "",
- config: "",
- },
- call: function(req) {
- if (!req.args.iface || !req.args.config)
- return libubus.STATUS_INVALID_ARGUMENT;
- if (wpas.add_iface(req.args) < 0)
- return libubus.STATUS_INVALID_ARGUMENT;
- return {
- pid: wpas.getpid()
- };
- }
- },
- config_remove: {
- args: {
- iface: ""
- },
- call: function(req) {
- if (!req.args.iface)
- return libubus.STATUS_INVALID_ARGUMENT;
- wpas.remove_iface(req.args.iface);
- return 0;
- }
- },
- };
- wpas.data.ubus = ubus;
- wpas.data.obj = ubus.publish("wpa_supplicant", main_obj);
- wpas.udebug_set("wpa_supplicant", wpas.data.ubus);
- function iface_event(type, name, data) {
- let ubus = wpas.data.ubus;
- data ??= {};
- data.name = name;
- wpas.data.obj.notify(`iface.${type}`, data, null, null, null, -1);
- ubus.call("service", "event", { type: `wpa_supplicant.${name}.${type}`, data: {} });
- }
- function iface_hostapd_notify(phy, ifname, iface, state)
- {
- let ubus = wpas.data.ubus;
- let status = iface.status();
- let msg = { phy: phy };
- switch (state) {
- case "DISCONNECTED":
- case "AUTHENTICATING":
- case "SCANNING":
- msg.up = false;
- break;
- case "INTERFACE_DISABLED":
- case "INACTIVE":
- msg.up = true;
- break;
- case "COMPLETED":
- msg.up = true;
- msg.frequency = status.frequency;
- msg.sec_chan_offset = status.sec_chan_offset;
- break;
- default:
- return;
- }
- ubus.call("hostapd", "apsta_state", msg);
- }
- function iface_channel_switch(phy, ifname, iface, info)
- {
- let msg = {
- phy: phy,
- up: true,
- csa: true,
- csa_count: info.csa_count ? info.csa_count - 1 : 0,
- frequency: info.frequency,
- sec_chan_offset: info.sec_chan_offset,
- };
- ubus.call("hostapd", "apsta_state", msg);
- }
- return {
- shutdown: function() {
- for (let phy in wpas.data.config)
- set_config(phy, []);
- wpas.ubus.disconnect();
- },
- iface_add: function(name, obj) {
- iface_event("add", name);
- },
- iface_remove: function(name, obj) {
- iface_event("remove", name);
- },
- state: function(ifname, iface, state) {
- let phy = wpas.data.iface_phy[ifname];
- if (!phy) {
- wpas.printf(`no PHY for ifname ${ifname}`);
- return;
- }
- iface_hostapd_notify(phy, ifname, iface, state);
- if (state != "COMPLETED")
- return;
- let phy_data = wpas.data.config[phy];
- if (!phy_data)
- return;
- let iface_data = phy_data.data[ifname];
- if (!iface_data)
- return;
- let wdev_config = iface_data.config;
- if (!wdev_config || wdev_config.mode != "mesh")
- return;
- wdev_set_mesh_params(ifname, wdev_config);
- },
- event: function(ifname, iface, ev, info) {
- let phy = wpas.data.iface_phy[ifname];
- if (!phy) {
- wpas.printf(`no PHY for ifname ${ifname}`);
- return;
- }
- if (ev == "CH_SWITCH_STARTED")
- iface_channel_switch(phy, ifname, iface, info);
- }
- };
|