#!/usr/bin/env ucode 'use strict'; import { vlist_new, is_equal, wdev_create, wdev_remove } from "/usr/share/hostap/common.uc"; import { readfile, writefile, basename, readlink, glob } from "fs"; let keep_devices = {}; let phy = shift(ARGV); let new_config = shift(ARGV); const mesh_params = [ "mesh_retry_timeout", "mesh_confirm_timeout", "mesh_holding_timeout", "mesh_max_peer_links", "mesh_max_retries", "mesh_ttl", "mesh_element_ttl", "mesh_hwmp_max_preq_retries", "mesh_path_refresh_time", "mesh_min_discovery_timeout", "mesh_hwmp_active_path_timeout", "mesh_hwmp_preq_min_interval", "mesh_hwmp_net_diameter_traversal_time", "mesh_hwmp_rootmode", "mesh_hwmp_rann_interval", "mesh_gate_announcements", "mesh_sync_offset_max_neighor", "mesh_rssi_threshold", "mesh_hwmp_active_path_to_root_timeout", "mesh_hwmp_root_interval", "mesh_hwmp_confirmation_interval", "mesh_awake_window", "mesh_plink_timeout", "mesh_auto_open_plinks", "mesh_fwding", "mesh_power_mode" ]; function iface_stop(wdev) { if (keep_devices[wdev.ifname]) return; wdev_remove(wdev.ifname); } function iface_start(wdev) { let ifname = wdev.ifname; if (readfile(`/sys/class/net/${ifname}/ifindex`)) { system([ "ip", "link", "set", "dev", ifname, "down" ]); wdev_remove(ifname); } wdev_create(phy, ifname, wdev); system([ "ip", "link", "set", "dev", ifname, "up" ]); if (wdev.freq) system(`iw dev ${ifname} set freq ${wdev.freq} ${wdev.htmode}`); if (wdev.mode == "adhoc") { let cmd = ["iw", "dev", ifname, "ibss", "join", wdev.ssid, wdev.freq, wdev.htmode, "fixed-freq" ]; if (wdev.bssid) push(cmd, wdev.bssid); for (let key in [ "beacon-interval", "basic-rates", "mcast-rate", "keys" ]) if (wdev[key]) push(cmd, key, wdev[key]); system(cmd); } else if (wdev.mode == "mesh") { let cmd = [ "iw", "dev", ifname, "mesh", "join", wdev.ssid, "freq", wdev.freq, wdev.htmode ]; for (let key in [ "mcast-rate", "beacon-interval" ]) if (wdev[key]) push(cmd, key, wdev[key]); system(cmd); cmd = ["iw", "dev", ifname, "set", "mesh_param" ]; let len = length(cmd); for (let param in mesh_params) if (wdev[param]) push(cmd, param, wdev[param]); if (len == length(cmd)) return; system(cmd); } } function iface_cb(new_if, old_if) { if (old_if && new_if && is_equal(old_if, new_if)) return; if (old_if) iface_stop(old_if); if (new_if) iface_start(new_if); } function drop_inactive(config) { for (let key in config) { if (!readfile(`/sys/class/net/${key}/ifindex`)) delete config[key]; } } function add_ifname(config) { for (let key in config) config[key].ifname = key; } function delete_ifname(config) { for (let key in config) delete config[key].ifname; } function add_existing(phy, config) { let wdevs = glob(`/sys/class/ieee80211/${phy}/device/net/*`); wdevs = map(wdevs, (arg) => basename(arg)); for (let wdev in wdevs) { if (config[wdev]) continue; if (basename(readlink(`/sys/class/net/${wdev}/phy80211`)) != phy) continue; if (trim(readfile(`/sys/class/net/${wdev}/operstate`)) == "down") config[wdev] = {}; } } let statefile = `/var/run/wdev-${phy}.json`; for (let dev in ARGV) keep_devices[dev] = true; if (!phy || !new_config) { warn(`Usage: ${basename(sourcepath())} [