diff --git a/include/meson.mk b/include/meson.mk index fdb94b65425ab3..62dc7bd5dec30b 100644 --- a/include/meson.mk +++ b/include/meson.mk @@ -55,8 +55,14 @@ else MESON_CPU:="$(CPU_TYPE)$(if $(CPU_SUBTYPE),+$(CPU_SUBTYPE))" endif +ifeq ($(MESON_USE_STAGING_PYTHON),) +PYTHON_BIN:=$(STAGING_DIR_HOST)/bin/$(PYTHON) +else +PYTHON_BIN:=$(STAGING_DIR_HOSTPKG)/bin/$(PYTHON) +endif + define Meson - $(2) $(STAGING_DIR_HOST)/bin/$(PYTHON) $(STAGING_DIR_HOST)/bin/meson.py $(1) + $(2) $(PYTHON_BIN) $(STAGING_DIR_HOST)/bin/meson.py $(1) endef define Meson/CreateNativeFile @@ -65,7 +71,7 @@ define Meson/CreateNativeFile -e "s|@CXX@|$(foreach BIN,$(HOSTCXX),'$(BIN)',)|" \ -e "s|@PKGCONFIG@|$(PKG_CONFIG)|" \ -e "s|@CMAKE@|$(STAGING_DIR_HOST)/bin/cmake|" \ - -e "s|@PYTHON@|$(STAGING_DIR_HOST)/bin/python3|" \ + -e "s|@PYTHON@|$(PYTHON_BIN)|" \ -e "s|@CFLAGS@|$(foreach FLAG,$(HOST_CFLAGS) $(HOST_CPPFLAGS),'$(FLAG)',)|" \ -e "s|@CXXFLAGS@|$(foreach FLAG,$(HOST_CXXFLAGS) $(HOST_CPPFLAGS),'$(FLAG)',)|" \ -e "s|@LDFLAGS@|$(foreach FLAG,$(HOST_LDFLAGS),'$(FLAG)',)|" \ @@ -84,7 +90,7 @@ define Meson/CreateCrossFile -e "s|@NM@|$(TARGET_NM)|" \ -e "s|@PKGCONFIG@|$(PKG_CONFIG)|" \ -e "s|@CMAKE@|$(STAGING_DIR_HOST)/bin/cmake|" \ - -e "s|@PYTHON@|$(STAGING_DIR_HOST)/bin/python3|" \ + -e "s|@PYTHON@|$(PYTHON_BIN)|" \ -e "s|@CFLAGS@|$(foreach FLAG,$(TARGET_CFLAGS) $(EXTRA_CFLAGS) $(TARGET_CPPFLAGS) $(EXTRA_CPPFLAGS),'$(FLAG)',)|" \ -e "s|@CXXFLAGS@|$(foreach FLAG,$(TARGET_CXXFLAGS) $(EXTRA_CXXFLAGS) $(TARGET_CPPFLAGS) $(EXTRA_CPPFLAGS),'$(FLAG)',)|" \ -e "s|@LDFLAGS@|$(foreach FLAG,$(TARGET_LDFLAGS) $(EXTRA_LDFLAGS),'$(FLAG)',)|" \ diff --git a/include/target.mk b/include/target.mk index 02ea68b15c8121..a4428efab710dd 100644 --- a/include/target.mk +++ b/include/target.mk @@ -375,6 +375,7 @@ define BuildTargets/DumpCurrent echo 'Target-Description:'; \ echo "$$$$DESCRIPTION"; \ echo '@@'; \ + $(if $(DEFAULT_PROFILE),echo 'Target-Default-Profile: $(DEFAULT_PROFILE)';) \ echo 'Default-Packages: $(DEFAULT_PACKAGES) $(call extra_packages,$(DEFAULT_PACKAGES))'; \ $(DUMPINFO) $(if $(CUR_SUBTARGET),$(SUBMAKE) -r --no-print-directory -C image -s DUMP=1 SUBTARGET=$(CUR_SUBTARGET)) diff --git a/include/toplevel.mk b/include/toplevel.mk index a52c56832eca03..092dff786c9922 100644 --- a/include/toplevel.mk +++ b/include/toplevel.mk @@ -75,22 +75,7 @@ endif _ignore = $(foreach p,$(IGNORE_PACKAGES),--ignore $(p)) -# Config that will invalidate the .targetinfo as they will affect -# DEFAULT_PACKAGES. -# Keep DYNAMIC_DEF_PKG_CONF in sync with target.mk to reflect the same configs -DYNAMIC_DEF_PKG_CONF := CONFIG_USE_APK CONFIG_SELINUX CONFIG_SMALL_FLASH CONFIG_USE_SECCOMP -check-dynamic-def-pkg: FORCE - @+DEF_PKG_CONFS=""; \ - if [ -f $(TOPDIR)/.config ]; then \ - for config in $(DYNAMIC_DEF_PKG_CONF); do \ - DEF_PKG_CONFS="$$DEF_PKG_CONFS "$$(grep "$$config"=y $(TOPDIR)/.config); \ - done; \ - fi; \ - [ ! -f tmp/.packagedynamicdefault ] || OLD_DEF_PKG_CONFS=$$(cat tmp/.packagedynamicdefault); \ - [ "$$DEF_PKG_CONFS" = "$$OLD_DEF_PKG_CONFS" ] || rm -rf tmp/info/.targetinfo*; \ - mkdir -p tmp && echo "$$DEF_PKG_CONFS" > tmp/.packagedynamicdefault; - -prepare-tmpinfo: check-dynamic-def-pkg FORCE +prepare-tmpinfo: FORCE @+$(MAKE) -r -s $(STAGING_DIR_HOST)/.prereq-build $(PREP_MK) mkdir -p tmp/info feeds [ -e $(TOPDIR)/feeds/base ] || ln -sf $(TOPDIR)/package $(TOPDIR)/feeds/base diff --git a/package/base-files/files/etc/init.d/led b/package/base-files/files/etc/init.d/led index 7f05254c2ba3a3..377b9dcf3ebce6 100755 --- a/package/base-files/files/etc/init.d/led +++ b/package/base-files/files/etc/init.d/led @@ -3,6 +3,10 @@ START=96 +extra_command "turnon" "Put the LEDs into their default state" +extra_command "turnoff" "Turn all LEDs off" +extra_command "blink" "Blink all LEDs" + led_color_set() { local cfg="$1" local sysfs="$2" @@ -168,7 +172,31 @@ load_led() { } } +turnoff() { + for led in `ls /sys/class/leds/`; do + echo 0 > /sys/class/leds/$led/brightness + done +} + +turnon() { + turnoff + . /etc/diag.sh + set_state done + start +} + +blink() { + for led in `ls /sys/class/leds/`; do + echo 0 > /sys/class/leds/$led/brightness + echo timer > /sys/class/leds/$led/trigger + done +} + start() { + [ "$(uci -q get system.@system[-1].leds_off)" = '1' ] && { + turnoff + exit 0 + } [ -e /sys/class/leds/ ] && { [ -s /var/run/led.state ] && { local led trigger brightness color diff --git a/package/base-files/files/etc/rc.button/reset b/package/base-files/files/etc/rc.button/reset index 2403122ad21d1a..84651334710dce 100755 --- a/package/base-files/files/etc/rc.button/reset +++ b/package/base-files/files/etc/rc.button/reset @@ -23,7 +23,7 @@ released) elif [ "$SEEN" -ge 5 -a -n "$OVERLAY" ] then echo "FACTORY RESET" > /dev/console - jffs2reset -y && reboot & + factoryreset -y && reboot & fi ;; esac diff --git a/package/base-files/files/sbin/firstboot b/package/base-files/files/sbin/firstboot index d9af57d59645bc..3dd6f1e7d24676 100755 --- a/package/base-files/files/sbin/firstboot +++ b/package/base-files/files/sbin/firstboot @@ -1,3 +1,3 @@ #!/bin/sh -/sbin/jffs2reset $@ +/sbin/factoryreset $@ diff --git a/package/boot/uboot-mediatek/patches/453-add-openwrt-one.patch b/package/boot/uboot-mediatek/patches/453-add-openwrt-one.patch index cf5f79f5841996..6c31d88be81825 100644 --- a/package/boot/uboot-mediatek/patches/453-add-openwrt-one.patch +++ b/package/boot/uboot-mediatek/patches/453-add-openwrt-one.patch @@ -469,7 +469,7 @@ +CONFIG_LMB_MAX_REGIONS=64 --- /dev/null +++ b/openwrt-one-nor_env -@@ -0,0 +1,47 @@ +@@ -0,0 +1,48 @@ +ethaddr_factory=mtd read factory 0x46000000 0x0 0x20000 && env readmem -b ethaddr 0x4600002a 0x6 ; setenv ethaddr_factory +bl2_mtd_write=mtd erase bl2-nor && mtd write bl2-nor $loadaddr 0x0 0x40000 +bl2_tftp_write=tftpboot $loadaddr $bootfile_bl2_nor && run bl2_mtd_write @@ -510,6 +510,7 @@ +serverip=192.168.11.23 +tftp_boot=run led_start ; tftpboot $loadaddr $bootfile && bootm $loadaddr#$bootconf +tftp_write=run led_start ; tftpboot $loadaddr $bootfile && mtd erase recovery 0x0 ${filesize} && mtd write recovery $loadaddr 0x0 ${filesize} ++usb_pgood_delay=4000 +usb_recovery=run led_start ; usb start && run usb_recovery_bl2 && run usb_recovery_ubi && run led_loop_done +usb_recovery_bl2=fatload usb 0:1 ${loadaddr} ${recoverfile_bl2} && run recovery_write_bl2 +usb_recovery_ubi=fatload usb 0:1 ${loadaddr} ${recoverfile_ubi} && run recovery_write_ubi @@ -519,7 +520,7 @@ +_bootmenu_update_title=setenv _bootmenu_update_title ; setenv bootmenu_title "$bootmenu_title $ver" --- /dev/null +++ b/openwrt-one-spi-nand_env -@@ -0,0 +1,60 @@ +@@ -0,0 +1,61 @@ +ethaddr_factory=mtd read factory 0x46000000 0x0 0x20000 && env readmem -b ethaddr 0x4600002a 0x6 ; setenv ethaddr_factory +ipaddr=192.168.11.11 +serverip=192.168.11.23 @@ -571,6 +572,7 @@ +ubi_read_production=ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs +ubi_read_recovery=ubi check recovery && ubi read $loadaddr recovery +ubi_remove_rootfs=ubi check rootfs_data && ubi remove rootfs_data ++usb_pgood_delay=4000 +usb_recover=run led_start ; usb start && run usb_recover_production && run led_loop_done +usb_recover_production=fatload usb 0:1 ${loadaddr} ${bootfile_upg} && iminfo $loadaddr && run ubi_write_production +ubi_write_fip=run ubi_remove_rootfs ; ubi check fip && ubi remove fip ; ubi create fip $filesize static && ubi write $loadaddr fip $filesize diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile index 22cd0e97b41770..1c848d1f57ebe1 100644 --- a/package/kernel/mac80211/Makefile +++ b/package/kernel/mac80211/Makefile @@ -100,7 +100,7 @@ PKG_CONFIG_DEPENDS += \ define KernelPackage/cfg80211 $(call KernelPackage/mac80211/Default) TITLE:=cfg80211 - wireless configuration API - DEPENDS+= +iw +iwinfo +wifi-scripts +wireless-regdb +USE_RFKILL:kmod-rfkill + DEPENDS+= +iw +!WIFI_SCRIPTS_UCODE:iwinfo +wifi-scripts +wireless-regdb +USE_RFKILL:kmod-rfkill ABI_VERSION:=$(PKG_VERSION)-$(PKG_RELEASE) FILES:= \ $(PKG_BUILD_DIR)/compat/compat.ko \ diff --git a/package/network/config/wifi-scripts/Config.in b/package/network/config/wifi-scripts/Config.in new file mode 100644 index 00000000000000..92e661246491e7 --- /dev/null +++ b/package/network/config/wifi-scripts/Config.in @@ -0,0 +1,3 @@ +config WIFI_SCRIPTS_UCODE + bool "Use new ucode based scripts" + default n diff --git a/package/network/config/wifi-scripts/Makefile b/package/network/config/wifi-scripts/Makefile index ae41f749498624..52edd1b56764da 100644 --- a/package/network/config/wifi-scripts/Makefile +++ b/package/network/config/wifi-scripts/Makefile @@ -13,17 +13,22 @@ PKG_RELEASE:=1 PKG_LICENSE:=GPL-2.0 PKG_MAINTAINER:=Felix Fietkau +PKG_CONFIG_DEPENDS:=CONFIG_WIFI_SCRIPTS_UCODE include $(INCLUDE_DIR)/package.mk define Package/wifi-scripts SECTION:=utils CATEGORY:=Base system - DEPENDS:=+netifd +ucode +ucode-mod-nl80211 +ucode-mod-rtnl +ucode-mod-ubus +ucode-mod-uci + DEPENDS:=+netifd +ucode +ucode-mod-nl80211 +ucode-mod-rtnl +ucode-mod-ubus +ucode-mod-uci +ucode-mod-digest TITLE:=Wi-Fi configuration scripts PKGARCH:=all endef +define Package/wifi-scripts/config + source "$(SOURCE)/Config.in" +endef + define Package/wifi-scripts/description A set of scripts that handle setup and configuration of Wi-Fi devices. endef @@ -40,6 +45,9 @@ endef define Package/wifi-scripts/install $(INSTALL_DIR) $(1) $(CP) ./files/* $(1)/ +ifeq ($(CONFIG_WIFI_SCRIPTS_UCODE),y) + $(CP) ./files-ucode/* $(1)/ +endif endef $(eval $(call BuildPackage,wifi-scripts)) diff --git a/package/network/config/wifi-scripts/files-ucode/lib/netifd/wireless/mac80211.sh b/package/network/config/wifi-scripts/files-ucode/lib/netifd/wireless/mac80211.sh new file mode 100755 index 00000000000000..fe364b8f48e689 --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/lib/netifd/wireless/mac80211.sh @@ -0,0 +1,347 @@ +#!/usr/bin/ucode + +'use strict'; + +import { set_default, log } from 'wifi.common'; +import { validate, dump_options } from 'wifi.validate'; +import * as supplicant from 'wifi.supplicant'; +import * as hostapd from 'wifi.hostapd'; +import * as netifd from 'wifi.netifd'; +import * as iface from 'wifi.iface'; +import * as fs from 'fs'; + +global.radio = ARGV[2]; + +const mesh_param_list = [ + "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 phy_suffix(radio, sep) { + if (radio == null || radio < 0) + return ""; + return sep + radio; +} + +function reset_config(phy, radio) { + let name = phy + phy_suffix(radio, "."); + let prev_config = `/var/run/hostapd-${name}.conf`; + + global.ubus.call('hostapd', 'config_set', { phy, radio, config: '', prev_config }); + global.ubus.call('wpa_supplicant', 'config_set', { phy, radio, config: []}); + + name = phy + phy_suffix(radio, ":"); + system(`ucode /usr/share/hostap/wdev.uc ${name} set_config '{}'`); +} + +function phy_filename(phy, name) { + return `/sys/class/ieee80211/${phy}/${name}`; +} + +function phy_file(phy, name) { + return fs.readfile(phy_filename(phy, name)); +} + +function phy_index(phy) { + return +phy_file(phy, "index"); +} + +function phy_path_match(phy, path) { + let phy_path = fs.realpath(phy_filename(phy, "device")); + return substr(phy_path, -length(path)) == path; +} + +function find_phy_by_path(phys, path) { + if (!path) + return null; + + path = split(path, "+"); + phys = filter(phys, (phy) => phy_path_match(phy, path[0])); + phys = sort(phys, (a, b) => phy_index(a) - phy_index(b)); + + return phys[+path[1]]; +} + +function find_phy_by_macaddr(phys, macaddr) { + macaddr = lc(macaddr); + return filter(phys, (phy) => phy_file(phy, "macaddr") == macaddr)[0]; +} + +function find_phy_by_name(phys, name) { + return index(phys, name) < 0 ? null : name; +} + +function find_phy(config) { + let phys = fs.lsdir("/sys/class/ieee80211"); + + return find_phy_by_path(phys, config.path) ?? + find_phy_by_macaddr(phys, config.macaddr) ?? + find_phy_by_name(phys, config.phy); +} + +function get_channel_frequency(band, channel) { + if (channel < 1) + return null; + + switch (band) { + case '2g': + if (channel == 14) + return 2484; + return 2407 + channel * 5; + case '5g': + if (channel >= 182 && channel <= 196) + return 4000 + channel * 5; + return 5000 + channel * 5; + case '6g': + if (channel == 2) + return 5935; + return 5950 + channel * 5; + case '60g': + return 56160 + channel * 2160; + } +} + +function setup_phy(phy, config, data) { + if (config.channel == "auto") + config.channel = 0; + config.channel = +config.channel; + config.frequency = get_channel_frequency(config.band, config.channel); + + if (config.country) { + log(`Setting country code to ${config.country}`); + system(`iw reg set ${config.country}`); + } + + set_default(config, 'rxantenna', 0xffffffff); + set_default(config, 'txantenna', 0xffffffff); + + if (config.txantenna == 'all') + config.txantenna = 0xffffffff; + if (config.rxantenna == 'all') + config.rxantenna = 0xffffffff; + + if (config.txantenna != data?.txantenna || config.rxantenna != data?.rxantenna) + reset_config(phy, config.radio); + + netifd.set_data({ + phy, + radio: config.radio, + txantenna: config.txantenna, + rxantenna: config.rxantenna + }); + + if (config.txpower) + config.txpower = 'fixed ' + config.txpower + '00'; + else + config.txpower = 'auto'; + + log(`Configuring '${phy}' txantenna: ${config.txantenna}, rxantenna: ${config.rxantenna} distance: ${config.distance}`); + system(`iw phy ${phy} set antenna ${config.txantenna} ${config.rxantenna}`); + system(`iw phy ${phy} set distance ${config.distance}`); + + if (config.frag) + system(`iw phy ${phy} set frag ${frag}`); + if (config.rts) + system(`iw phy ${phy} set rts ${rts}`); +} + +function iw_htmode(config) { + let suffix = substr(config.htmode, 3); + if (suffix == "40+" || suffix == "40-") + return "HT" + suffix; + + switch (config.htmode ?? "NONE") { + case "HT20": + case "VHT20": + case "HE20": + case "EHT20": + return "HT20"; + case "VHT80": + case "HE80": + case "EHT80": + case "HE160": + case "EHT160": + case "EHT320": + return "80MHZ"; + case "NONE": + case "NOHT": + return "NOHT"; + } + + if (substr(config.htmode, 2) == "40") { + switch (config.band) { + case "2g": + if (+config.channel < 7) + return "HT40+"; + else + return "HT40-"; + default: + return ((+config.channel / 4) % 2) ? "HT40+" : "HT40-"; + } + } + + return null; +} + +function config_add(config, name, val) { + if (val != null) + config[name] = val; +} + +function config_add_mesh_params(config, data) { + for (let param in mesh_param_list) + config_add(config, param, data[param]); +} + +function setup() { + let data = json(ARGV[3]); + + data.phy = find_phy(data.config); + if (!data.phy) { + log('Bug: PHY is undefined for device'); + netifd.set_retry(false); + return 1; + } + data.phy_suffix = phy_suffix(data.config.radio, ":"); + data.vif_phy_suffix = phy_suffix(data.config.radio, "."); + let active_ifnames = []; + + log('Starting'); + + validate('device', data.config); + setup_phy(data.phy, data.config, data.data); + + let supplicant_mesh; + let has_ap = false; + let idx = {}; + let supplicant_data = []; + let wdev_data = {}; + + for (let k, v in data.interfaces) { + let mode = v.config.mode; + idx[mode] ??= 0; + let mode_idx = idx[mode]++; + + if (!v.config.ifname) + v.config.ifname = data.phy + data.vif_phy_suffix + "-" + mode + mode_idx; + push(active_ifnames, v.config.ifname); + + if (v.config.encryption == 'owe' && v.config.owe_transition) { + mode_idx = idx[mode]++; + v.config.owe_transition_ifname = data.phy + data.vif_phy_suffix + "-" + mode + mode_idx; + push(active_ifnames, v.config.ifname); + } + + switch (mode) { + case 'ap': + has_ap = true; + // fallthrough + case 'sta': + case 'adhoc': + case 'mesh': + if (mode != "ap") + data.config.noscan = true; + validate('iface', v.config); + iface.prepare(v.config, data.phy + data.phy_suffix, data.config.num_global_macaddr); + netifd.set_vif(k, v.config.ifname); + break; + } + + switch (mode) { + case 'adhoc': + if (config.frequency && !v.config.wpa) + break; + // fallthrough + case 'mesh': + supplicant_mesh ??= !system("wpa_supplicant -vmesh"); + if (mode == "mesh" && !supplicant_mesh) + break; + // fallthrough + case 'sta': + let config = supplicant.generate(supplicant_data, data, v); + if (mode == "mesh") + config_add_mesh_params(config, v.config); + continue; + case 'monitor': + break; + default: + continue; + } + + // fallback to wdev setup + let config = { + mode, + ssid: v.config.ssid, + }; + + if (!v.config.default_macaddr) + config.macaddr = v.config.macaddr; + + config_add(config, "htmode", wdev_htmode(data.config)); + if (mode != "monitor") { + config_add(config, "basic-rates", supplicant.ratelist(data.config.basic_rate)); + config_add(config, "mcast-rate", supplicant.ratestr(v.config.mcast_rate)); + config_add(config, "beacon-interval", data.config.beacon_int); + if (mode == "mesh") { + config_add(config, "ssid", v.config.mesh_id); + config_add_mesh_params(config, v.config); + } + } + + wdev_data[v.config.ifname] = config; + } + + if (length(supplicant_data) > 0) + supplicant.setup(supplicant_data, data); + + if (has_ap) + hostapd.setup(data); + + system(`ucode /usr/share/hostap/wdev.uc ${data.phy}${data.phy_suffix} set_config '${printf("%J", wdev_data)}' ${join(' ', active_ifnames)}`); + + if (length(supplicant_data) > 0) + supplicant.start(data); + + netifd.set_up(); + + return 0 +} + +function teardown() { + let data = json(ARGV[3]); + + if (!data.data?.phy) { + log('Bug: PHY is undefined for device'); + return 1; + } + + log(`Tearing down ${data.data.phy}`); + + reset_config(data.data.phy, data.data.radio); + + return 0; +} + +let ret = 1; + +switch(ARGV[1]) { +case 'dump': + ret = dump_options(); + break; + +case 'setup': + ret = setup(); + break; + +case 'teardown': + ret = teardown(); + break; +} + +exit(ret); diff --git a/package/network/config/wifi-scripts/files-ucode/usr/bin/iwinfo b/package/network/config/wifi-scripts/files-ucode/usr/bin/iwinfo new file mode 100755 index 00000000000000..01285eb385d6de --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/bin/iwinfo @@ -0,0 +1,156 @@ +#!/usr/bin/ucode + +'use strict'; + +import * as iwinfo from 'iwinfo'; + +function print_assoclist(stations) { + for (let mac, station in stations) { + printf(`${station.mac} ${station.signal} dBm / ${station.noise} dBm (SNR ${station.snr}) ${station.inactive_time} ms ago\n`); + for (let k in [ 'rx', 'tx' ]) { + let bitrate = station[k]; + let flags = join(', ', bitrate.flags); + + printf(`\t${uc(k)}: ${bitrate.bitrate} MBit/s`); + if (length(bitrate.flags)) + printf(', %s', flags); + printf('%10d Pkts.\n', bitrate.packets); + } + printf(`\texpected throughput: ${station.expected_throughput}\n\n`); + } +} + +function print_countrylist(list) { + for (let k, v in list.countries) + printf(`${k == list.active ? '*' : ' '} ${k} "${v}"\n`); +} + +function print_freqlist(channels) { + for (let channel in channels) { + printf(`${channel.active ? '*' : ' '} ${channel.freq} GHz (Band: ${channel.band} GHz, Channel ${channel.channel})`); + if (length(channel.flags)) + printf(` [${join(', ', channel.flags)}]`); + printf('\n'); + } +} + +function print_htmodelist(htmode) { + printf('%s\n', join(' ', htmode)); +} + +function print_info(list) { + let padding = ' '; + + for (let bss in list) { + printf(`${bss.iface} ESSID: "${bss.ssid}"\n`); + printf(`${padding}Access Point: ${bss.mac}\n`); + printf(`${padding}Mode: ${bss.mode} Channel: ${bss.channel} (${bss.freq} GHz) HT Mode: ${bss.htmode}\n`); + printf(`${padding}Center Channel 1: ${bss.center_freq1} 2: ${bss.center_freq2}\n`); + printf(`${padding}Tx-Power: ${bss.txpower} dBm Link Quality: ${bss.quality}/70\n`); + printf(`${padding}Signal: ${bss.signal} Noise: ${bss.noise}\n`); + printf(`${padding}Bit Rate: ${bss.bitrate ?? 'unknown'} MBit/s\n`); + printf(`${padding}Encryption: ${bss.encryption}\n`); + printf(`${padding}Type: nl80211 HW Mode(s): 802.11${bss.hwmode}\n`); + printf(`${padding}Hardware: ${bss.hw_type} [${bss.hw_id}]\n`); + printf(`${padding}TX power offset: ${bss.power_offset}\n`); + printf(`${padding}Channel offset: ${bss.channel_offset}\n`); + printf(`${padding}Supports VAPs: ${bss.vaps} PHY name: ${bss.phy}\n`); + if (bss.owe_transition_ifname) + printf(`${padding}OWE partner: ${bss.owe_transition_ifname}\n`); + printf('\n'); + } + return 0; +} + +function print_scan(cells) { + let idx = 1; + + for (let cell in cells) { + printf('Cell %02d - Address: %s\n', idx++, cell.bssid); + printf('\t Mode: %s Frequency: %s GHz Band: %s GHz Channel: %d\n', cell.mode, cell.frequency, cell.band, cell.channel); + printf('\t Signal: %d dBm Quality: %2d/70\n', cell.dbm, cell.quality); + + if (!length(cell.crypto.key_mgmt)) + printf('\t Encryption: NONE\n'); + else + printf('\t Encryption: %s (%s)\n', join(' / ', cell.crypto.key_mgmt), join(' / ', cell.crypto.pair)); + + if (cell.ht) { + printf('\t HT Operation:\n'); + printf('\t\tPrimary Channel: %d\n', cell.ht.primary_channel); + printf('\t\tSecondary Channel Offset: %s\n', cell.ht.secondary_chan_off); + printf('\t\tChannel Width: %s\n', cell.ht.chan_width); + } + + if (cell.vht) { + printf('\t VHT Operation:\n'); + printf('\t\tCenter Frequency 1: %d\n', cell.vht.center_chan_1); + printf('\t\tCenter Frequency 2: %s\n', cell.vht.center_chan_2); + printf('\t\tChannel Width: %s\n', cell.vht.chan_width); + } + + printf('\n'); + } +} + +function print_txpowerlist(list) { + for (let power in list) + printf('%s %2d dbm (%4d mW)\n', power.active ? '*' : ' ', power.dbm, power.mw); +} + +let pretty = true; +if (ARGV[0] == '-j') { + pretty = false; + shift(ARGV); +} + +if (!length(ARGV)) { + let info = iwinfo.info(); + if (pretty) + print_info(info); + else + printf('%.J\n', info); + return 0; +} + +const commands = { + assoclist: [ iwinfo.assoclist, print_assoclist ], + countrylist: [ iwinfo.countrylist, print_countrylist ], + freqlist: [ iwinfo.freqlist, print_freqlist ], + htmodelist: [ iwinfo.htmodelist, print_htmodelist ], + info: [ iwinfo.info, print_info ], + scan: [ iwinfo.scan, print_scan ], + txpowerlist: [ iwinfo.txpowerlist, print_txpowerlist ], +}; + +if (length(ARGV) == 2 && iwinfo.ifaces[ARGV[0]]) + for (let cmd, cb in commands) + if (substr(cmd, 0, length(ARGV[1])) == ARGV[1]) { + let ret = cb[0](ARGV[0]); + + if (pretty) + cb[1](ret); + else + printf('%.J\n', ret); + return 0; + } + +switch(ARGV[0]) { +case 'phy': + printf('%.J\n', iwinfo.phys); + return 0; + +case 'iface': + printf('%.J\n', iwinfo.ifaces); + return 0; +} + +printf('Usage:\n' + + '\tiwinfo info\n' + + '\tiwinfo scan\n' + + '\tiwinfo txpowerlist\n' + + '\tiwinfo freqlist\n' + + '\tiwinfo assoclist\n' + + '\tiwinfo countrylist\n' + + '\tiwinfo htmodelist\n' + + '\tiwinfo phyname
\n'); diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/iso3166.json b/package/network/config/wifi-scripts/files-ucode/usr/share/iso3166.json new file mode 100644 index 00000000000000..ecd0b653839855 --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/iso3166.json @@ -0,0 +1,249 @@ +{ + "00": "World", + "AD": "Andorra", + "AE": "United Arab Emirates", + "AF": "Afghanistan", + "AG": "Antigua and Barbuda", + "AI": "Anguilla", + "AL": "Albania", + "AM": "Armenia", + "AN": "Netherlands Antilles", + "AO": "Angola", + "AQ": "Antarctica", + "AR": "Argentina", + "AS": "American Samoa", + "AT": "Austria", + "AU": "Australia", + "AW": "Aruba", + "AX": "Aland Islands", + "AZ": "Azerbaijan", + "BA": "Bosnia and Herzegovina", + "BB": "Barbados", + "BD": "Bangladesh", + "BE": "Belgium", + "BF": "Burkina Faso", + "BG": "Bulgaria", + "BH": "Bahrain", + "BI": "Burundi", + "BJ": "Benin", + "BL": "Saint Barthelemy", + "BM": "Bermuda", + "BN": "Brunei Darussalam", + "BO": "Bolivia", + "BR": "Brazil", + "BS": "Bahamas", + "BT": "Bhutan", + "BV": "Bouvet Island", + "BW": "Botswana", + "BY": "Belarus", + "BZ": "Belize", + "CA": "Canada", + "CC": "Cocos (Keeling) Islands", + "CD": "Congo", + "CF": "Central African Republic", + "CG": "Congo", + "CH": "Switzerland", + "CI": "Cote d'Ivoire", + "CK": "Cook Islands", + "CL": "Chile", + "CM": "Cameroon", + "CN": "China", + "CO": "Colombia", + "CR": "Costa Rica", + "CU": "Cuba", + "CV": "Cape Verde", + "CX": "Christmas Island", + "CY": "Cyprus", + "CZ": "Czech Republic", + "DE": "Germany", + "DJ": "Djibouti", + "DK": "Denmark", + "DM": "Dominica", + "DO": "Dominican Republic", + "DZ": "Algeria", + "EC": "Ecuador", + "EE": "Estonia", + "EG": "Egypt", + "EH": "Western Sahara", + "ER": "Eritrea", + "ES": "Spain", + "ET": "Ethiopia", + "FI": "Finland", + "FJ": "Fiji", + "FK": "Falkland Islands", + "FM": "Micronesia", + "FO": "Faroe Islands", + "FR": "France", + "GA": "Gabon", + "GB": "United Kingdom", + "GD": "Grenada", + "GE": "Georgia", + "GF": "French Guiana", + "GG": "Guernsey", + "GH": "Ghana", + "GI": "Gibraltar", + "GL": "Greenland", + "GM": "Gambia", + "GN": "Guinea", + "GP": "Guadeloupe", + "GQ": "Equatorial Guinea", + "GR": "Greece", + "GS": "South Georgia", + "GT": "Guatemala", + "GU": "Guam", + "GW": "Guinea-Bissau", + "GY": "Guyana", + "HK": "Hong Kong", + "HM": "Heard and McDonald Islands", + "HN": "Honduras", + "HR": "Croatia", + "HT": "Haiti", + "HU": "Hungary", + "ID": "Indonesia", + "IE": "Ireland", + "IL": "Israel", + "IM": "Isle of Man", + "IN": "India", + "IO": "Chagos Islands", + "IQ": "Iraq", + "IR": "Iran", + "IS": "Iceland", + "IT": "Italy", + "JE": "Jersey", + "JM": "Jamaica", + "JO": "Jordan", + "JP": "Japan", + "KE": "Kenya", + "KG": "Kyrgyzstan", + "KH": "Cambodia", + "KI": "Kiribati", + "KM": "Comoros", + "KN": "Saint Kitts and Nevis", + "KP": "North Korea", + "KR": "South Korea", + "KW": "Kuwait", + "KY": "Cayman Islands", + "KZ": "Kazakhstan", + "LA": "Laos", + "LB": "Lebanon", + "LC": "Saint Lucia", + "LI": "Liechtenstein", + "LK": "Sri Lanka", + "LR": "Liberia", + "LS": "Lesotho", + "LT": "Lithuania", + "LU": "Luxembourg", + "LV": "Latvia", + "LY": "Libyan Arab Jamahiriya", + "MA": "Morocco", + "MC": "Monaco", + "MD": "Moldova", + "ME": "Montenegro", + "MF": "Saint Martin (French part)", + "MG": "Madagascar", + "MH": "Marshall Islands", + "MK": "Macedonia", + "ML": "Mali", + "MM": "Myanmar", + "MN": "Mongolia", + "MO": "Macao", + "MP": "Northern Mariana Islands", + "MQ": "Martinique", + "MR": "Mauritania", + "MS": "Montserrat", + "MT": "Malta", + "MU": "Mauritius", + "MV": "Maldives", + "MW": "Malawi", + "MX": "Mexico", + "MY": "Malaysia", + "MZ": "Mozambique", + "NA": "Namibia", + "NC": "New Caledonia", + "NE": "Niger", + "NF": "Norfolk Island", + "NG": "Nigeria", + "NI": "Nicaragua", + "NL": "Netherlands", + "NO": "Norway", + "NP": "Nepal", + "NR": "Nauru", + "NU": "Niue", + "NZ": "New Zealand", + "OM": "Oman", + "PA": "Panama", + "PE": "Peru", + "PF": "French Polynesia", + "PG": "Papua New Guinea", + "PH": "Philippines", + "PK": "Pakistan", + "PL": "Poland", + "PM": "Saint Pierre and Miquelon", + "PN": "Pitcairn", + "PR": "Puerto Rico", + "PS": "Palestinian Territory", + "PT": "Portugal", + "PW": "Palau", + "PY": "Paraguay", + "QA": "Qatar", + "RE": "Reunion", + "RO": "Romania", + "RS": "Serbia", + "RU": "Russian Federation", + "RW": "Rwanda", + "SA": "Saudi Arabia", + "SB": "Solomon Islands", + "SC": "Seychelles", + "SD": "Sudan", + "SE": "Sweden", + "SG": "Singapore", + "SH": "St. Helena and Dependencies", + "SI": "Slovenia", + "SJ": "Svalbard and Jan Mayen", + "SK": "Slovakia", + "SL": "Sierra Leone", + "SM": "San Marino", + "SN": "Senegal", + "SO": "Somalia", + "SR": "Suriname", + "ST": "Sao Tome and Principe", + "SV": "El Salvador", + "SY": "Syrian Arab Republic", + "SZ": "Swaziland", + "TC": "Turks and Caicos Islands", + "TD": "Chad", + "TF": "French Southern Territories", + "TG": "Togo", + "TH": "Thailand", + "TJ": "Tajikistan", + "TK": "Tokelau", + "TL": "Timor-Leste", + "TM": "Turkmenistan", + "TN": "Tunisia", + "TO": "Tonga", + "TR": "Turkey", + "TT": "Trinidad and Tobago", + "TV": "Tuvalu", + "TW": "Taiwan", + "TZ": "Tanzania", + "UA": "Ukraine", + "UG": "Uganda", + "UM": "U.S. Minor Outlying Islands", + "US": "United States", + "UY": "Uruguay", + "UZ": "Uzbekistan", + "VA": "Vatican City State", + "VC": "St. Vincent and Grenadines", + "VE": "Venezuela", + "VG": "Virgin Islands, British", + "VI": "Virgin Islands, U.S.", + "VN": "Viet Nam", + "VU": "Vanuatu", + "WF": "Wallis and Futuna", + "WS": "Samoa", + "YE": "Yemen", + "YT": "Mayotte", + "ZA": "South Africa", + "ZM": "Zambia", + "ZW": "Zimbabwe" +} diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/schema/wireless.wifi-device.json b/package/network/config/wifi-scripts/files-ucode/usr/share/schema/wireless.wifi-device.json new file mode 100644 index 00000000000000..9a7e777b633a83 --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/schema/wireless.wifi-device.json @@ -0,0 +1,717 @@ +{ + "$id": "https://openwrt.org/wifi.device.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "OpenWrt WiFi Device Schema", + "type": "object", + "properties": { + "acs_chan_bias": { + "description": "Can be used to increase (or decrease) the likelihood of a specific channel to be selected by the ACS algorithm", + "type": "string" + }, + "acs_exclude_dfs": { + "description": "Exclude DFS channels from ACS", + "type": "boolean", + "default": false + }, + "airtime_mode": { + "description": "Set the airtime policy operating mode", + "type": "number", + "default": 0, + "minimum": 0, + "maximum": 3 + }, + "antenna_gain": { + "description": "Reduction in antenna gain from regulatory maximum in dBi", + "type": "number", + "default": 0 + }, + "assoc_sa_query_max_timeout": { + "description": "Association SA Query maximum timeout", + "type": "number" + }, + "assoc_sa_query_retry_timeout": { + "description": "Association SA Query retry timeout", + "type": "number" + }, + "auth_cache": { + "type": "alias", + "default": "okc" + }, + "background_radar": { + "type": "alias", + "default": "enable_background_radar" + }, + "band": { + "description": "The wireless band thatthe radio shall operate on", + "type": "string", + "enum": [ + "2g", + "5g", + "6g", + "60g" + ] + }, + "basic_rate": { + "type": "alias", + "default": "basic_rates" + }, + "basic_rates": { + "description": "Set the supported basic rates. Each basic_rate is measured in kb/s. This option only has an effect on ap and adhoc wifi-ifaces. ", + "type": "array", + "items": { + "type": "number" + } + }, + "beacon_int": { + "description": "Set the beacon interval. This is the time interval between beacon frames, measured in units of 1.024 ms. hostapd permits this to be set between 15 and 65535. This option only has an effect on ap and adhoc wifi-ifaces", + "type": "number", + "default": 100, + "minimum": 15, + "maximum": 65535 + }, + "beacon_rate": { + "description": "Beacon frame TX rate configuration", + "type": "string" + }, + "beamformee_antennas": { + "description": "Beamformee antenna override", + "type": "number", + "default": 4 + }, + "beamformer_antennas": { + "description": "Beamformer antenna override", + "type": "number", + "default": 4 + }, + "bssid": { + "description": "Overrides the MAC address used for the Wi-Fi interface. Warning: if the MAC address specified is a multicast address, this override will fail silently. To avoid this problem, ensure that the mac address specified is a valid unicast mac address", + "type": "string" + }, + "cell_density": { + "description": "Configures data rates based on the coverage cell density. Normal configures basic rates to 6, 12, 24 Mbps if legacy_rates is 0, else to 5.5, 11 Mbps. High configures basic rates to 12, 24 Mbps if legacy_rates is 0, else to the 11 Mbps rate. Very High configures 24 Mbps as the basic rate. Supported rates lower than the minimum basic rate are not offered. The basic_rate and supported_rates options overrides this option. 0 = Disabled, 1 = Normal, 2 = High, 3 = Very High", + "type": "number", + "default": 0, + "minimum": 0, + "maximum": 3 + }, + "chanbw": { + "description": "Specifies a narrow channel width in MHz, possible values are: 5, 10, 20", + "type": "number", + "enum": [ 5, 10, 20 ] + }, + "channel": { + "description": "Specifies the wireless channel. “auto” defaults to the lowest available channel, or utilizes the ACS algorithm depending on hardware/driver support", + "type": "string" + }, + "channels": { + "type": "alias", + "default": "chanlist" + }, + "channel_list": { + "type": "alias", + "default": "chanlist" + }, + "chanlist": { + "description": "Use specific channels, when channel is in “auto” mode. This option allows hostapd to select one of the provided channels when a channel should be automatically selected. Channels can be provided as range using hyphen ('-') or individual channels can be specified by space (' ') separated values", + "type": "array", + "items": { + "type": "number" + } + }, + "country": { + "type": "alias", + "default": "country_code" + }, + "country3": { + "description": "The third octet of the Country String (dot11CountryString)", + "type": "string" + }, + "country_code": { + "description": "Specifies the country code, affects the available channels and transmission powers. For types mac80211 and broadcom a two letter country code is used (EN or DE). The madwifi driver expects a numeric code", + "type": "string" + }, + "country_ie": { + "type": "alias", + "default": "ieee80211d" + }, + "disabled": { + "description": "When set to 1, wireless network is disabled", + "type": "boolean", + "default": false + }, + "distance": { + "description": "Distance between the ap and the furthest client in meters", + "type": "number", + "default": 0 + }, + "doth": { + "type": "alias", + "default": "ieee80211h" + }, + "dsss_cck_40": { + "description": "DSSS/CCK Mode in 40 MHz allowed in Beacon, Measurement Pilot and Probe Response frames", + "type": "boolean", + "default": true + }, + "enable_background_radar": { + "description": "This feature allows CAC to be run on dedicated radio RF chains", + "type": "boolean" + }, + "frag": { + "description": "Fragmentation threshold", + "type": "number" + }, + "greenfield": { + "description": "Receive Greenfield - treats pre-80211n traffic as noise", + "type": "boolean", + "default": false + }, + "he_bss_color": { + "description": "BSS color to be announced", + "type": "number", + "minimum": 1, + "maximum": 128, + "default": 128 + }, + "he_bss_color_enabled": { + "description": "Enable BSS color", + "type": "boolean", + "default": true + }, + "he_default_pe_duration": { + "description": "The duration of PE field in an HE PPDU in us", + "type": "number", + "default": 4, + "enum": [ 4, 8, 12, 16 ] + }, + "he_mu_beamformer": { + "description": "HE multiple user beamformer support", + "type": "boolean", + "default": true + }, + "he_mu_edca_ac_be_aci": { + "type": "number", + "default": 0 + }, + "he_mu_edca_ac_be_aifsn": { + "type": "number", + "default": 8 + }, + "he_mu_edca_ac_be_ecwmax": { + "type": "number", + "default": 10 + }, + "he_mu_edca_ac_be_ecwmin": { + "type": "number", + "default": 9 + }, + "he_mu_edca_ac_be_timer": { + "type": "number", + "default": 255 + }, + "he_mu_edca_ac_bk_aci": { + "type": "number", + "default": 1 + }, + "he_mu_edca_ac_bk_aifsn": { + "type": "number", + "default": 15 + }, + "he_mu_edca_ac_bk_ecwmax": { + "type": "number", + "default": 10 + }, + "he_mu_edca_ac_bk_ecwmin": { + "type": "number", + "default": 9 + }, + "he_mu_edca_ac_bk_timer": { + "type": "number", + "default": 255 + }, + "he_mu_edca_ac_vi_aci": { + "type": "number", + "default": 2 + }, + "he_mu_edca_ac_vi_aifsn": { + "type": "number", + "default": 5 + }, + "he_mu_edca_ac_vi_ecwmax": { + "type": "number", + "default": 7 + }, + "he_mu_edca_ac_vi_ecwmin": { + "type": "number", + "default": 5 + }, + "he_mu_edca_ac_vi_timer": { + "type": "number", + "default": 255 + }, + "he_mu_edca_ac_vo_aci": { + "type": "number", + "default": 3 + }, + "he_mu_edca_ac_vo_aifsn": { + "type": "number", + "default": 5 + }, + "he_mu_edca_ac_vo_ecwmax": { + "type": "number", + "default": 7 + }, + "he_mu_edca_ac_vo_ecwmin": { + "type": "number", + "default": 5 + }, + "he_mu_edca_ac_vo_timer": { + "type": "number", + "default": 255 + }, + "he_mu_edca_qos_info_param_count": { + "type": "number", + "default": 0 + }, + "he_mu_edca_qos_info_q_ack": { + "type": "number", + "default": 0 + }, + "he_mu_edca_qos_info_queue_request": { + "type": "number", + "default": 0 + }, + "he_mu_edca_qos_info_txop_request": { + "type": "number", + "default": 0 + }, + "he_oper_centr_freq_seg0_idx": { + "description": "", + "type": "string" + }, + "he_oper_chwidth": { + "description": "", + "type": "string" + }, + "he_6ghz_reg_pwr_type": { + "description": "This config is to set the 6 GHz Access Point type.", + "type": "number", + "minimum": 0, + "maximum": 4, + "default": 0 + }, + "he_rts_threshold": { + "description": "Duration of STA transmission", + "type": "number", + "default": 1023 + }, + "he_spr_non_srg_obss_pd_max_offset": { + "description": "", + "type": "number" + }, + "he_spr_psr_enabled": { + "description": "", + "type": "boolean", + "default": false + }, + "he_spr_sr_control": { + "description": "", + "type": "number", + "default": 3 + }, + "he_su_beamformee": { + "description": "", + "type": "boolean", + "default": true + }, + "he_su_beamformer": { + "description": "", + "type": "boolean", + "default": true + }, + "he_twt_required": { + "description": "", + "type": "boolean", + "default": false + }, + "hostapd_options": { + "type": "array", + "items": { + "type": "string" + } + }, + "ht_coex": { + "description": "Disable honoring 40 MHz intolerance in coexistence flags of stations", + "type": "boolean", + "default": false + }, + "htc_vht": { + "description": "STA supports receiving a VHT variant HT Control field", + "type": "boolean", + "default": true + }, + "htmode": { + "description": "Specifies the high throughput mode", + "type": "string", + "enum": [ + "NOHT", "HT20", "HT40-", "HT40+", "HT40", + "VHT20", "VHT40", "VHT80", "VHT160", + "HE20", "HE40", "HE80", "HE160", + "EHT20", "EHT40", "EHT80", "EHT160", "EHT320" ] + }, + "hwmode": { + "type": "alias", + "default": "hw_mode" + }, + "hw_mode": { + "description": "Legacy way, use the band property instead", + "type": "string", + "enum": [ "11a", "11b", "11g", "11ad" ] + }, + "ieee80211d": { + "description": "Enables IEEE 802.11d country IE (information element) advertisement in beacon and probe response frames. This IE contains the country code and channel/power map. Requires country", + "type": "boolean", + "default": true + }, + "ieee80211h": { + "description": "This enables radar detection and DFS support", + "type": "boolean", + "default": true + }, + "ieee80211w": { + "description": "Whether management frame protection (MFP) is enabled", + "type": "number", + "minimum": 0, + "maximum": 2 + }, + "ieee80211w_max_timeout": { + "type": "alias", + "default": "assoc_sa_query_max_timeout" + }, + "ieee80211w_mgmt_cipher": { + "description": "Cypher used for MFP", + "type": "string" + }, + "ieee80211w_retry_timeout": { + "type": "alias", + "default": "assoc_sa_query_retry_timeout" + }, + "iface_max_num_sta": { + "description": "Limits the maximum allowed number of associated clients", + "type": "number" + }, + "ldpc": { + "description": " LDPC (Low-Density Parity-Check code) capability ", + "type": "boolean", + "default": true + }, + "legacy_rates": { + "description": "Allow legacy 802.11b data rates (used by cell_density)", + "type": "boolean", + "default": false + }, + "local_pwr_constraint": { + "description": "Add Power Constraint element to Beacon and Probe Response frame", + "type": "number", + "minimum": 0, + "maximum": 255 + }, + "log_80211": { + "description": "Enable IEEE 802.11 logging", + "type": "boolean", + "default": true + }, + "log_8021x": { + "description": "Enable IEEE 802.1X logging", + "type": "boolean", + "default": true + }, + "log_driver": { + "description": "Enable driver interface logging", + "type": "boolean", + "default": true + }, + "log_iapp": { + "description": "Enable iapp logging", + "type": "boolean", + "default": true + }, + "log_level": { + "description": "Log severity", + "type": "number", + "default": 2, + "minimum": 0, + "maximum": 4 + }, + "log_mlme": { + "description": "Enable MLME logging", + "type": "boolean", + "default": true + }, + "log_radius": { + "description": "Enable Radius logging", + "type": "boolean", + "default": true + }, + "log_wpa": { + "description": "Enable WPA logging", + "type": "boolean", + "default": true + }, + "logger_stdout": { + "description": "Log to stdout", + "type": "boolean", + "default": true + }, + "logger_stdout_level": { + "description": "Log severity", + "type": "number", + "default": 2, + "minimum": 0, + "maximum": 4 + }, + "logger_syslog": { + "description": "Log to syslog", + "type": "boolean", + "default": true + }, + "logger_syslog_level": { + "description": "Syslog severity", + "type": "number", + "default": 2, + "minimum": 0, + "maximum": 4 + }, + "macaddr": { + "type": "alias", + "default": "bssid" + }, + "max_amsdu": { + "description": "Maximum A-MSDU length of 7935 octects (3839 octets if option set to 0)", + "type": "boolean", + "default": true + }, + "maxassoc": { + "type": "alias", + "default": "iface_max_num_sta" + }, + "mbssid": { + "description": "Multiple BSSID Advertisement in IEEE 802.11ax IEEE Std 802.11ax-2021 added a feature where instead of multiple interfaces on a common radio transmitting individual Beacon frames, those interfaces can form a set with a common Beacon frame transmitted for all Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection", + "type": "number", + "default": 0, + "minimum": 0, + "maximum": 2 + }, + "min_tx_power": { + "description": "Set minimum permitted max TX power (in dBm) for ACS and DFS channel selection", + "type": "number", + "default": 0 + }, + "mu_beamformee": { + "description": "Supports operation as an MU beamformee", + "type": "boolean", + "default": true + }, + "mu_beamformer": { + "description": " Supports operation as an MU beamformer", + "type": "boolean", + "default": true + }, + "multiple_bssid": { + "type": "alias", + "default": "mbssid" + }, + "num_global_macaddr": { + "description": "The number of MACs that this radio can use", + "type": "number", + "default": 1 + }, + "no_probe_resp_if_max_sta": { + "description": "Do not answer probe requests if iface_max_num_sta was reached", + "type": "boolean" + }, + "noscan": { + "description": "Do not scan for overlapping BSSs in HT40+/- mode.", + "type": "boolean", + "default": false + }, + "okc": { + "description": "Enable Opportunistic Key Caching", + "type": "boolean" + }, + "path": { + "description": "Alternative to phy used to identify the device based paths in /sys/devices", + "type": "string" + }, + "radio": { + "description": "Index of the phy radio (for multi-radio PHYs)", + "type": "number", + "default": -1 + }, + "reg_power_type": { + "type": "alias", + "default": "he_6ghz_reg_pwr_type" + }, + "require_mode": { + "description": "Sets the minimum client capability level mode that connecting clients must support to be allowed to connect", + "type": "string", + "enum": [ "ht", "ac", "ax" ] + }, + "rnr_beacon": { + "description": "", + "type": "string" + }, + "rsn_preauth": { + "description": "Enable IEEE 802.11i/RSN/WPA2 pre-authentication", + "type": "boolean" + }, + "rssi_ignore_probe_request": { + "description": "Ignore Probe Request frames if RSSI is below given threshold (in dBm)", + "type": "number", + "default": 0 + }, + "rssi_reject_assoc_rssi": { + "description": "Reject STA association if RSSI is below given threshold (in dBm)", + "type": "number", + "default": 0 + }, + "rts": { + "description": "Override the RTS/CTS threshold", + "type": "number" + }, + "rts_threshold": { + "description": "RTS/CTS threshold", + "type": "number", + "minimum": -1, + "maximum": 65535 + }, + "rx_antenna_pattern": { + "description": "Rx antenna pattern does not change during the lifetime of an association", + "type": "boolean", + "default": true + }, + "rx_stbc": { + "description": "Supports reception of PPDUs using STBC", + "type": "number", + "default": 3, + "minimum": 0, + "maximum": 4 + }, + "rxantenna": { + "description": "Specifies the antenna for receiving, the value may be driver specific, usually it is 1 for the first and 2 for the second antenna. Specifying 0 enables automatic selection by the driver if supported. This option has no effect if diversity is enabled", + "type": "number" + }, + "rxldpc": { + "description": "Supports receiving LDPC coded pkts", + "type": "boolean", + "default": true + }, + "short_gi_160": { + "description": "Short GI for 160 MHz", + "type": "boolean", + "default": true + }, + "short_gi_20": { + "description": "Short GI for 20 MHz", + "type": "boolean", + "default": true + }, + "short_gi_40": { + "description": "Short GI for 40 MHz", + "type": "boolean", + "default": true + }, + "short_gi_80": { + "description": "Short GI for 80 MHz", + "type": "boolean" + }, + "spectrum_mgmt_required": { + "description": "Set Spectrum Management subfield in the Capability Information field", + "type": "boolean", + "default": false + }, + "stationary_ap": { + "description": "Stationary AP config indicates that the AP doesn't move hence location data can be considered as always up to date.", + "type": "boolean", + "default": true + }, + "su_beamformee": { + "description": "Single user beamformee", + "type": "boolean", + "default": true + }, + "su_beamformer": { + "description": "Single user beamformer", + "type": "boolean", + "default": true + }, + "supported_rates": { + "description": "Set the supported data rates. Each supported rate is measured in kb/s. This option only has an effect on ap and adhoc wifi-ifaces. This must be a superset of the rates set in basic_rate. The minimum basic rate should also be the minimum supported rate. It is recommended to use the cell_density option instead", + "type": "array", + "items": { + "type": "number" + } + }, + "tx_antenna_pattern": { + "description": "Tx antenna pattern does not change during the lifetime of an association", + "type": "boolean", + "default": true + }, + "tx_burst": { + "type": "alias", + "default": "tx_queue_data2_burst" + }, + "tx_queue_data2_burst": { + "description": "", + "type": "number" + }, + "tx_stbc": { + "description": "Transmit STBC (Space-Time Block Coding)", + "type": "boolean", + "default": true + }, + "tx_stbc_2by1": { + "description": "Supports transmission of at least 2×1 STBC", + "type": "boolean", + "default": true + }, + "txantenna": { + "description": "Specifies the antenna for transmitting, values are identical to rxantenna", + "type": "number" + }, + "txpower": { + "description": "Specifies the maximum desired transmission power in dBm. The actual txpower used depends on regulatory requirements", + "type": "number" + }, + "vht160": { + "description": "Supported channel widths. 0 == 160MHz and 80+80 MHz not supported, 1 == 160 MHz supported, 2 == 160MHz and 80+80 MHz supported", + "type": "number", + "minimum": 0, + "maximum": 2, + "default": 2 + }, + "vht_link_adapt": { + "description": "TA supports link adaptation using VHT variant HT Control field", + "type": "number", + "minimum": 0, + "maximum": 3 + }, + "vht_max_a_mpdu_len_exp": { + "description": "Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv", + "type": "number", + "minimum": 0, + "maximum": 7 + }, + "vht_max_mpdu": { + "description": "Maximum MPDU length", + "type": "number", + "enum": [ 3895, 7991, 11454 ], + "default": 11454 + }, + "vht_txop_ps": { + "description": "VHT TXOP PS mode", + "type": "boolean", + "default": true + } + } +} diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/schema/wireless.wifi-iface.json b/package/network/config/wifi-scripts/files-ucode/usr/share/schema/wireless.wifi-iface.json new file mode 100644 index 00000000000000..3964098b5712dd --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/schema/wireless.wifi-iface.json @@ -0,0 +1,1157 @@ +{ + "$id": "https://openwrt.org/wifi.iface.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "OpenWrt WiFi Interface Schema", + "type": "object", + "properties": { + "access_network_type": { + "description": "Interworking Access Network Type", + "type": "number", + "minimum": 0, + "maximum": 15 + }, + "acct_interval": { + "type": "alias", + "default": "radius_acct_interim_interval" + }, + "acct_port": { + "type": "alias", + "default": "acct_server_port" + }, + "acct_secret": { + "type": "alias", + "default": "acct_server_shared_secret" + }, + "acct_server": { + "type": "alias", + "default": "acct_server_addr" + }, + "acct_server_addr": { + "description": "RADIUS accounting server to handle client authentication", + "type": "array", + "items": { + "type": "string" + } + }, + "acct_server_port": { + "description": "RADIUS accounting port", + "type": "number", + "default": 1813 + }, + "acct_server_shared_secret": { + "description": "Shared accounting RADIUS secret", + "type": "string" + }, + "airtime_bss_limit": { + "description": "Whether the current BSS should be limited (when airtime_mode=3)", + "type": "boolean" + }, + "airtime_bss_weight": { + "description": "Per-BSS airtime weight. In multi-BSS mode, set for each BSS and hostapd will configure station weights to enforce the correct ratio between BSS weights depending on the number of active stations", + "type": "number" + }, + "airtime_sta_weight": { + "description": "Static configuration of station weights (when airtime_mode=1). Kernel default weight is 256", + "type": "array", + "items": { + "type": "string" + } + }, + "altsubject_match": { + "description": "Semicolon separated string of entries to be matched against the alternative subject name of the authentication server certificate", + "type": "array", + "items": { + "type": "string" + } + }, + "altsubject_match2": { + "type": "array" + }, + "anonymous_identity": { + "description": "Anonymous identity string for EAP", + "type": "string" + }, + "anqp_3gpp_cell_net": { + "description": "3GPP Cellular Network information", + "type": "array", + "items": { + "type": "string" + } + }, + "anqp_domain_id": { + "description": "An identifier for a set of APs in an ESS that share the same common ANQP information", + "type": "number", + "minimum": 0, + "maximum": 65535, + "default": 0 + }, + "ap_isolate": { + "description": "Isolates wireless clients from each other, only applicable in ap mode", + "type": "boolean", + "default": false + }, + "ap_max_inactivity": { + "description": "Station inactivity limit in seconds: If a station does not send anything in ap_max_inactivity seconds, an empty data frame is sent to it in order to verify whether it is still in range. If this frame is not ACKed, the station will be disassociated and then deauthenticated", + "type": "number" + }, + "ap_pin": { + "description": "Static access point PIN for WPS", + "type": "string" + }, + "ap_setup_locked": { + "description": "AP can be configured into a locked state where new WPS Registrar are not accepted", + "type": "boolean" + }, + "anqp_elem": { + "description": "Arbitrary ANQP-element configuration", + "type": "array", + "items": { + "type": "string" + } + }, + "asra": { + "description": "Additional Step Required for Access", + "type": "boolean", + "default": false + }, + "assoc_sa_query_max_timeout": { + "description": "Specifies the 802.11w Association SA Query maximum timeout.", + "type": "number", + "minimum": 1, + "maximum": 4294967295 + }, + "assoc_sa_query_retry_timeout": { + "description": "Association SA Query retry timeout", + "type": "number", + "minimum": 1, + "maximum": 4294967295 + }, + "auth": { + "description": "Defines the phase 2 (inner) authentication method, only applicable if eap_type is peap or ttl", + "type": "string" + }, + "auth_cache": { + "type": "alias", + "default": "okc" + }, + "auth_port": { + "type": "alias", + "default": "auth_server_port" + }, + "auth_secret": { + "type": "alias", + "default": "auth_server_shared_secret" + }, + "auth_server": { + "type": "alias", + "default": "auth_server_addr" + }, + "auth_server_addr": { + "description": "RADIUS authentication server to handle client authentication", + "type": "array", + "items": { + "type": "string" + } + }, + "auth_server_port": { + "description": "RADIUS authentication port", + "type": "number", + "default": 1812 + }, + "auth_server_shared_secret": { + "description": "Shared authentication RADIUS secret", + "type": "string" + }, + "basic_rate": { + "type": "array" + }, + "bss_load_update_period": { + "description": "BSS Load update period (in BUs)", + "type": "number", + "default": 60 + }, + "bss_transition": { + "description": "BSS Transition Management", + "type": "boolean" + }, + "bssid": { + "description": "Override the BSSID of the network", + "type": "string" + }, + "bssid_blacklist": { + "type": "array" + }, + "bssid_whitelist": { + "type": "array" + }, + "ca_cert": { + "description": "Specifies the path the CA certificate used for authentication", + "type": "string" + }, + "ca_cert2_usesystem": { + "type": "boolean" + }, + "ca_cert_usesystem": { + "type": "boolean" + }, + "chan_util_avg_period": { + "description": "Channel utilization averaging period (in BUs)", + "type": "number", + "default": 600 + }, + "civic": { + "description": "The content of a location civic measurement subelement", + "type": "string" + }, + "client_cert": { + "description": "File path to client certificate file (PEM/DER)", + "type": "string" + }, + "dae_client": { + "type": "alias", + "default": "radius_das_client" + }, + "dae_port": { + "type": "alias", + "default": "radius_das_port" + }, + "dae_secret": { + "type": "alias", + "default": "radius_das_secret" + }, + "default_disabled": { + "type": "alias", + "default": "disabled" + }, + "device_name": { + "description": "Primary Device Name used by WPS", + "type": "string", + "default": "OpenWrt AP" + }, + "device_type": { + "description": "Primary Device Type used by WPS", + "type": "string", + "default": "6-0050F204-1" + }, + "disabled": { + "description": "Do not bring the interface up automatically", + "type": "boolean" + }, + "disable_dgaf": { + "description": "Disable Downstream Group-Addressed Forwarding", + "type": "boolean", + "default": false + }, + "disassoc_low_ack": { + "description": "Disassociate stations based on excessive transmission failures or other indications of connection loss. This depends on the driver capabilities and may not be available with all drivers.", + "type": "boolean", + "default": true + }, + "domain_match": { + "type": "array", + "items": { + "type": "string" + } + }, + "domain_match2": { + "type": "array" + }, + "domain_name" : { + "type": "array", + "items": { + "type": "string" + } + }, + "domain_suffix_match": { + "type": "array", + "items": { + "type": "string" + } + }, + "domain_suffix_match2": { + "type": "array" + }, + "dtim_period": { + "description": "Set the DTIM (delivery traffic information message) period. There will be one DTIM per this many beacon frames. This may be set between 1 and 255. This option only has an effect on ap wifi-ifaces.", + "type": "number", + "default": 2, + "minimum": 1, + "maximum": 255 + }, + "dynamic_ownip": { + "type": "alias", + "default": "dynamic_own_ip_addr" + }, + "dynamic_own_ip_addr": { + "type": "boolean" + }, + "dynamic_vlan": { + "description": "Allow RADIUS authentication server to decide which VLAN is used for the stations", + "type": "boolean" + }, + "eap_reauth_period": { + "description": "EAP reauthentication period in seconds", + "type": "number" + }, + "eap_server": { + "description": "Use integrated EAP server instead of external RADIUS authentication server", + "type": "boolean" + }, + "eap_type": { + "type": "string" + }, + "eap_user_file": { + "description": "Path for EAP server user database", + "type": "string" + }, + "eapol_version": { + "description": "IEEE 802.1X/EAPOL version", + "type": "number", + "enum": [ 1, 2 ] + }, + "enable": { + "description": "Enable the interface", + "type": "boolean", + "default": true + }, + "encryption": { + "type": "string" + }, + "esr": { + "description": "Emergency services reachable", + "type": "boolean", + "default": false + }, + "ext_registrar": { + "description": "WPS UPnP interface", + "type": "boolean" + }, + "fils": { + "description": "Enable FILS", + "type": "boolean" + }, + "fils_dhcp": { + "description": "DHCP server for FILS HLP. Set to '*' for automatic lookup.", + "type": "string" + }, + "ft_over_ds": { + "description": "Whether to enable FT-over-DS", + "type": "boolean", + "default": false + }, + "ft_psk_generate_local": { + "description": "Whether to generate FT response locally for PSK networks. This avoids use of PMK-R1 push/pull from other APs with FT-PSK networks as the required information (PSK and other session data) is already locally available.", + "type": "boolean" + }, + "ftm_responder": { + "description": "Publish fine timing measurement (FTM) responder functionality", + "type": "boolean" + }, + "gas_address3": { + "type": "string" + }, + "hidden": { + "type": "alias", + "default": "ignore_broadcast_ssid" + }, + "hessid": { + "description": "Homogeneous ESS identifier", + "type": "string" + }, + "hostapd_bss_options": { + "description": "Additional raw options to be added", + "type": "array", + "items": { + "type": "string" + } + }, + "hs20": { + "description": "Enable Hotspot 2.0 support", + "type": "boolean" + }, + "hs20_conn_capab": { + "description": "Connection Capability", + "type": "array", + "items": { + "type": "string" + } + }, + "hs20_deauth_req_timeout": { + "description": "Deauthentication request timeout", + "type": "number", + "default": 60 + }, + "hs20_oper_friendly_name": { + "description": "Operator Friendly Name", + "type": "array", + "items": { + "type": "string" + } + }, + "hs20_operating_class": { + "description": "Operating Class Indication", + "type": "string" + }, + "hs20_t_c_filename": { + "description": "Terms and Conditions information", + "type": "string" + }, + "hs20_t_c_server_url": { + "description": "Terms and Conditions server", + "type": "string" + }, + "hs20_t_c_timestamp": { + "description": "Terms and Conditions timestamp", + "type": "string" + }, + "hs20_wan_metrics": { + "description": "WAN Metrics", + "type": "string" + }, + "identity": { + "description": "Identity string for EAP", + "type": "string" + }, + "ieee80211k": { + "description": "Enables Radio Resource Measurement (802.11k) support", + "type": "boolean", + "default": true + }, + "ieee80211r": { + "description": "Enables fast BSS transition (802.11r) support.", + "type": "boolean" + }, + "ieee80211w": { + "description": "Enables MFP (802.11w) support (0 = disabled, 1 = optional, 2 = required). Requires the 'full' version of wpad/hostapd and support from the Wi-Fi driver", + "type": "number", + "enum": [ 0, 1, 2 ], + "default": 0 + }, + "ieee80211w_max_timeout": { + "type": "alias", + "default": "assoc_sa_query_max_timeout" + }, + "ieee80211w_mgmt_cipher": { + "description": "Group Management cypher", + "type": "string" + }, + "ieee80211w_retry_timeout": { + "type": "alias", + "default": "assoc_sa_query_retry_timeout" + }, + "ifname": { + "description": "Specifies a custom name for the Wi-Fi interface, which is otherwise automatically named. Maximum length: 15 characters", + "type": "string" + }, + "ignore_broadcast_ssid": { + "description": "Disables the broadcasting of beacon frames if set to 1 and, in doing so, hides the ESSID. Where the ESSID is hidden, clients may fail to roam and airtime efficiency may be significantly reduced.", + "type": "boolean", + "default": false + }, + "internet": { + "description": "Whether the network provides connectivity to the Internet", + "type": "boolean", + "default": true + }, + "isolate": { + "type": "alias", + "default": "ap_isolate" + }, + + "iw_access_network_type": { + "type": "alias", + "default": "access_network_type" + }, + "iw_anqp_3gpp_cell_net": { + "type": "alias", + "default": "anqp_3gpp_cell_net" + }, + "iw_anqp_elem": { + "type": "alias", + "default": "anqp_elem" + }, + "iw_asra": { + "type": "alias", + "default": "asra" + }, + "iw_domain_name": { + "type": "alias", + "default": "domain_name" + }, + "iw_enabled": { + "type": "boolean", + "default": false + }, + "iw_esr": { + "type": "alias", + "default": "esr" + }, + "iw_gas_address3": { + "type": "alias", + "default": "gas_address3" + }, + "iw_hessid": { + "type": "alias", + "default": "hessid" + }, + "iw_internet": { + "type": "alias", + "default": "internet" + }, + "iw_ipaddr_type_availability": { + "type": "number" + }, + "iw_nai_realm": { + "type": "alias", + "default": "nai_realm" + }, + "iw_network_auth_type": { + "type": "alias", + "default": "network_auth_type" + }, + "iw_qos_map_set": { + "type": "alias", + "default": "qos_map_set" + }, + "roaming_consortium": { + "type": "alias", + "default": "roaming_consortium" + }, + "iw_uesa": { + "type": "alias", + "default": "uesa" + }, + "iw_venue_group": { + "type": "alias", + "default": "venue_group" + }, + "iw_venue_name": { + "type": "alias", + "default": "venue_name" + }, + "iw_venue_type": { + "type": "alias", + "default": "venue_type" + }, + "iw_venue_url": { + "type": "alias", + "default": "venue_url" + }, + "key": { + "description": "Encryption key", + "type": "string" + }, + "lci": { + "description": "The content of a LCI measurement subelement", + "type": "string" + }, + "macaddr": { + "description": "Override the BSSID of the network", + "type": "string" + }, + "macfile": { + "description": "File containing a list MACs used by the macfilter", + "type": "string" + }, + "macfilter": { + "description": "Allow/deny associations based on the clients MAC", + "type": "string", + "enum": [ "allow", "deny" ] + }, + "maclist": { + "description": "List of MACs used by the macfilter option", + "type": "array", + "items": { + "type": "string" + } + }, + "manufacturer": { + "description": "Manufacturer used by WPS", + "type": "string", + "default": "www.openwrt.org" + }, + "max_inactivity": { + "type": "alias", + "default": "ap_max_inactivity" + }, + "max_listen_int": { + "type": "alias", + "default": "max_listen_interval" + }, + "max_listen_interval": { + "description": "How many Beacon periods STAs are allowed to remain asleep", + "type": "number" + }, + "max_num_sta": { + "description": "Maximum number of stations allowed in station table", + "type": "number" + }, + "maxassoc": { + "type": "alias", + "default": "max_num_sta" + }, + "mbo": { + "description": "Multiband Operation", + "type": "boolean" + }, + "mcast_rate": { + "description": "Allowed multicast rates", + "type": "array", + "items": { + "type": "number" + } + }, + "mesh_auto_open_plinks": { + "type": "boolean" + }, + "mesh_awake_window": { + "type": "number" + }, + "mesh_confirm_timeout": { + "type": "number" + }, + "mesh_element_ttl": { + "type": "number" + }, + "mesh_fwding": { + "description": "Enable 802.11s layer-2 routing and forwarding", + "type": "boolean" + }, + "mesh_gate_announcements": { + "type": "number" + }, + "mesh_holding_timeout": { + "type": "number" + }, + "mesh_hwmp_active_path_timeout": { + "type": "number" + }, + "mesh_hwmp_active_path_to_root_timeout": { + "type": "number" + }, + "mesh_hwmp_confirmation_interval": { + "type": "number" + }, + "mesh_hwmp_max_preq_retries": { + "type": "number" + }, + "mesh_hwmp_net_diameter_traversal_time": { + "type": "number" + }, + "mesh_hwmp_preq_min_interval": { + "type": "number" + }, + "mesh_hwmp_rann_interval": { + "type": "number" + }, + "mesh_hwmp_root_interval": { + "type": "number" + }, + "mesh_hwmp_rootmode": { + "type": "number" + }, + "mesh_id": { + "type": "string" + }, + "mesh_max_peer_links": { + "type": "number" + }, + "mesh_max_retries": { + "type": "number" + }, + "mesh_min_discovery_timeout": { + "type": "number" + }, + "mesh_path_refresh_time": { + "type": "number" + }, + "mesh_plink_timeout": { + "type": "number" + }, + "mesh_power_mode": { + "type": "string" + }, + "mesh_retry_timeout": { + "type": "number" + }, + "mesh_rssi_threshold": { + "type": "number" + }, + "mesh_sync_offset_max_neighor": { + "type": "number" + }, + "mesh_ttl": { + "type": "number" + }, + "mobility_domain": { + "description": "DID is used to indicate a group of APs between which a STA can use Fast BSS Transition.", + "type": "string" + }, + "mode": { + "type": "string" + }, + "multi_ap": { + "description": "Enable Multi-AP functionality", + "type": "number" + }, + "multi_ap_backhaul_key": { + "type": "string" + }, + "multi_ap_backhaul_ssid": { + "description": "Multi-AP backhaul BSS SSID", + "type": "string" + }, + "multicast_to_unicast": { + "description": "Request that the AP will do multicast-to-unicast conversion for ARP, IPv4, and IPv6 frames ", + "type": "boolean" + }, + "multicast_to_unicast_all": { + "type": "alias", + "default": "multicast_to_unicast" + }, + "nas_identifier": { + "description": "NAS-Identifier string for RADIUS messages", + "type": "string" + }, + "nai_realm": { + "description": "NAI Realm information", + "type": "array", + "items": { + "type": "string" + } + }, + "nasid": { + "type": "alias", + "default": "nas_identifier" + }, + "network_auth_type": { + "description": "Network Authentication Type", + "type": "string" + }, + "ocv": { + "description": "Operating Channel Validation", + "type": "number", + "minimum": 0, + "maximum": 15 + }, + "okc": { + "description": "PMKSA and Opportunistic Key Caching", + "type": "boolean" + }, + "operator_icon": { + "type": "array" + }, + "osen": { + "description": "OSU Server-Only Authenticated L2 Encryption Network", + "type": "boolean", + "default": false + }, + "osu_provider": { + "type": "array", + "items": { + "type": "string" + } + }, + "osu_ssid": { + "type": "string" + }, + "owe_transition": { + "description": "Indicate that an OWE BSS shall automatically add an unencrypted transition interface", + "type": "boolean" + }, + "owe_transition_bssid": { + "description": "Pointer to the matching open/OWE BSS", + "type": "string" + }, + "owe_transition_ifname": { + "description": "Alternatively, OWE transition mode BSSID/SSID can be configured with a reference to a BSS operated by this hostapd process.", + "type": "string" + }, + "owe_transition_ssid": { + "description": "The SSID used by the OWE transition device", + "type": "string" + }, + "ownip": { + "type": "alias", + "default": "own_ip_addr" + }, + "own_ip_addr": { + "description": "The own IP address of the access point", + "type": "string" + }, + "password:wpakey": { + "type": "string" + }, + "pbc_in_m1": { + "description": "WPS capability discovery workaround for PBC with Windows 7", + "type": "boolean" + }, + "per_sta_vif": { + "description": "Per-Station AP_VLAN interface mode", + "type": "boolean" + }, + "pmk_r1_push": { + "description": "Whether PMK-R1 push is enabled at R0KH", + "type": "boolean", + "default": false + }, + "port:port": { + "type": "number" + }, + "powersave": { + "type": "boolean" + }, + "ppsk": { + "description": "Lookup PSK2 Keys up via a Radius server", + "type": "boolean" + }, + "preamble": { + "description": "Short Preamble", + "type": "boolean", + "default": true + }, + "priv_key": { + "type": "string" + }, + "priv_key_pwd": { + "type": "string" + }, + "private_key": { + "description": "Private key matching with the server certificate for EAP-TLS/PEAP/TTLS", + "type": "string" + }, + "private_key_passwd": { + "description": "Passphrase for private key", + "type": "string" + }, + "proxy_arp": { + "description": "Proxy ARP", + "type": "boolean" + }, + "qos_map_set": { + "description": "QoS Map Set configuration", + "type": "string", + "default": "0,0,2,16,1,1,255,255,18,22,24,38,40,40,44,46,48,56" + }, + "r0_key_lifetime": { + "description": "Default lifetime of the PMK-R0 in seconds", + "type": "number" + }, + "r0kh": { + "description": "List of R0KHs in the same Mobility Domain", + "type": "array", + "items": { + "type": "string" + } + }, + "r1_key_holder": { + "description": "PMK-R1 Key Holder identifier", + "type": "string" + }, + "r1kh": { + "description": "List of R1KHs in the same Mobility Domain", + "type": "array", + "items": { + "type": "string" + } + }, + "radius_acct_interim_interval": { + "description": "Interim accounting update interval", + "type": "number" + }, + "radius_acct_req_attr": { + "description": "Additional Accounting-Request attributes", + "type": "array", + "items": { + "type": "string" + } + }, + "radius_auth_req_attr": { + "description": "Additional Access-Request attributes", + "type": "array", + "items": { + "type": "string" + } + }, + "radius_client_addr": { + "description": "RADIUS client forced local IP address for the access point", + "type": "string" + }, + "radius_das_client": { + "description": "DAS client (the host that can send Disconnect/CoA requests)", + "type": "string" + }, + "radius_das_port": { + "description": "Dynamic Authorization Extensions port", + "type": "number" + }, + "radius_das_secret": { + "description": "Dynamic Authorization Extensions secret", + "type": "string" + }, + "radius_request_cui" :{ + "description": "Request Chargeable-User-Identity (RFC 4372)", + "type": "boolean" + }, + "reassociation_deadline": { + "description": "Reassociation deadline in time units", + "type": "number", + "minimum": 1000, + "maximum": 65535, + "default": 1000 + }, + "request_cui": { + "type": "alias", + "default": "radius_request_cui" + }, + "rrm_beacon_report": { + "description": "Enable beacon report via radio measurements", + "type": "boolean", + "default": true + }, + "rrm_neighbor_report": { + "description": "Enable neighbor report via radio measurements", + "type": "boolean", + "default": true + }, + "rnr": { + "description": "Enable reduced neighbor reporting", + "type": "boolean", + "default": true + }, + "roaming_consortium": { + "description": "Roaming Consortium List", + "type": "array", + "items": { + "type": "string" + } + }, + "rsn_preauth": { + "type": "boolean" + }, + "sae_pwe": { + "description": "SAE mechanism for PWE derivation", + "type": "number", + "enum": [ 0, 1, 2 ] + }, + "sae_require_mfp": { + "description": "Require MFP for all associations using SAE", + "type": "boolean" + }, + "server:host": { + "type": "string" + }, + "server_cert": { + "description": "Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS", + "type": "string" + }, + "server_id": { + "description": "Server identity", + "type": "string" + }, + "short_preamble": { + "type": "alias", + "default": "preamble" + }, + "skip_inactivity_poll": { + "description": "The inactivity polling can be disabled to disconnect stations based on inactivity timeout so that idle stations are more likely to be disconnected even if they are still in range of the AP", + "type": "boolean", + "default": false + }, + "ssid": { + "type": "string" + }, + "ssid:string": { + "type": "string" + }, + "start_disabled": { + "type": "number" + }, + "subject_match": { + "description": "Substring to be matched against the subject of the authentication server certificate", + "type": "string" + }, + "subject_match2": { + "type": "string" + }, + "supported_rates": { + "type": "array" + }, + "tdls_prohibit": { + "description": "Prohibit use of TDLS in this BSS", + "type": "boolean" + }, + "time_advertisement": { + "description": "Time advertisement", + "type": "number", + "enum": [ 0, 2 ] + }, + "time_zone": { + "description": "Local time zone as specified in 8.3 of IEEE Std 1003.1-2004", + "type": "string" + }, + "uapsd": { + "type": "alias", + "default": "uapsd_advertisement_enabled" + }, + "uapsd_advertisement_enabled": { + "description": "WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD]", + "type": "boolean", + "default": true + }, + "uesa": { + "description": "Unauthenticated emergency service accessible", + "type": "boolean", + "default": false + }, + "utf8_ssid": { + "description": "Whether the SSID is to be interpreted using UTF-8 encoding", + "type": "boolean", + "default": true + }, + "vendor_elements": { + "description": "Additional vendor specific elements for Beacon and Probe Response frames", + "type": "array", + "items": { + "type": "string" + } + }, + "venue_group": { + "type": "string" + }, + "venue_name": { + "description": "Venue Name information", + "type": "array", + "items": { + "type": "string" + } + }, + "venue_type": { + "type": "string" + }, + "venue_url": { + "description": "Venue URL information", + "type": "array", + "items": { + "type": "string" + } + }, + "vlan_bridge": { + "description": "Bridge (prefix) to add the wifi and the tagged interface to.", + "type": "string" + }, + "vlan_file": { + "type": "string" + }, + "vlan_naming": { + "description": "When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs to know how to name it.", + "type": "boolean", + "default": true + }, + "vlan_no_bridge": { + "description": "To not setup a bridge for dynamic vlans", + "type": "boolean" + }, + "vlan_tagged_interface": { + "type": "string" + }, + "wds": { + "type": "boolean" + }, + "wds_bridge": { + "description": "If bridge parameter is set, the WDS STA interface will be added to the same bridge by default", + "type": "string" + }, + "wds_sta": { + "description": "If bridge parameter is set, the WDS STA interface will be added to the same bridge by default", + "type": "boolean" + }, + "wmm": { + "type": "alias", + "default": "wmm_enabled" + }, + "wmm_enabled": { + "description": "Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e)", + "type": "boolean", + "default": true + }, + "wnm_sleep_mode": { + "description": "WNM-Sleep Mode (extended sleep mode for stations)", + "type": "boolean" + }, + "wnm_sleep_mode_no_keys": { + "description": "WNM-Sleep Mode GTK/IGTK workaround", + "type": "boolean" + }, + "wpa_disable_eapol_key_retries": { + "description": "Workaround for key reinstallation attacks", + "type": "boolean", + "default": false + }, + "wpa_gmk_rekey": { + "description": "Time interval for rekeying GMK (master key used internally to generate GTKs)", + "type": "number" + }, + "wpa_group_rekey": { + "description": "Time interval for rekeying GTK (broadcast/multicast encryption keys)", + "type": "number" + }, + "wpa_master_rekey": { + "type": "alias", + "default": "wpa_gmk_rekey" + }, + "wpa_pair_rekey": { + "type": "alias", + "default": "wpa_ptk_rekey" + }, + "wpa_psk_file": { + "description": "External file conatining VLAN PSK MAC address triplets", + "type": "string" + }, + "wpa_ptk_rekey": { + "description": "Maximum lifetime for PTK in seconds", + "type": "number" + }, + "wpa_strict_rekey": { + "description": "Rekey GTK when any STA that possesses the current GTK is leaving the BSS", + "type": "boolean" + }, + "wps_ap_setup_locked": { + "type": "alias", + "default": "ap_setup_locked" + }, + "wps_device_name": { + "type": "alias", + "default": "device_name" + }, + "wps_device_type": { + "type": "alias", + "default": "device_type" + }, + "wps_independent": { + "description": "Whether to manage this interface independently from other WPS interfaces", + "type": "number", + "default": true + }, + "wps_label": { + "description": "Support WPS labels", + "type": "boolean" + }, + "wps_manufacturer": { + "type": "alias", + "default": "manufacturer" + }, + "wps_pbc_in_m1": { + "type": "alias", + "default": "pbc_in_m1" + }, + "wps_pin": { + "type": "alias", + "default": "ap_pin" + }, + "wps_pushbutton": { + "description": "Support WPS pushbutton", + "type": "boolean" + } + } +} diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/schema/wireless.wifi-station.json b/package/network/config/wifi-scripts/files-ucode/usr/share/schema/wireless.wifi-station.json new file mode 100644 index 00000000000000..dbad47abf4b0a7 --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/schema/wireless.wifi-station.json @@ -0,0 +1,20 @@ +{ + "$id": "https://openwrt.org/wifi.station.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "OpenWrt WiFi Station Schema", + "type": "object", + "properties": { + "mac": { + "description": "The stations MAC", + "type": "string" + }, + "key": { + "description": "The passphrase that shall be used", + "type": "string" + }, + "vid": { + "description": "The VLAN Id used by the station", + "type": "string" + } + } +} diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/schema/wireless.wifi-vlan.json b/package/network/config/wifi-scripts/files-ucode/usr/share/schema/wireless.wifi-vlan.json new file mode 100644 index 00000000000000..a06c8dabf0b78a --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/schema/wireless.wifi-vlan.json @@ -0,0 +1,16 @@ +{ + "$id": "https://openwrt.org/wifi.vlan.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "OpenWrt WiFi VLAN Schema", + "type": "object", + "properties": { + "name": { + "description": "VLAN name", + "type": "string" + }, + "vid": { + "description": "VLAN ID", + "type": "string" + } + } +} diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/iwinfo.uc b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/iwinfo.uc new file mode 100644 index 00000000000000..71672c23adc423 --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/iwinfo.uc @@ -0,0 +1,607 @@ +'use strict'; + +import * as nl80211 from 'nl80211'; +import * as libubus from 'ubus'; +import { readfile, stat } from "fs"; + +let wifi_devices = json(readfile('/usr/share/wifi_devices.json')); +let countries = json(readfile('/usr/share/iso3166.json')); +let board_data = json(readfile('/etc/board.json')); + +export let phys = nl80211.request(nl80211.const.NL80211_CMD_GET_WIPHY, nl80211.const.NLM_F_DUMP, { split_wiphy_dump: true }); +let interfaces = nl80211.request(nl80211.const.NL80211_CMD_GET_INTERFACE, nl80211.const.NLM_F_DUMP); + +let ubus = libubus.connect(); +let wireless_status = ubus.call('network.wireless', 'status'); + +function find_phy(wiphy) { + for (let k, phy in phys) + if (phy.wiphy == wiphy) + return phy; + return null; +} + +function get_noise(iface) { + for (let phy in phys) { + let channels = nl80211.request(nl80211.const.NL80211_CMD_GET_SURVEY, nl80211.const.NLM_F_DUMP, { dev: iface.ifname }); + for (let k, channel in channels) + if (channel.survey_info.frequency == iface.wiphy_freq) + return channel.survey_info.noise; + } + + return -100; +} + +function get_country(iface) { + let reg = nl80211.request(nl80211.const.NL80211_CMD_GET_REG, 0, { dev: iface.ifname }); + + return reg.reg_alpha2 ?? ''; +} + +function get_max_power(iface) { + let phy = find_phy(iface.wiphy); + + for (let k, band in phy.wiphy_bands) + if (band) + for (let freq in band.freqs) + if (freq.freq == iface.wiphy_freq) + return freq.max_tx_power;; + return 0; +} + +function get_hardware_id(iface) { + let hw = { + type: 'nl80211', + id: 'Generic MAC80211', + power_offset: 0, + channel_offset: 0, + }; + + let path = `/sys/class/ieee80211/phy${iface.wiphy}/device/`; + if (stat(path) + 'vendor') { + let data = []; + for (let lookup in [ 'vendor', 'device', 'subsystem_vendor', 'subsystem_device' ]) + push(data, trim(readfile(path + lookup), '\n')); + + for (let device in wifi_devices.pci) { + let match = 0; + for (let i = 0; i < 4; i++) + if (lc(data[i]) == lc(device[i])) + match++; + if (match == 4) { + hw.type = `${data[0]}:${data[1]} ${data[2]}:${data[3]}`; + hw.power_offset = device[4]; + hw.channel_offset = device[5]; + hw.id = `${device[6]} ${device[7]}`; + } + } + } + + let compatible = trim(readfile(`/sys/class/net/${iface.ifname}/device/of_node/compatible`), '\n'); + if (compatible && wifi_devices.compatible[compatible]) { + hw.id = wifi_devices.compatible[compatible][0] + ' ' + wifi_devices.compatible[compatible][1]; + hw.compatible = compatible; + hw.type = 'embedded'; + } + + return hw; +} + +const iftypes = [ + 'Unknown', 'Ad-Hoc', 'Client', 'Master', 'Master (VLAN)', + 'WDS', 'Monitor', 'Mesh Point', 'P2P Client', 'P2P Go', +]; + +export let ifaces = {}; +for (let k, v in interfaces) { + let iface = ifaces[v.ifname] = v; + + iface.mode = iftypes[iface.iftype] ?? 'unknonw', + iface.noise = get_noise(iface); + iface.country = get_country(iface); + iface.max_power = get_max_power(iface); + iface.assoclist = nl80211.request(nl80211.const.NL80211_CMD_GET_STATION, nl80211.const.NLM_F_DUMP, { dev: v.ifname }) ?? []; + iface.hardware = get_hardware_id(iface); + + iface.bss_info = ubus.call('hostapd', 'bss_info', { iface: v.ifname }); + if (!iface.bss_info) + iface.bss_info = ubus.call('wpa_supplicant', 'bss_info', { iface: v.ifname }); +} + +for (let radio, data in wireless_status) + for (let k, v in data.interfaces) { + if (!v.ifname || !ifaces[v.ifname]) + continue; + + ifaces[v.ifname].ssid = v.config.ssid || v.config.mesh_id; + ifaces[v.ifname].radio = data.config; + + let bss_info = ifaces[v.ifname].bss_info; + let owe_transition_ifname = bss_info?.owe_transition_ifname; + + if (v.config.owe_transition && ifaces[owe_transition_ifname]) { + ifaces[v.ifname].owe_transition_ifname = owe_transition_ifname; + ifaces[owe_transition_ifname].ssid = v.config.ssid; + ifaces[owe_transition_ifname].radio = data.config; + ifaces[owe_transition_ifname].owe_transition_ifname = v.ifname + } + } + +function format_channel(freq) { + if (freq < 1000) + return 0; + if (freq == 2484) + return 14; + if (freq == 5935) + return 2; + if (freq < 2484) + return (freq - 2407) / 5; + if (freq >= 4910 && freq <= 4980) + return (freq - 4000) / 5; + if (freq < 5950) + return (freq - 5000) / 5; + if (freq <= 45000) + return (freq - 5950) / 5; + if (freq >= 58320 && freq <= 70200) + return (freq - 56160) / 2160; + + return 'unknown'; +} + +function format_band(freq) { + if (freq == 5935) + return '6'; + if (freq < 2484) + return '2.4'; + if (freq < 5950) + return '5'; + if (freq <= 45000) + return '6'; + + return '60'; +} + +function format_frequency(freq) { + if (!freq) + return 'unknown'; + freq = '' + freq; + return substr(freq, 0, 1) + '.' + substr(freq, 1); +} + +function format_rate(rate) { + if (!rate) + return 'unknown'; + return '' + (rate / 10) + '.' + (rate % 10); +} + +function format_mgmt_key(key) { + switch(+key) { + case 1: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + return '802.1x'; + + case 2: + return 'WPA PSK'; + + case 4: + return 'FT PSK'; + + case 6: + return 'WPA PSK2'; + + case 8: + return 'SAE'; + + case 18: + return 'OWE'; + } + + return null; +} + +function assoc_flags(data) { + const assoc_mhz = { + width_40: 40, + width_80: 80, + width_80p80: '80+80', + width_160: 160, + width_320: 320, + width_10: 10, + width_5: 5 + }; + + let mhz = 'unknown'; + for (let k, v in assoc_mhz) + if (data[k]) + mhz = v; + + const assoc_flags = { + mcs: { + mcs: 'MCS', + }, + vht_mcs: { + vht_mcs: 'VHT-MCS', + vht_nss: 'VHT-NSS', + }, + he_mcs: { + he_mcs: 'HE-MCS', + he_nss: 'HE-NSS', + he_gi: 'HE-GI', + he_dcm: 'HE-DCM', + }, + eht_mcs: { + eht_mcs: 'EHT-MCS', + eht_nss: 'EHT-NSS', + eht_gi: 'EHT-GI', + }, + }; + + let flags = []; + for (let k, v in assoc_flags) { + if (!data[k]) + continue; + + let first = 0; + for (let name, flag in v) { + if (data[name] == null) + continue; + push(flags, `${flag} ${data[name]}`); + if (!first++) + push(flags, `${mhz}MHz`); + } + } + + return flags; +} + +function dbm2mw(dbm) { + const LOG10_MAGIC = 1.25892541179; + let res = 1.0; + let ip = dbm / 10; + let fp = dbm % 10; + + for (let k = 0; k < ip; k++) + res *= 10; + for (let k = 0; k < fp; k++) + res *= 1.25892541179; + + return int(res); +} + +function dbm2quality(dbm) { + let quality = dbm; + + if (quality < -110) + quality = -110; + else if (quality > -40) + quality = -40; + quality += 110; + + return quality; +} + +function hwmodelist(name) { + const mode = { 'HT*': 'n', 'VHT*': 'ac', 'HE*': 'ax' }; + let iface = ifaces[name]; + let phy = board_data.wlan?.['phy' + iface.wiphy]; + if (!phy) + return ''; + let htmodes = phy.info.bands[uc(iface.radio.band)].modes; + let list = []; + if (iface.radio.band == '2g' && 'NOHT' in htmodes) + push(list, 'g/b'); + for (let k, v in mode) + for (let htmode in htmodes) + if (wildcard(htmode, k)) + push(list, v); + + return join('/', reverse(uniq(list))); +} + +export function assoclist(dev) { + let stations = ifaces[dev].assoclist; + let ret = {}; + + for (let station in stations) { + let sta = { + mac: uc(station.mac), + signal: station.sta_info.signal_avg, + noise: ifaces[dev].noise, + snr: station.sta_info.signal_avg - ifaces[dev].noise, + inactive_time: station.sta_info.inactive_time, + rx: { + bitrate: format_rate(station.sta_info.rx_bitrate.bitrate), + bitrate_raw: station.sta_info.rx_bitrate.bitrate, + packets: station.sta_info.rx_packets, + flags: assoc_flags(station.sta_info.rx_bitrate), + }, + tx: { + bitrate: format_rate(station.sta_info.tx_bitrate.bitrate), + bitrate_raw: station.sta_info.tx_bitrate.bitrate, + packets: station.sta_info.tx_packets, + flags: assoc_flags(station.sta_info.tx_bitrate), + }, + expected_throughput: station.sta_info.expected_throughput ?? 'unknown', + }; + ret[sta.mac] = sta; + } + + return ret; +}; + +export function freqlist(name) { + const freq_flags = { + no_10mhz: 'NO_10MHZ', + no_20mhz: 'NO_20MHZ', + no_ht40_minus: 'NO_HT40-', + no_ht40_plus: 'NO_HT40+', + no_80mhz: 'NO_80MHZ', + no_160mhz: 'NO_160MHZ', + indoor_only: 'INDOOR_ONLY', + no_ir: 'NO_IR', + no_he: 'NO_HE', + radar: 'RADAR_DETECTION', + }; + + let iface = ifaces[name]; + let phy = find_phy(iface.wiphy); + let channels = []; + + for (let k, band in phy.wiphy_bands) { + if (!band) + continue; + + let band_name = format_band(band.freqs[0].freq); + for (let freq in band.freqs) { + if (freq.disabled) + continue; + + let channel = { + freq: format_frequency(freq.freq), + band: band_name, + channel: format_channel(freq.freq), + flags: [], + active: iface.wiphy_freq == freq.freq, + }; + + for (let k, v in freq_flags) + if (freq[k]) + push(channel.flags, v); + + push(channels, channel); + } + } + + return channels; +}; + +export function info(name) { + let order = []; + for (let iface, data in ifaces) + push(order, iface); + + let list = []; + for (let iface in sort(order)) { + if (name && iface != name) + continue; + let data = ifaces[iface]; + let dev = { + iface, + ssid: data.ssid, + mac: data.mac, + mode: data.mode, + channel: format_channel(data.wiphy_freq), + freq: format_frequency(data.wiphy_freq), + htmode: data.radio.htmode, + center_freq1: format_channel(data.center_freq1) || 'unknown', + center_freq2: format_channel(data.center_freq2) || 'unknown', + txpower: data.wiphy_tx_power_level / 100, + noise: data.noise, + signal: 0, + bitrate: 0, + encryption: 'unknown', + hwmode: hwmodelist(iface), + phy: 'phy' + data.wiphy, + vaps: 'no', + hw_type: data.hardware.type, + hw_id: data.hardware.id, + power_offset: data.hardware.power_offset || 'none', + channel_offset: data.hardware.channel_offset || 'none', + }; + + let phy = find_phy(data.wiphy); + for (let limit in phy.interface_combinations[0]?.limits) + if (limit.types?.ap && limit.max > 1) + dev.vaps = 'yes'; + + if (data.bss_info) { + if (data.bss_info.wpa_key_mgmt && data.bss_info.wpa_pairwise) + dev.encryption = `${replace(data.bss_info.wpa_key_mgmt, ' ', ' / ')} (${data.bss_info.wpa_pairwise})`; + else if (data.owe_transition_ifname) + dev.encryption = 'none (OWE transition)'; + else + dev.encryption = 'none'; + } + + let stations = assoclist(iface); + for (let k, station in stations) { + dev.signal += station.signal; + dev.bitrate += station.tx.bitrate_raw; + } + dev.signal /= length(data.assoclist) || 1; + dev.bitrate /= length(data.assoclist) || 1; + dev.bitrate = format_rate(dev.bitrate); + dev.quality = dbm2quality(dev.signal); + + if (data.owe_transition_ifname) + dev.owe_transition_ifname = data.owe_transition_ifname; + + push(list, dev); + } + + return list; +}; + +export function htmodelist(name) { + let iface = ifaces[name]; + let phy = board_data.wlan?.['phy' + iface.wiphy]; + if (!phy) + return []; + + return filter(phy.info.bands[uc(iface.radio.band)].modes, (v) => v != 'NOHT'); +}; + +export function txpowerlist(name) { + let iface = ifaces[name]; + let max_power = iface.max_power / 100; + let match = iface.wiphy_tx_power_level / 100; + let list = []; + + for (let power = 0; power <= max_power; power++) { + let txpower = { + dbm: power, + mw: dbm2mw(power), + active: power == match, + }; + push(list, txpower); + } + + return list; +}; + +export function countrylist(dev) { + let iface = ifaces[dev]; + + let list = { + active: iface.country, + countries, + }; + + return list; +}; + +export function scan(dev) { + const rsn_cipher = [ 'NONE', 'WEP-40', 'TKIP', 'WRAP', 'CCMP', 'WEP-104', 'AES-OCB', 'CKIP', 'GCMP', 'GCMP-256', 'CCMP-256' ]; + const ht_chan_offset = [ 'no secondary', 'above', '[reserved]', 'below' ]; + const vht_chan_width = [ '20 or 40 MHz', '80 MHz', '80+80 MHz', '160 MHz' ]; + const ht_chan_width = [ '20 MHz', '40 MHz or higher' ]; + const SCAN_FLAG_AP = (1<<2); + + let params = { + dev, + scan_flags: SCAN_FLAG_AP, + scan_ssids: [ '' ], + }; + + let res = nl80211.request(nl80211.const.NL80211_CMD_TRIGGER_SCAN, 0, params); + if (res === false) { + printf("Unable to trigger scan: " + nl80211.error() + "\n"); + exit(1); + } + + res = nl80211.waitfor([ + nl80211.const.NL80211_CMD_NEW_SCAN_RESULTS, + nl80211.const.NL80211_CMD_SCAN_ABORTED + ], 5000); + + if (!res) { + printf("Netlink error while awaiting scan results: " + nl80211.error() + "\n"); + exit(1); + } else if (res.cmd == nl80211.const.NL80211_CMD_SCAN_ABORTED) { + printf("Scan aborted by kernel\n"); + exit(1); + } + + let scan = nl80211.request(nl80211.const.NL80211_CMD_GET_SCAN, nl80211.const.NLM_F_DUMP, { dev }); + + let cells = []; + for (let k, bss in scan) { + bss = bss.bss; + let cell = { + bssid: uc(bss.bssid), + frequency: format_frequency(bss.frequency), + band: format_band(bss.frequency), + channel: format_channel(bss.frequency), + dbm: bss.signal_mbm / 100, + + }; + + if (bss.capability & (1 << 1)) + cell.mode = 'Ad-Hoc'; + else if (bss.capability & (1 << 0)) + cell.mode = 'Master'; + else + cell.mode = 'Mesh Point'; + + cell.quality = dbm2quality(cell.dbm); + + for (let ie in bss.information_elements) + switch(ie.type) { + case 0: + case 114: + cell.ssid = ie.data; + break; + + case 7: + cell.country = substr(ie.data, 0, 2); + break; + + case 48: + cell.crypto = { + group: rsn_cipher[+ord(ie.data, 5)] ?? '', + pair: [], + key_mgmt: [], + }; + + let offset = 6; + let count = +ord(ie.data, offset); + offset += 2; + + for (let i = 0; i < count; i++) { + let key = rsn_cipher[+ord(ie.data, offset + 3)]; + if (key) + push(cell.crypto.pair, key); + offset += 4; + } + + count = +ord(ie.data, offset); + offset += 2; + + for (let i = 0; i < count; i++) { + let key = format_mgmt_key(ord(ie.data, offset + 3)); + if (key) + push(cell.crypto.key_mgmt, key); + offset += 4; + } + break; + + case 61: + cell.ht = { + primary_channel: ord(ie.data, 0), + secondary_chan_off: ht_chan_offset[ord(ie.data, 1) & 0x3], + chan_width: ht_chan_width[(ord(ie.data, 1) & 0x4) >> 2], + }; + break; + + case 192: + cell.vht = { + chan_width: vht_chan_width[ord(ie.data, 0)], + center_chan_1: ord(ie.data, 1), + center_chan_2: ord(ie.data, 2), + }; + break; + }; + + + + push(cells, cell); + } + + return cells; +}; diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/ap.uc b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/ap.uc new file mode 100644 index 00000000000000..cc2900de9da7ea --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/ap.uc @@ -0,0 +1,480 @@ +'use strict'; + +import * as libuci from 'uci'; +import * as fs from 'fs'; + +import { append, append_raw, append_value, append_vars, comment, push_config, set_default, touch_file } from 'wifi.common'; +import * as netifd from 'wifi.netifd'; +import * as iface from 'wifi.iface'; + +function iface_setup(config) { + switch(config.fixup) { + case 'owe': + config.ignore_broadcast_ssid = true; + config.ssid = config.ssid + 'OWE'; + break; + + case 'owe-transition': + let ifname = config.ifname; + config.ifname = config.owe_transition_ifname; + config.owe_transition_ifname = ifname; + config.owe_transition_ssid = config.ssid + 'OWE'; + config.encryption = 'none'; + config.ignore_broadcast_ssid = false; + iface.prepare(config); + break; + } + + comment('Setup interface: ' + config.ifname); + + config.bridge = config.network_bridge; + config.snoop_iface = config.network_ifname; + if (!config.wds) + config.wds_bridge = null; + else + config.wds_sta = true; + + if (!config.idx) + append('interface', config.ifname); + else + append('bss', config.ifname); + + if (config.multicast_to_unicast || config.proxy_arp) + config.ap_isolate = 1; + + append('bssid', config.macaddr); + +append_vars(config, [ + 'ctrl_interface', 'ap_isolate', 'max_num_sta', 'ap_max_inactivity', 'airtime_bss_weight', + 'airtime_bss_limit', 'airtime_sta_weight', 'bss_load_update_period', 'chan_util_avg_period', + 'disassoc_low_ack', 'skip_inactivity_poll', 'ignore_broadcast_ssid', 'uapsd_advertisement_enabled', + 'utf8_ssid', 'multi_ap', 'ssid', 'tdls_prohibit', 'bridge', 'wds_sta', 'wds_bridge', + 'snoop_iface', 'vendor_elements', 'nas_identifier', 'radius_acct_interim_interval', + 'ocv', 'multicast_to_unicast', 'preamble', 'wmm_enabled', 'proxy_arp', 'per_sta_vif', 'mbo', + 'bss_transition', 'wnm_sleep_mode', 'wnm_sleep_mode_no_keys', 'qos_map_set', 'max_listen_int', + 'dtim_period', + ]); +} + +function iface_authentication_server(config) { + for (let server in config.auth_server_addr) { + append('auth_server_addr', server); + append_vars(config, [ 'auth_server_port', 'auth_server_shared_secret' ]); + } + + append_vars(config, [ 'radius_auth_req_attr' ]); +} + +function iface_accounting_server(config) { + for (let server in config.acct_server_addr) { + append('acct_server_addr', server); + append_vars(config, [ 'acct_server_port', 'acct_server_shared_secret' ]); + } + + append_vars(config, [ 'radius_acct_req_attr' ]); +} + +function iface_auth_type(config) { + iface.parse_encryption(config); + + if (config.auth_type in [ 'sae', 'owe', 'eap2', 'eap192' ]) { + config.ieee80211w = 2; + config.sae_require_mfp = 1; + config.sae_pwe = 2; + } + + if (config.auth_type in [ 'psk-sae', 'eap-eap2' ]) { + config.ieee80211w = 1; + config.sae_require_mfp = 1; + config.sae_pwe = 2; + } + + if (config.own_ip_addr) + config.dynamic_own_ip_addr = null; + + if (!config.wpa) + config.wpa_disable_eapol_key_retries = null; + + switch(config.auth_type) { + case 'none': + case 'owe': + config.wps_possible = 1; + config.wps_state = 1; + + if (config.owe_transition_ssid) + config.owe_transition_ssid = `"${config.owe_transition_ssid}"`; + + append_vars(config, [ + 'owe_transition_ssid', 'owe_transition_bssid', 'owe_transition_ifname', + ]); + break; + + case 'psk': + case 'psk2': + case 'sae': + case 'psk-sae': + config.vlan_possible = 1; + config.wps_possible = 1; + + if (config.auth_type == 'psk' && config.ppsk) { + iface_authentication_server(config); + config.macaddr_acl = 2; + config.wpa_psk_radius = 2; + } else if (length(config.key) == 64) { + config.wpa_psk = key; + } else if (length(config.key) >= 8) { + config.wpa_passphrase = config.key; + } else if (!config.wpa_psk_file) { + netifd.setup_failed('INVALID_WPA_PSK'); + } + + set_default(config, 'wpa_psk_file', `/var/run/hostapd-${config.ifname}.psk`); + touch_file(config.wpa_psk_file); + set_default(config, 'dynamic_vlan', 0); + break; + + case 'eap': + case 'eap2': + case 'eap-eap2': + case 'eap192': + config.vlan_possible = 1; + + if (config.fils) { + set_default(config, 'erp_domain', substr(digest.md5(config.ssid), 0, 4)); + set_default(config, 'fils_realm', config.erp_domain); + set_default(config, 'erp_send_reauth_start', 1); + set_default(config, 'fils_cache_id', substr(digest.md5(config.fils_realm), 0, 4)); + } + + if (!config.eap_server) { + iface_authentication_server(config); + iface_accounting_server(config); + } + + if (config.radius_das_client && config.radius_das_secret) { + set_default(config, 'radius_das_port', 3799); + set_default(config, 'radius_das_client', `${config.radius_das_client} ${config.radius_das_secret}`); + } + + set_default(config, 'eapol_version', config.wpa & 1); + if (!config.eapol_version) + config.eapol_version = null; + append('eapol_key_index_workaround', '1'); + append('ieee8021x', '1'); + + break; + } + + append_vars(config, [ + 'sae_require_mfp', 'sae_pwe', 'time_advertisement', 'time_zone', + 'wpa_group_rekey', 'wpa_ptk_rekey', 'wpa_gmk_rekey', 'wpa_strict_rekey', + 'macaddr_acl', 'wpa_psk_radius', 'wpa_psk', 'wpa_passphrase', 'wpa_psk_file', + 'eapol_version', 'dynamic_vlan', 'radius_request_cui', 'eap_reauth_period', + 'radius_das_client', 'radius_das_port', 'own_ip_addr', 'dynamic_own_ip_addr', + 'wpa_disable_eapol_key_retries', 'auth_algs', 'wpa', 'wpa_pairwise', + 'erp_domain', 'fils_realm', 'erp_send_reauth_start', 'fils_cache_id' + ]); +} + +function iface_ppsk(config) { + if (!(config.auth_type in [ 'none', 'owe', 'psk', 'sae', 'psk-sae', 'wep' ]) || !config.auth_server_addr) + return; + + iface_authentication_server(config); + append('macaddr_acl', '2'); +} + +function iface_wps(config) { + push_config(config, 'config_methods', 'wps_pushbutton', 'push_button'); + push_config(config, 'config_methods', 'wps_label', 'label'); + + if (config.multi_ap == 1) + config.wps_possible = false; + + if (config.wps_possible && length(config.config_methods)) { + config.eap_server = 1; + set_default(config, 'wps_state', 2); + + if (config.ext_registrar && config.network_bridge) + set_default(config, 'upnp_iface', config.network_bridge); + + if (config.multi_ap && config.multi_ap_backhaul_ssid) { + append_vars(config, [ 'multi_ap_backhaul_ssid' ]); + if (length(config.multi_ap_backhaul_key) == 64) + append('multi_ap_backhaul_wpa_psk', config.multi_ap_backhaul_key); + else if (length(config.multi_ap_backhaul_key) > 8) + append('multi_ap_backhaul_wpa_passphrase', config.multi_ap_backhaul_key); + else + netifd.setup_failed('INVALID_WPA_PSK'); + } + + append_vars(config, [ + 'wps_state', 'device_type', 'device_name', 'config_methods', 'wps_independent', 'eap_server', + 'ap_pin', 'ap_setup_locked', 'upnp_iface' + ]); + } +} + +function iface_rrm(config) { + set_default(config, 'rrm_neighbor_report', config.ieee80211k); + set_default(config, 'rrm_beacon_report', config.ieee80211k); + + append_vars(config, [ + 'rrm_neighbor_report', 'rrm_beacon_report', 'rnr', 'ftm_responder', + ]); +} + +function iface_ftm(config, phy_features) { + if (!phy_features.ftm_responder || !config.ftm_responder) + return; + + append_vars(config, [ + 'ftm_responder', 'lci', 'civic' + ]); +} + +function iface_macfilter(config) { + let path = `/var/run/hostapd-${config.ifname}.maclist`; + + switch(config.macfilter) { + case 'allow': + append('accept_mac_file', path); + append('macaddr_acl', 1); + config.vlan_possible = 1; + break; + + case 'deny': + append('deny_mac_file', path); + append('macaddr_acl', 0); + break; + + default: + return; + } + + let file = fs.open(path, 'w'); + if (!file) { + warn(`Failed to open ${path}`); + return; + } + + if (config.maclist) + file.write(join('\n', config.maclist)); + + let macfile = fs.readfile(config.macfile); + if (macfile) + file.write(macfile); + file.close(); +} + +function iface_vlan(interface, config, vlans) { + let path = `/var/run/hostapd-${config.ifname}.vlan`; + + let file = fs.open(path, 'w'); + for (let k, vlan in vlans) + if (vlan.config.name && vlan.config.vid) { + let ifname = `${config.ifname}-${vlan.config.name}`; + file.write(`${vlan.config.vid} ${ifname}\n`); + netifd.set_vlan(interface, k, ifname); + } + file.close(); + + set_default(config, 'vlan_file', path); + append_vars(config, [ 'vlan_file' ]); + + if (!config.vlan_possible || !config.dynamic_vlan) + return; + + config.vlan_no_bridge = !config.vlan_bridge; + + append_vars(config, [ + 'dynamic_vlan', 'vlan_naming', 'vlan_bridge', 'vlan_no_bridge', + 'vlan_tagged_interface' + ]); +} + +function iface_stations(config, stas) { + if (!length(stas)) + return; + + let path = `/var/run/hostapd-${config.ifname}.psk`; + + let file = fs.open(path, 'w'); + for (let k, sta in stas) + if (sta.config.mac && sta.config.key) { + let station = `${sta.config.mac} ${sta.config.key}\n`; + if (sta.config.vid) + station = `vlanid=${sta.config.vid} ` + station; + file.write(station); + } + file.close(); + + set_default(config, 'wpa_psk_file', path); +} + +function iface_eap_server(config) { + if (!config.eap_server) + return; + + set_default(config, 'eap_server', true); + set_default(config, 'eap_server_erp', true); + + append_vars(config, [ + 'eap_server', 'eap_server_erp', 'eap_user_file', 'ca_cert', 'server_cert', + 'private_key', 'private_key_passwd', 'server_id', + ]); +} + +function iface_roaming(config) { + if (!config.ieee80211r || config.wpa < 2) + return; + + set_default(config, 'mobility_domain', substr(digest.md5(config.ssid), 0, 4)); + set_default(config, 'ft_psk_generate_local', config.auth_type == 'psk'); + set_default(config, 'ft_iface', config.network_ifname); + + if (config.ft_psk_generate_local) { + if (!config.r0kh || !config.r1kh) { + if (!config.auth_secret && !config.key) + netifd.setup_failed('FT_KEY_CANT_BE_DERIVED'); + + let ft_key = digest.md5(`${mobility_domain}/${auth_secret ?? key}`); + + set_default(config, 'r0kh', 'ff:ff:ff:ff:ff:ff,*,' + ft_key); + set_default(config, 'r1kh', '00:00:00:00:00:00,00:00:00:00:00:00,' + ft_key); + } + + append_vars(config, [ + 'r0kh', 'r1kh', 'r1_key_holder', 'r0_key_lifetime', 'pmk_r1_push' + ]); + } + + append_vars(config, [ + 'mobility_domain', 'ft_psk_generate_local', 'ft_over_ds', 'reassociation_deadline', + 'ft_iface' + ]); +} + +function iface_mfp(config) { + if (!config.ieee80211w || config.wpa < 2) { + append('ieee80211w', 0); + return; + } + + if (config.auth_type == 'eap192') + config.group_mgmt_cipher = 'BIP-GMAC-256'; + else + config.group_mgmt_cipher = config.ieee80211w_mgmt_cipher ?? 'AES-128-CMAC'; + + append_vars(config, [ + 'ieee80211w', 'group_mgmt_cipher', 'assoc_sa_query_max_timeout', 'assoc_sa_query_retry_timeout' + ]); +} + +function iface_key_caching(config) { + if (config.wpa < 2) + return; + + if (config.network_bridge && config.rsn_preauth) { + set_default(config, 'okc', true); + config.rsn_preauth_interfaces = config.network_bridge; + + append_vars(config, [ + 'rsn_preauth', 'rsn_preauth_interfaces' + ]); + } else { + set_default(config, 'okc', (config.auth_type in [ 'sae', 'psk-sae', 'owe' ])); + } + + if (!config.okc && !config.fils) + config.disable_pmksa_caching = 1; + + append_vars(config, [ + 'okc', 'disable_pmksa_caching' + ]); +} + +function iface_hs20(config) { + if (!config.hs20) + return; + + let uci = libuci.cursor(); + let icons = uci.get_all('wireless'); + for (let k, icon in icons) + if (icon['.type'] == 'hs20-icon') + append('hs20_icon', `${icon.width}:${icon.heigth}:${icon.lang}:${icon.type}:${k}:${icon.path}`); + + append_vars(config, [ + 'hs20', 'disable_dgaf', 'osen', 'anqp_domain_id', 'hs20_deauth_req_timeout', 'osu_ssid', + 'hs20_wan_metrics', 'hs20_operating_class', 'hs20_t_c_filename', 'hs20_t_c_timestamp', + 'hs20_t_c_server_url', 'hs20_oper_friendly_name', 'hs20_conn_capab', 'osu_provider', + 'operator_icon' + ]); +} + +function iface_interworking(config) { + if (!config.iw_enabled) + return; + + config.interworking = true; + + if (config.domain_name) + config.domain_name = join(',', config.domain_name); + + if (config.anqp_3gpp_cell_net) + config.domain_name = join(',', config.anqp_3gpp_cell_net); + + append_vars(config, [ + 'interworking', 'internet', 'asra', 'uesa', 'access_network_type', 'hessid', 'venue_group', + 'venue_type', 'network_auth_type', 'gas_address3', 'roaming_consortium', 'anqp_elem', 'nai_realm', + 'venue_name', 'venue_url', 'domain_name', 'anqp_3gpp_cell_net', + ]); +} + +export function generate(interface, config, vlans, stas, phy_features) { + config.ctrl_interface = '/var/run/hostapd'; + + iface_stations(config, stas); + + iface_setup(config); + + iface_auth_type(config); + + iface_accounting_server(config); + + iface_ppsk(config); + + iface_wps(config); + + iface_rrm(config); + + iface_ftm(config, phy_features); + + iface_macfilter(config); + + iface_vlan(interface, config, vlans); + + iface_eap_server(config); + + iface_roaming(config); + + iface_mfp(config); + + iface_key_caching(config); + + iface_hs20(config); + + iface_interworking(config); + + iface.wpa_key_mgmt(config); + append_vars(config, [ + 'wpa_key_mgmt' + ]); + + /* raw options */ + for (let raw in config.hostapd_options) + append_raw(raw); + + if (config.default_macaddr) + append_raw('#default_macaddr'); +}; diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/common.uc b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/common.uc new file mode 100644 index 00000000000000..a4d7eb3ed75892 --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/common.uc @@ -0,0 +1,124 @@ +'use strict'; + +import * as libubus from 'ubus'; +import * as fs from 'fs'; + +global.ubus = libubus.connect(); + +let config_data = ''; +let network_data = ''; + +export function log(msg) { + printf(`wifi-scripts: ${msg}\n`); +}; + +export function append_raw(value) { + config_data += value + '\n'; +}; + +export function append(key, value) { + if (value == null) + return; + + switch (type(value)) { + case 'array': + value = join(' ', value); + break; + case 'bool': + value = value ? 1 : 0; + break; + } + + append_raw(key + '=' + value); +}; + +export function append_vars(dict, keys) { + for (let key in keys) + append(key, dict[key]); +}; + +export function network_append_raw(value) { + network_data += value + '\n'; +}; + +export function network_append(key, value) { + if (value == null) + return; + + switch (type(value)) { + case 'array': + value = join(' ', value); + break; + case 'bool': + value = value ? 1 : 0; + break; + } + + network_append_raw('\t' + key + '=' + value); +}; + +export function network_append_vars(dict, keys) { + for (let key in keys) + network_append(key, dict[key]); +}; + +export function set_default(dict, key, value) { + if (dict[key] == null) + dict[key] = value; +}; + +export function push_config(dict, key, option, value) { + if (!dict[option]) + return; + + dict[key] ??= []; + push(dict[key], value); +}; + +export function touch_file(filename) { + let file = fs.open(filename, "a"); + if (file) + file.close(); + else + log('Failed to touch ' + filename); +}; + +export function append_value(config, key, value) { + if (!config[key]) + config[key] = value; + else + config[key] += ' ' + value; +}; + +export function comment(comment) { + append_raw('\n# ' + comment); +}; + +export function dump_config(file) { + if (file) + fs.writefile(file, config_data); + + return config_data; +}; + +export function dump_network(file) { + config_data += 'network={\n'; + config_data += network_data;; + config_data += '}\n'; + + if (file) + fs.writefile(file, config_data); + + printf('%s\n', config_data); + + return config_data; +}; + +export function flush_config() { + config_data = ''; +}; + +export function flush_network() { + config_data = ''; + network_data = ''; +}; diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/hostapd.uc b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/hostapd.uc new file mode 100644 index 00000000000000..a17f6b547435d3 --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/hostapd.uc @@ -0,0 +1,577 @@ +'use strict'; + +import { append, append_raw, append_vars, dump_config, flush_config, set_default } from 'wifi.common'; +import { validate } from 'wifi.validate'; +import * as netifd from 'wifi.netifd'; +import * as iface from 'wifi.iface'; +import * as nl80211 from 'nl80211'; +import * as ap from 'wifi.ap'; +import * as fs from 'fs'; + +const NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER = 33; +const NL80211_EXT_FEATURE_RADAR_BACKGROUND = 61; + +let phy_features = {}; +let phy_capabilities = {}; + +/* make sure old style UCI and hwmode and newer band properties are correctly resolved */ +function set_device_defaults(config) { + /* validate the hw mode */ + if (config.hwmode in [ '11a', '11b', '11g', '11ad' ]) + config.hw_mode = substr(config.hwmode, 2); + else if (config.channel > 14) + config.hw_mode = 'a'; + else + config.hw_mode = 'g'; + + /* validate band */ + if (config.band == '2g') + config.hw_mode = 'g'; + else if (config.band in [ '5g', '6g', '60g' ]) + config.hw_mode = 'a'; + else + switch (config.hw_mode) { + case 'a': + config.band = '5g'; + break; + + case 'ad': + config.band = '60g'; + break; + + default: + config.band = '2g'; + break; + } +} + +/* setup sylog / stdout */ +function device_log_append(config) { + let log_mask = 0; + + for (let k in [ 'log_mlme', 'log_iapp', 'log_driver', 'log_wpa', 'log_radius', 'log_8021x', 'log_80211' ]) { + log_mask <<= 1; + log_mask |= config[k] ? 1 : 0; + } + + append('logger_syslog', log_mask); + append('logger_syslog_level', config.log_level); + append('logger_stdout', log_mask); + append('logger_stdout_level', config.log_level); +} + +/* setup country code */ +function device_country_code(config) { + let status = global.ubus.call('network.wireless', 'status'); + for (let name, radio in status) { + if (!radio.config.country) + continue; + config.country_code = radio.config.country; + } + + if (!exists(config, 'country_code')) + return; + + if (config.hw_mode != 'a') + delete config.ieee80211h; + append_vars(config, [ 'country_code', 'country3', 'ieee80211h' ]); + if (config.ieee80211d) + append_vars(config, [ 'ieee80211d', 'local_pwr_constraint', 'spectrum_mgmt_required' ]); +} + + +/* setup cell density */ +function device_cell_density_append(config) { + switch (config.hw_mode) { + case 'b': + if (config.cell_density == 1) { + config.supported_rates = [ 5500, 11000 ]; + config.basic_rates = [ 5500, 11000 ]; + } else if (config.cell_density > 2) { + config.supported_rates = [ 11000 ]; + config.basic_rates = [ 11000 ]; + } + ;; + case 'g': + if (config.cell_density in [ 0, 1 ]) { + if (!config.legacy_rates) { + config.supported_rates = [ 6000, 9000, 12000, 18000, 24000, 36000, 48000, 54000 ]; + config.basic_rates = [ 6000, 12000, 24000 ]; + } else if (config.cell_density == 1) { + config.supported_rates = [ 5500, 6000, 9000, 11000, 12000, 18000, 24000, 36000, 48000, 54000 ]; + config.basic_rates = [ 5500, 11000 ]; + } + } else if (config.cell_density == 2 || (config.cell_density > 3 && config.legacy_rates)) { + if (!config.legacy_rates) { + config.supported_rates = [ 12000, 18000, 24000, 36000, 48000, 54000 ]; + config.basic_rates = [ 12000, 24000 ]; + } else { + config.supported_rates = [ 11000, 12000, 18000, 24000, 36000, 48000, 54000 ]; + config.basic_rates = [ 11000 ]; + } + } else if (config.cell_density > 2) { + config.supported_rates = [ 24000, 36000, 48000, 54000 ]; + config.basic_rates = [ 24000 ]; + } + ;; + case 'a': + switch (config.cell_density) { + case 1: + config.supported_rates = [ 6000, 9000, 12000, 18000, 24000, 36000, 48000, 54000 ]; + config.basic_rates = [ 6000, 12000, 24000 ]; + break; + + case 2: + config.supported_rates = [ 12000, 18000, 24000, 36000, 48000, 54000 ]; + config.basic_rates = [ 12000, 24000 ]; + break; + + case 3: + config.supported_rates = [ 24000, 36000, 48000, 54000 ]; + config.basic_rates = [ 24000 ]; + break; + } + } +} + +function device_rates(config) { + for (let key in [ 'supported_rates', 'basic_rates' ]) + config[key] = map(config[key], x => x / 100); + + append_vars(config, [ 'beacon_rate', 'supported_rates', 'basic_rates' ]); +} + +function device_htmode_append(config) { + config.channel_offset = config.band == '6g' ? 1 : 0; + + /* 802.11n */ + config.ieee80211n = 0; + if (config.band != '6g') { + if (config.htmode in [ 'VHT20', 'HT20', 'HE20', 'EHT20' ]) + config.ieee80211n = 1; + if (config.htmode in [ 'HT40', 'HT40+', 'HT40-', 'VHT40', 'VHT80', 'VHT160', 'HE40', 'HE80', 'HE160', 'EHT40', 'EHT80', 'EHT160' ]) { + config.ieee80211n = 1; + if (!config.channel) + config.ht_capab = '[HT40+]'; + else + switch (config.hw_mode) { + case 'a': + switch (((config.channel / 4) + config.channel_offset) % 2) { + case 0: + config.ht_capab = '[HT40-]'; + break; + + case 1: + config.ht_capab = '[HT40+]'; + break; + } + break; + + default: + switch (config.htmode) { + case 'HT40+': + case 'HT40-': + config.ht_capab = '[' + config.htmode + ']'; + break; + + default: + if (config.channel < 7) + config.ht_capab = '[HT40+]'; + else + config.ht_capab = '[HT40-]'; + break; + } + } + } + + if (config.ieee80211n) { + let ht_capab = phy_capabilities.ht_capa; + + if (ht_capab & 0x1 && config.ldpc) + config.ht_capab += '[LDPC]'; + if (ht_capab & 0x10 && config.greenfield) + config.ht_capab += '[GF]'; + if (ht_capab & 0x20 && config.short_gi_20) + config.ht_capab += '[SHORT-GI-20]'; + if (ht_capab & 0x40 && config.short_gi_40) + config.ht_capab += '[SHORT-GI-40]'; + if (ht_capab & 0x80 && config.tx_stbc) + config.ht_capab += '[TX-STBC]'; + if (ht_capab & 0x800 && config.max_amsdu) + config.ht_capab += '[MAX-AMSDU-7935]'; + if (ht_capab & 0x1000 && config.dsss_cck_40) + config.ht_capab += '[DSSS_CCK-40]'; + let rx_stbc = [ '', '[RX-STBC1]', '[RX-STBC12]', '[RX-STBC123]' ]; + config.ht_capab += rx_stbc[min(config.rx_stbc, (ht_capab >> 8) & 3)]; + + append_vars(config, [ 'ieee80211n', 'ht_coex', 'ht_capab' ]); + } + } + + /* 802.11ac */ + config.ieee80211ac = 1; + config.vht_oper_centr_freq_seg0_idx = 0; + config.vht_oper_chwidth = 0; + + switch (config.htmode) { + case 'VHT20': + case 'HE20': + case 'EHT20': + break; + + case 'VHT40': + case 'HE40': + case 'EHT40': + config.vht_oper_centr_freq_seg0_idx = config.channel + (((config.channel / 4) + config.channel_offset) % 2 ? 2 : -2); + break; + + case 'VHT80': + case 'HE80': + case 'EHT80': + let delta = [ -6, 6, 2, -2 ]; + config.vht_oper_centr_freq_seg0_idx = config.channel + delta[((config.channel / 4) + config.channel_offset) % 4]; + config.vht_oper_chwidth = 1; + break; + + case 'VHT160': + case 'HE160': + case 'EHT160': + let vht_oper_centr_freq_seg0_idx_map = [[ 64, 50 ], [ 128, 114 ], [ 177, 163 ]]; + if (config.band == '6g') + vht_oper_centr_freq_seg0_idx_map = [ + [ 29, 15 ], [ 61, 47 ], [ 93, 79 ], [ 125, 111 ], + [ 157, 143 ], [ 189, 175 ], [ 221, 207 ]]; + for (let k, v in vht_oper_centr_freq_seg0_idx_map) + if (v[0] <= config.channel) { + config.vht_oper_centr_freq_seg0_idx = v[1]; + break; + } + config.vht_oper_chwidth = 2; + break; + + default: + config.ieee80211ac = 0; + break; + } + + config.eht_oper_chwidth = config.vht_oper_chwidth; + config.eht_oper_centr_freq_seg0_idx = config.vht_oper_centr_freq_seg0_idx; + + if (config.band == '6g') { + config.ieee80211ac = 0; + + switch(config.htmode) { + case 'HE20': + case 'EHT20': + config.op_class = 131; + break; + + case 'EHT320': + let eht_center_seg0_map = [ + [ 61, 31 ], [ 125, 95 ], [ 189, 159 ], [ 221, 191 ] + ]; + + for (let k, v in eht_center_seg0_map) + if (v[0] <= config.channel) { + config.eht_oper_centr_freq_seg0_idx = v[1]; + break; + } + config.op_class = 137; + config.eht_oper_chwidth = 7; + break; + + case 'HE40': + case 'HE80': + case 'HE160': + case 'EHT40': + case 'EHT80': + case 'EHT160': + config.op_class = 132 + config.eht_oper_chwidth; + break; + } + + append_vars(config, [ 'op_class' ]); + } + + if (config.ieee80211ac && config.hw_mode == 'a') { + /* VHT capab */ + if (config.vht_oper_chwidth < 2) { + config.vht160 = 0; + config.short_gi_160 = 0; + } + + config.tx_queue_data2_burst = '2.0'; + + let vht_capab = phy_capabilities.vht_capa; + + config.vht_capab = ''; + if (vht_capab & 0x10 && config.rxldpc) + config.vht_capab += '[RXLDPC]'; + if (vht_capab & 0x20 && config.short_gi_80) + config.vht_capab += '[SHORT-GI-80]'; + if (vht_capab & 0x40 && config.short_gi_160) + config.vht_capab += '[SHORT-GI-160]'; + if (vht_capab & 0x80 && config.tx_stbc_2by1) + config.vht_capab += '[TX-STBC-2BY1]'; + if (vht_capab & 0x800 && config.su_beamformer) + config.vht_capab += '[SU-BEAMFORMER]'; + if (vht_capab & 0x1000 && config.su_beamformee) + config.vht_capab += '[SU-BEAMFORMEE]'; + if (vht_capab & 0x80000 && config.mu_beamformer) + config.vht_capab += '[MU-BEAMFORMER]'; + if (vht_capab & 0x100000 && config.mu_beamformee) + config.vht_capab += '[MU-BEAMFORMEE]'; + if (vht_capab & 0x200000 && config.vht_txop_ps) + config.vht_capab += '[VHT-TXOP-PS]'; + if (vht_capab & 0x400000 && config.htc_vht) + config.vht_capab += '[HTC-VHT]'; + if (vht_capab & 0x10000000 && config.rx_antenna_pattern) + config.vht_capab += '[RX-ANTENNA-PATTERN]'; + if (vht_capab & 0x20000000 && config.tx_antenna_pattern) + config.vht_capab += '[TX-ANTENNA-PATTERN]'; + let rx_stbc = [ '', '[RX-STBC1]', '[RX-STBC12]', '[RX-STBC123]', '[RX-STBC-1234]' ]; + config.vht_capab += rx_stbc[min(config.rx_stbc, (vht_capab >> 8) & 7)]; + + if (vht_capab & 0x800 && config.su_beamformer) + config.vht_capab += '[SOUNDING-DIMENSION' + min(((vht_capab >> 16) & 3) + 1, config.beamformer_antennas) + ']'; + if (vht_capab & 0x1000 && config.su_beamformee) + config.vht_capab += '[BF-ANTENNA-' + min(((vht_capab >> 13) & 3) + 1, config.beamformer_antennas) + ']'; + + /* supported Channel widths */ + if (vht_capab & 0xc == 8 && config.vht160 <= 2) + config.vht_capab += '[VHT160-80PLUS80]'; + else if (vht_capab & 0xc == 4 && config.vht160 <= 1) + config.vht_capab += '[VHT160]'; + + /* maximum MPDU length */ + if (vht_capab & 3 > 1 && config.vht_max_mpdu > 11454) + config.vht_capab += '[MAX-MPDU-11454]'; + else if (vht_capab & 3 && config.vht_max_mpdu > 7991) + config.vht_capab += '[MAX-MPDU-7991]'; + + /* maximum A-MPDU length exponent */ + let max_a_mpdu_len_exp = (vht_capab >> 20) & 0x38; + for (let exp = 7; exp; exp--) + if (max_a_mpdu_len_exp >= (0x8 * exp) && exp <= config.vht_max_a_mpdu_len_exp) { + config.vht_capab += '[MAX-A-MPDU-LEN-EXP' + exp + ']'; + break; + } + + /* whether or not the STA supports link adaptation using VHT variant */ + let vht_link_adapt = vht_capab & 0xC000000; + if (vht_link_adapt >= 0xC000000 && config.vht_link_adapt > 3) + config.vht_capab += '[VHT-LINK-ADAPT-3]'; + if (vht_link_adapt >= 0x8000000 && config.vht_link_adapt > 2) + config.vht_capab += '[VHT-LINK-ADAPT-2]'; + + append_vars(config, [ + 'ieee80211ac', 'vht_oper_chwidth', 'vht_oper_centr_freq_seg0_idx', + 'vht_capab' + ]); + } + + /* 802.11ax */ + if (wildcard(config.htmode, 'HE*') || wildcard(config.htmode, 'EHT*')) { + let he_phy_cap = phy_capabilities.he_phy_cap; + let he_mac_cap = phy_capabilities.he_mac_cap; + + config.ieee80211ax = true; + + if (config.hw_mode == 'a') { + config.he_oper_chwidth = config.vht_oper_chwidth; + config.he_oper_centr_freq_seg0_idx = config.vht_oper_centr_freq_seg0_idx; + } + + if (config.he_bss_color_enabled) { + if (config.he_spr_non_srg_obss_pd_max_offset) + config.he_spr_sr_control |= 1 << 2; + if (!config.he_spr_psr_enabled) + config.he_spr_sr_control |= 1; + append_vars(config, [ 'he_bss_color', 'he_spr_non_srg_obss_pd_max_offset', 'he_spr_sr_control' ]); + } + + if (!(he_phy_cap[3] & 0x80)) + config.he_su_beamformer = false; + if (!(he_phy_cap[4] & 0x1)) + config.he_su_beamformee = false; + if (!(he_phy_cap[4] & 0x2)) + config.he_mu_beamformer = false; + if (!(he_phy_cap[7] & 0x1)) + config.he_spr_psr_enabled = false; + if (!(he_mac_cap[0] & 0x1)) + config.he_twt_required= false; + + append_vars(config, [ + 'ieee80211ax', 'he_oper_chwidth', 'he_oper_centr_freq_seg0_idx', + 'he_su_beamformer', 'he_su_beamformee', 'he_mu_beamformer', 'he_twt_required', + 'he_default_pe_duration', 'he_rts_threshold', 'he_mu_edca_qos_info_param_count', + 'he_mu_edca_qos_info_q_ack', 'he_mu_edca_qos_info_queue_request', 'he_mu_edca_qos_info_txop_request', + 'he_mu_edca_ac_be_aifsn', 'he_mu_edca_ac_be_aci', 'he_mu_edca_ac_be_ecwmin', + 'he_mu_edca_ac_be_ecwmax', 'he_mu_edca_ac_be_timer', 'he_mu_edca_ac_bk_aifsn', + 'he_mu_edca_ac_bk_aci', 'he_mu_edca_ac_bk_ecwmin', 'he_mu_edca_ac_bk_ecwmax', + 'he_mu_edca_ac_bk_timer', 'he_mu_edca_ac_vi_ecwmin', 'he_mu_edca_ac_vi_ecwmax', + 'he_mu_edca_ac_vi_aifsn', 'he_mu_edca_ac_vi_aci', 'he_mu_edca_ac_vi_timer', + 'he_mu_edca_ac_vo_aifsn', 'he_mu_edca_ac_vo_aci', 'he_mu_edca_ac_vo_ecwmin', + 'he_mu_edca_ac_vo_ecwmax', 'he_mu_edca_ac_vo_timer', + ]); + } + + if (wildcard(config.htmode, 'EHT*')) { + config.ieee80211be = true; + append_vars(config, [ 'ieee80211be' ]); + + if (config.hw_mode == 'a') + append_vars(config, [ 'eht_oper_chwidth', 'eht_oper_centr_freq_seg0_idx' ]); + + if (config.band == "6g") { + config.stationary_ap = true; + append_vars(config, [ 'he_6ghz_reg_pwr_type', ]); + } + } + + append_vars(config, [ 'tx_queue_data2_burst', 'stationary_ap' ]); +} + +function device_extended_features(data, flag) { + return !!(data[flag / 8] | (1 << (flag % 8))); +} + +function device_capabilities(phy) { + let idx = +substr(phy, 3, 1);; + let phys = nl80211.request(nl80211.const.NL80211_CMD_GET_WIPHY, nl80211.const.NLM_F_DUMP, { wiphy: idx, split_wiphy_dump: true }); + + for (let phy in phys) { + if (!phy || phy.wiphy != idx) + continue; + for (let band in phy.wiphy_bands) { + if (!band) + continue; + phy_capabilities.ht_capa = band.ht_capa ?? 0; + phy_capabilities.vht_capa = band.vht_capa ?? 0; + for (let iftype in band.iftype_data) { + if (!iftype.iftypes.ap) + continue; + phy_capabilities.he_mac_cap = iftype.he_cap_mac; + phy_capabilities.he_phy_cap = iftype.he_cap_phy; + } + break; + } + + phy_features.ftm_responder = device_extended_features(phy.extended_features, NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER); + phy_features.radar_background = device_extended_features(phy.extended_features, NL80211_EXT_FEATURE_RADAR_BACKGROUND); + break; + } +} + +function generate(config) { + if (!config.phy) + die(`${config.path} is an unknown phy`); + + device_capabilities(config.phy); + + append('driver', 'nl80211'); + + set_device_defaults(config); + + device_log_append(config); + + device_country_code(config); + + device_cell_density_append(config); + + device_rates(config); + + /* beacon */ + append_vars(config, [ 'beacon_int', 'beacon_rate', 'rnr_beacon', 'mbssid' ]); + + /* wpa_supplicant co-exist */ + append_vars(config, [ 'noscan' ]); + + /* airtime */ + append_vars(config, [ 'airtime_mode' ]); + + /* assoc/thresholds */ + append_vars(config, [ 'rssi_reject_assoc_rssi', 'rssi_ignore_probe_request', 'iface_max_num_sta', 'no_probe_resp_if_max_sta' ]); + + /* ACS / Radar*/ + if (!phy_features.radar_background || config.band != '5g') + delete config.enable_background_radar; + else + set_default(config, 'enable_background_radar', phy_features.radar_background); + + append_vars(config, [ 'acs_chan_bias', 'acs_exclude_dfs', 'enable_background_radar' ]); + + /* TX Power */ + append_vars(config, [ 'min_tx_power' ]); + + /* hwmode, channel, op_class, ... */ + append_vars(config, [ 'hw_mode', 'channel', 'rts_threshold', 'chanlist' ]); + if (config.hw_mode in [ 'a', 'g' ] && config.require_mode in [ 'n', 'ac', 'ax' ]) { + let require_mode = { n: 'require_ht', ac: 'require_vht', ax: 'require_he' }; + + config.legacy_rates = false; + append(require_mode[config.require_mode], 1); + } + device_htmode_append(config); + + /* 6G power mode */ + if (config.band != '6g') + append_vars(config, [ 'reg_power_type' ]); + + /* raw options */ + for (let raw in config.hostapd_options) + append_raw(raw); +} + +let iface_idx = 0; +function setup_interface(interface, config, vlans, stas, phy_features, fixup) { + config = { ...config, fixup }; + + config.idx = iface_idx++; + ap.generate(interface, config, vlans, stas, phy_features); +} + +export function setup(data) { + let file_name = `/var/run/hostapd-${data.phy}${data.vif_phy_suffix}.conf`; + + flush_config(); + + if (fs.stat(file_name)) + fs.rename(file_name, file_name + '.prev'); + + data.config.phy = data.phy; + + generate(data.config); + + if (data.config.num_global_macaddr) + append('\n#num_global_macaddr', data.config.num_global_macaddr); + + for (let k, interface in data.interfaces) { + if (interface.config.mode != 'ap') + continue; + + interface.config.network_bridge = interface.bridge; + interface.config.network_ifname = interface['bridge-ifname']; + + let owe = interface.config.encryption == 'owe' && interface.config.owe_transition; + + setup_interface(k, interface.config, interface.vlans, interface.stas, phy_features, owe ? 'owe' : null ); + if (owe) + setup_interface(k, interface.config, interface.vlans, interface.stas, phy_features, 'owe-transition'); + } + + let config = dump_config(file_name); + + let msg = { + phy: data.phy, + radio: data.config.radio, + config: file_name, + prev_config: file_name + '.prev' + }; + let ret = global.ubus.call('hostapd', 'config_set', msg); + + if (ret) + netifd.add_process('/usr/sbin/hostapd', ret.pid, true, true); + else + netifd.setup_failed('HOSTAPD_START_FAILED'); +}; diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/iface.uc b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/iface.uc new file mode 100644 index 00000000000000..3c15d87d003f84 --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/iface.uc @@ -0,0 +1,194 @@ +'use strict'; + +import { append_value, log } from 'wifi.common'; +import * as fs from 'fs'; + +export function parse_encryption(config) { + let encryption = split(config.encryption, '+', 2); + + config.wpa_pairwise = (config.hwmode == 'ad') ? 'GCMP' : 'CCMP'; + + switch(encryption[1]){ + case 'tkip+aes': + case 'tkip+ccmp': + case 'aes+tkip': + case 'ccmp+tkip': + config.wpa_pairwise = 'CCMP TKIP'; + break; + + case 'ccmp256': + config.wpa_pairwise = 'CCMP-256'; + break; + + case 'aes': + case 'ccmp': + config.wpa_pairwise = 'CCMP'; + break; + + case 'tkip': + config.wpa_pairwise = 'TKIP'; + break; + + case 'gcmp256': + config.wpa_pairwise = 'GCMP-256'; + break; + + case 'gcmp': + config.wpa_pairwise = 'GCMP'; + break; + + default: + if (config.encryption == 'wpa3-192') + config.wpa_pairwise = 'GCMP-256'; + break; + } + + config.wpa = 0; + for (let k, v in { 'wpa2*': 2, 'wpa3*': 2, '*psk2*': 2, 'psk3*': 2, 'sae*': 2, + 'owe*': 2, 'wpa*mixed*': 3, '*psk*mixed*': 3, 'wpa*': 1, '*psk*': 1, }) + if (wildcard(config.encryption, k)) { + config.wpa = v; + break; + } + if (!config.wpa) + config.wpa_pairwise = null; + + config.auth_type = encryption[0] ?? 'none'; + switch(config.auth_type) { + case 'owe': + config.auth_type = 'owe'; + break; + + case 'wpa3-192': + config.auth_type = 'eap192'; + break; + + case 'wpa3-mixed': + config.auth_type = 'eap-eap2'; + break; + + case 'wpa3': + config.auth_type = 'eap2'; + break; + + case 'sae-mixed': + config.auth_type = 'psk-sae'; + break; + + case 'wpa': + case 'wpa2': + config.auth_type = 'eap'; + break; + } +}; + +export function wpa_key_mgmt(config) { + if (!config.wpa) + return; + + switch(config.auth_type) { + case 'psk': + case 'psk2': + append_value(config, 'wpa_key_mgmt', 'WPA-PSK'); + if (config.wpa >= 2 && config.ieee80211r) + append_value(config, 'wpa_key_mgmt', 'FT-PSK'); + if (config.ieee80211w) + append_value(config, 'wpa_key_mgmt', 'WPA-PSK-SHA256'); + break; + + case 'eap': + append_value(config, 'wpa_key_mgmt', 'WPA-EAP'); + if (config.wpa >= 2 && config.ieee80211r) + append_value(config, 'wpa_key_mgmt', 'FT-EAP'); + if (config.ieee80211w) + append_value(config, 'wpa_key_mgmt', 'WPA-EAP--SHA256'); + break; + + case 'eap192': + append_value(config, 'wpa_key_mgmt', 'WPA-EAP-SUITE-B-192'); + if (config.ieee80211r) + append_value(config, 'wpa_key_mgmt', 'FT-EAP-SHA384'); + break; + + case 'eap-eap2': + append_value(config, 'wpa_key_mgmt', 'WPA-EAP'); + append_value(config, 'wpa_key_mgmt', 'WPA-EAP-SHA256'); + if (config.ieee80211r) + append_value(config, 'wpa_key_mgmt', 'FT-EAP'); + break; + + case 'eap2': + append_value(config, 'wpa_key_mgmt', 'WPA-EAP-SHA256'); + if (config.ieee80211r) + append_value(config, 'wpa_key_mgmt', 'FT-EAP'); + break; + + case 'sae': + append_value(config, 'wpa_key_mgmt', 'SAE'); + if (config.ieee80211r) + append_value(config, 'wpa_key_mgmt', 'FT-SAE'); + break; + + case 'psk-sae': + append_value(config, 'wpa_key_mgmt', 'WPA-PSK'); + append_value(config, 'wpa_key_mgmt', 'SAE'); + if (config.ieee80211w) + append_value(config, 'wpa_key_mgmt', 'WPA-PSK-SHA256'); + if (config.ieee80211r) { + append_value(config, 'wpa_key_mgmt', 'FT-PSK'); + append_value(config, 'wpa_key_mgmt', 'FT-SAE'); + } + break; + + case 'owe': + append_value(config, 'wpa_key_mgmt', 'OWE'); + break; + } + + if (config.fils) { + switch(config.auth_type) { + case 'eap192': + append_value(config, 'wpa_key_mgmt', 'FILS-SHA384'); + if (config.ieee80211r) + append_value(config, 'wpa_key_mgmt', 'FT-FILS-SHA384'); + break; + + case 'eap-eap2': + case 'eap2': + case 'eap': + append_value(config, 'wpa_key_mgmt', 'FILS-SHA256'); + if (config.ieee80211r) + append_value(config, 'wpa_key_mgmt', 'FT-FILS-SHA256'); + break; + } + } + + config.key_mgmt = config.wpa_key_mgmt; +}; + +function macaddr_random() { + let f = open("/dev/urandom", "r"); + let addr = f.read(6); + + addr = map(split(addr, ""), (v) => ord(v)); + addr[0] &= ~1; + addr[0] |= 2; + + return join(":", map(addr, (v) => sprintf("%02x", v))); +} + +let mac_idx = 0; +export function prepare(data, phy, num_global_macaddr) { + if (!data.macaddr) { + let pipe = fs.popen(`ucode /usr/share/hostap/wdev.uc ${phy} get_macaddr id=${mac_idx} num_global=${num_global_macaddr} mbssid=${data.mbssid ?? 0}`); + + data.macaddr = trim(pipe.read("all"), '\n'); + pipe.close(); + + data.default_macaddr = true; + mac_idx++; + } else if (data.macaddr == 'random') + data.macaddr = macaddr_random(); + + log(`Preparing interface: ${data.ifname} with MAC: ${data.macaddr}`); +}; diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/netifd.uc b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/netifd.uc new file mode 100644 index 00000000000000..5a4a9fafb37f25 --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/netifd.uc @@ -0,0 +1,49 @@ +'use strict'; + +import { log } from 'wifi.common'; +import * as fs from 'fs'; + +const CMD_UP = 0; +const CMD_SET_DATA = 1; +const CMD_PROCESS_ADD = 2; +const CMD_PROCESS_KILL_ALL = 3; +const CMD_SET_RETRY = 4; + +export function notify(command, params, data) { + params ??= {}; + data ??= {}; + + global.ubus.call('network.wireless', 'notify', { command, device: global.radio, ...params, data }); +}; + +export function set_up() { + notify(CMD_UP); +}; + +export function set_data(data) { + notify(CMD_SET_DATA, null, data); +}; + +export function add_process(exe, pid, required, keep) { + exe = fs.realpath(exe); + + notify(CMD_PROCESS_ADD, null, { pid, exe, required, keep }); +}; + +export function set_retry(retry) { + notify(CMD_SET_RETRY, null, { retry }); +}; + +export function set_vif(interface, ifname) { + notify(CMD_SET_DATA, { interface }, { ifname }); +}; + +export function set_vlan(interface, ifname, vlan) { + notify(CMD_SET_DATA, { interface, vlan }, { ifname }); +}; + +export function setup_failed(reason) { + log(`Device setup failed: ${reason}`); + printf('%s\n', reason); + set_retry(false); +}; diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/supplicant.uc b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/supplicant.uc new file mode 100644 index 00000000000000..04d7f216aa68a7 --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/supplicant.uc @@ -0,0 +1,237 @@ +'use strict'; + +import { append, append_raw, append_vars, network_append, network_append_raw, network_append_vars, + set_default, dump_network, flush_network } from 'wifi.common'; +import * as netifd from 'wifi.netifd'; +import * as iface from 'wifi.iface'; +import * as fs from 'fs'; + +function set_fixed_freq(data, config) { + if (!data.frequency) + return; + + set_default(config, 'fixed_freq', 1); + set_default(config, 'frequency', data.frequency); + + if (data.htmode in [ 'VHT80', 'HE80' ]) + set_default(config, 'max_oper_chwidth', 1); + else if (data.htmode in [ 'VHT160', 'HE160' ]) + set_default(config, 'max_oper_chwidth', 2); + else if (data.htmode in [ 'VHT20', 'VHT40', 'HE20', 'HE40' ]) + set_default(config, 'max_oper_chwidth', 0); + else + set_default(config, 'disable_vht', true); + + if (data.htmode in [ 'NOHT' ]) + set_default(config, 'disable_ht', true); + else if (data.htmode in [ 'HT20', 'VHT20', 'HE20' ]) + set_default(config, 'disable_ht40', true); + else if (data.htmode in [ 'VHT40', 'VHT80', 'VHT160', 'HE40', 'HE80', 'HE160' ]) + set_default(config, 'ht40', true); + + if (wildcard(data.htmode, 'VHT*')) + set_default(config, 'vht', 1); +} + +export function ratestr(rate) { + if (rate == null) + return rate; + + let rem = (rate / 100) % 10; + rate = int(rate / 1000); + if (rem > 0) + rate += "." + rem; + + return "" + rate; +}; + +export function ratelist(rates) { + if (length(rates) < 1) + return null; + + return join(",", map(rates, (rate) => ratestr(rate))); +}; + +function setup_sta(data, config) { + iface.parse_encryption(config); + + if (config.auth_type in [ 'sae', 'owe', 'eap2', 'eap192' ]) + set_default(config, 'ieee80211w', 2); + else if (config.auth_type in [ 'psk-sae' ]) + set_default(config, 'ieee80211w', 1); + + set_default(config, 'ieee80211r', 0); + set_default(config, 'multi_ap', 0); + set_default(config, 'default_disabled', 0); + +//multiap_flag_file="${_config}.is_multiap" + config.scan_ssid = 1; + + switch(config.mode) { + case 'sta': + set_default(config, 'multi_ap_backhaul_sta', config.multi_ap); + break; + + case 'adhoc': + config.ap_scan = 2; + config.scan_ssid = 0; + network_append('mode', 1); + set_fixed_freq(data, config); + break; + + case 'mesh': + config.ssid = config.mesh_id; + config.scan_ssid = null; + network_append('mode', 5); + + set_fixed_freq(data, config); + + if (config.encryption && config.encryption != 'none') + config.key_mgmt = 'SAE'; + + config.ieee80211w = null; + break; + } + + if (config.mode != 'mesh' ) { + switch(config.wpa) { + case 1: + config.proto = 'WPA'; + break; + + case 2: + config.proto = 'RSN'; + break; + } + } + + switch(config.auth_type) { + case 'none': + break; + + case 'owe': + iface.wpa_key_mgmt(config); + break; + + case 'psk': + case 'psk2': + case 'sae': + case 'psk-sae': + if (config.mode != 'mesh') + iface.wpa_key_mgmt(config); + + if (config.mode == 'mesh' || config.auth_type == 'sae') + config.sae_password = `"${config.key}"`; + else + config.psk = `"${config.key}"`; + + break; + + case 'eap': + case 'eap2': + case 'eap192': + iface.wpa_key_mgmt(config); + set_default(config, 'erp', config.fils); + + if (config.ca_cert_usesystem && fs.stat('/etc/ssl/certs/ca-certificates.crt')) + config.ca_cert = '/etc/ssl/certs/ca-certificates.crt'; + + switch(config.eap_type) { + case 'fast': + case 'peap': + case 'ttls': + set_default(config, 'auth', 'MSCHAPV2'); + if (config.auth == 'EAP-TLS') { + if (config.ca_cert2_usesystem && fs.stat('/etc/ssl/certs/ca-certificates.crt')) + config.ca_cert2 = '/etc/ssl/certs/ca-certificates.crt'; + } + break; + } + + } + + if (config.wpa_pairwise == 'GCMP') { + config.pairwise = 'GCMP'; + config.group = 'GCMP'; + } + + config.basic_rate = ratelist(config.basic_rate); + config.mcast_rate = ratestr(config.mcast_rate); + config.ssid = `"${config.ssid}"`; + + network_append_vars(config, [ + 'scan_ssid', 'noscan', 'disabled', 'multi_ap_backhaul_sta', + 'ocv', 'key_mgmt', 'psk', 'sae_password', 'pairwise', 'group', 'bssid', + 'proto', 'mesh_fwding', 'mesh_rssi_threshold', 'frequency', 'fixed_freq', + 'disable_ht', 'disable_ht40', 'disable_vht', 'vht', 'max_oper_chwidth', + 'ht40', 'ssid', 'beacon_int', 'ieee80211w', 'basic_rate', 'mcast_rate', + 'bssid_blacklist', 'bssid_whitelist', 'erp', 'ca_cert', 'identity', + 'anonymous_identity', 'client_cert', 'private_key', 'private_key_passwd', + 'subject_match', 'altsubject_match', 'domain_match', 'domain_suffix_match', + 'ca_cert2', 'client_cert2', 'private_key2', 'private_key2_passwd', 'password' + ]); +} + +export function generate(config_list, data, interface) { + flush_network(); + + if (interface.bridge && + (interface.config.mode == 'adhoc' || + (interface.config.mode == 'sta' && !interface.config.wds && !interface.config.multi_ap))){ + netifd.setup_failed('BRIDGE_NOT_ALLOWED'); + return 1; + } + + interface.config.country = data.config.country; + interface.config.beacon_int = data.config.beacon_int; + + setup_sta(data.config, interface.config); + + let file_name = `/var/run/wpa-supplicant-${interface.config.ifname}.conf`; + if (fs.stat(file_name)) + fs.rename(file_name, file_name + '.prev'); + dump_network(file_name); + + let config = { + mode: interface.config.mode, + ctrl: '/var/run/wpa_supplicant', + iface: interface.config.ifname, + config: file_name, + '4addr': !!interface.config.wds, + powersave: false + }; + + if (!interface.config.default_macaddr) + config.macaddr = interface.config.macaddr; + + if (interface.config.wds) + config.bridge = interface.bridge; + + push(config_list, config); + + return config; +}; + +export function setup(config, data) { + let ret = global.ubus.call('wpa_supplicant', 'config_set', { + phy: data.phy, + radio: data.config.radio, + config, + defer: true, + num_global_macaddr: data.config.num_global_macaddr, + }); + + if (ret) + netifd.add_process('/usr/sbin/wpa_supplicant', ret.pid, true, true); + else + netifd.setup_failed('SUPPLICANT_START_FAILED'); +}; + + +export function start(data) { + global.ubus.call('wpa_supplicant', 'config_set', { + phy: data.phy, + radio: data.config.radio, + num_global_macaddr: data.config.num_global_macaddr, + }); +}; diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/validate.uc b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/validate.uc new file mode 100644 index 00000000000000..e675b7a6ca0893 --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/validate.uc @@ -0,0 +1,121 @@ +'use strict'; + +import { log } from 'wifi.common'; +import * as fs from 'fs'; + +const schemas = { + device: json(fs.readfile('/usr/share/schema/wireless.wifi-device.json')).properties, + iface: json(fs.readfile('/usr/share/schema/wireless.wifi-iface.json')).properties, + vlan: json(fs.readfile('/usr/share/schema/wireless.wifi-vlan.json')).properties, + station: json(fs.readfile('/usr/share/schema/wireless.wifi-station.json')).properties, +}; + +const types = { + "array": 1, + "string": 3, + "number": 5, + "boolean": 7, +}; + +function dump_option(schema, key) { + let _key = (schema[key].type == 'alias') ? schema[key].default : key; + + return [ + key, + types[schema[_key].type] + ]; +} + +export function dump_options() { + let dump = { + "name": "mac80211", + }; + + for (let k, v in schemas) { + dump[k] = []; + for (let option in v) + push(dump[k], dump_option(v, option)); + }; + + printf('%J\n', dump); + + return 0; +}; + +function abort(msg) { + log(msg); + die(); +} + +function validate_value(schema, key, value) { + switch(schema.type) { + case 'number': + value = +value; + if (schema.minimum && value < schema.minimum) + abort(`${key}: ${value} is lower than the minimum value`); + if (schema.maximum && value > schema.maximum) + abort(`${key}: ${value} is larger than the maximum value`); + if (schema.enum && !(value in schema.enum)) + abort(`${key}: ${value} has to be one of ${schema.enum}`); + break; + + case 'boolean': + value = !!+value; + break; + + case 'string': + if (schema.enum && !(value in schema.enum)) + abort(`${key}: ${value} has to be one of ${schema.enum}`); + break; + + case 'array': + if (type(value) != 'array') + value = [ value ]; + if (schema.items?.type) + for (let k, v in value) + value[k] = validate_value(schema.items, key, v); + break; + } + + return value; +} + +export function validate(schema, dict) { + schema = schemas[schema]; + + /* complain about anything that is not in the schema */ + for (let k, v in dict) { + if (substr(k, 0, 1) == '.') + continue; + if (schema[k]) + continue; + log(`${k} is not present in the schema`); + } + + /* convert all aliases */ + for (let k, v in dict) { + if (schema[k]?.type != 'alias') + continue; + if (schema[k].default == null) + abort(`${k} alias does not have a default value`); + + dict[schema[k].default] = v; + delete dict[k]; + } + + /* set defaults */ + for (let k, v in schema) { + if (schema[k]?.type == 'alias') + continue; + if (dict[k] != null || schema[k].default == null) + continue; + dict[k] = schema[k].default; + } + + /* validate value constraints */ + for (let k, v in dict) { + if (!schema[k]) + continue; + dict[k] = validate_value(schema[k], k, v); + } +}; diff --git a/package/network/config/wifi-scripts/files-ucode/usr/share/wifi_devices.json b/package/network/config/wifi-scripts/files-ucode/usr/share/wifi_devices.json new file mode 100644 index 00000000000000..5a38ca4b2f5846 --- /dev/null +++ b/package/network/config/wifi-scripts/files-ucode/usr/share/wifi_devices.json @@ -0,0 +1,260 @@ +{ + "pci": [ + [ "0x0777", "0x11ac", "0x0777", "0xe7f9", 0, 0, "Ubiquiti", "LiteBeam, 5AC" ], + [ "0xffff", "0xffff", "0xffff", "0xb102", 0, 0, "Ubiquiti", "PowerStation2, (18V)" ], + [ "0xffff", "0xffff", "0xffff", "0xb202", 0, 0, "Ubiquiti", "PowerStation2, (16D)" ], + [ "0xffff", "0xffff", "0xffff", "0xb302", 0, 0, "Ubiquiti", "PowerStation2, (EXT)" ], + [ "0xffff", "0xffff", "0xffff", "0xb105", 0, 0, "Ubiquiti", "PowerStation5, (22V)" ], + [ "0xffff", "0xffff", "0xffff", "0xb305", 0, 0, "Ubiquiti", "PowerStation5, (EXT)" ], + [ "0xffff", "0xffff", "0xffff", "0xc302", 0, 0, "Ubiquiti", "PicoStation2" ], + [ "0xffff", "0xffff", "0xffff", "0xc3a2", 10, 0, "Ubiquiti", "PicoStation2, HP" ], + [ "0xffff", "0xffff", "0xffff", "0xa105", 0, 0, "Ubiquiti", "WispStation5" ], + [ "0xffff", "0xffff", "0xffff", "0xa002", 10, 0, "Ubiquiti", "LiteStation2" ], + [ "0xffff", "0xffff", "0xffff", "0xa005", 5, 0, "Ubiquiti", "LiteStation5" ], + [ "0xffff", "0xffff", "0xffff", "0xc002", 10, 0, "Ubiquiti", "NanoStation2" ], + [ "0xffff", "0xffff", "0xffff", "0xc005", 5, 0, "Ubiquiti", "NanoStation5" ], + [ "0xffff", "0xffff", "0xffff", "0xc102", 10, 0, "Ubiquiti", "NanoStation, Loco2" ], + [ "0xffff", "0xffff", "0xffff", "0xc105", 5, 0, "Ubiquiti", "NanoStation, Loco5" ], + [ "0xffff", "0xffff", "0xffff", "0xc202", 10, 0, "Ubiquiti", "Bullet2" ], + [ "0xffff", "0xffff", "0xffff", "0xc205", 5, 0, "Ubiquiti", "Bullet5" ], + [ "0x168c", "0xffff", "0x0777", "0xe002", 6, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe003", 3, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe005", 5, 0, "Ubiquiti", "NanoStation, M5" ], + [ "0x168c", "0xffff", "0x0777", "0xe006", 5, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe009", 6, 0, "Ubiquiti", "NanoStation, Loco, M9" ], + [ "0x168c", "0xffff", "0x0777", "0xe012", 10, 0, "Ubiquiti", "NanoStation, M2" ], + [ "0x168c", "0xffff", "0x0777", "0xe035", 3, 0, "Ubiquiti", "NanoStation, M3" ], + [ "0x168c", "0xffff", "0x0777", "0xe0a2", 2, 0, "Ubiquiti", "NanoStation, Loco, M2" ], + [ "0x168c", "0xffff", "0x0777", "0xe0a5", 1, 0, "Ubiquiti", "NanoStation, Loco, M5" ], + [ "0x168c", "0xffff", "0x0777", "0xe102", 6, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe105", 5, 0, "Ubiquiti", "Rocket, M5" ], + [ "0x168c", "0xffff", "0x0777", "0xe112", 10, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe115", 3, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe1a3", 3, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe1a5", 5, 0, "Ubiquiti", "PowerBridge, M5" ], + [ "0x168c", "0xffff", "0x0777", "0xe1b2", 10, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe1b3", 3, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe1b5", 5, 0, "Ubiquiti", "Rocket, M5" ], + [ "0x168c", "0xffff", "0x0777", "0xe1b6", 5, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe1b9", 6, 0, "Ubiquiti", "Rocket, M9" ], + [ "0x168c", "0xffff", "0x0777", "0xe1c2", 10, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe1c3", 3, 0, "Ubiquiti", "Rocket, M3" ], + [ "0x168c", "0xffff", "0x0777", "0xe1c5", 5, 0, "Ubiquiti", "Rocket, M5, GPS" ], + [ "0x168c", "0xffff", "0x0777", "0xe1c5", 5, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe1d2", 10, 0, "Ubiquiti", "Rocket, M2, Titanium" ], + [ "0x168c", "0xffff", "0x0777", "0xe1d3", 3, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe1d5", 5, 0, "Ubiquiti", "airOS, XM/XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe1d9", 6, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe1e3", 3, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe1e5", 5, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe202", 12, 0, "Ubiquiti", "Bullet, M2" ], + [ "0x168c", "0xffff", "0x0777", "0xe205", 6, 0, "Ubiquiti", "Bullet, M5" ], + [ "0x168c", "0xffff", "0x0777", "0xe212", 1, 0, "Ubiquiti", "AirGrid, M2" ], + [ "0x168c", "0xffff", "0x0777", "0xe215", 1, 0, "Ubiquiti", "AirGrid, M5" ], + [ "0x168c", "0xffff", "0x0777", "0xe232", 2, 0, "Ubiquiti", "NanoBridge, M2" ], + [ "0x168c", "0xffff", "0x0777", "0xe233", 3, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe235", 1, 0, "Ubiquiti", "NanoBridge, M5" ], + [ "0x168c", "0xffff", "0x0777", "0xe239", 6, 0, "Ubiquiti", "NanoBridge, M9" ], + [ "0x168c", "0xffff", "0x0777", "0xe242", 9, 0, "Ubiquiti", "AirGrid, M2, HP" ], + [ "0x168c", "0xffff", "0x0777", "0xe243", 3, 0, "Ubiquiti", "NanoBridge, M3" ], + [ "0x168c", "0xffff", "0x0777", "0xe245", 6, 0, "Ubiquiti", "AirGrid, M5, HP" ], + [ "0x168c", "0xffff", "0x0777", "0xe252", 9, 0, "Ubiquiti", "AirGrid, M2, HP" ], + [ "0x168c", "0xffff", "0x0777", "0xe255", 6, 0, "Ubiquiti", "AirGrid, M5, HP" ], + [ "0x168c", "0xffff", "0x0777", "0xe2a3", 3, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe2a5", 5, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe2b2", 10, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe2b5", 1, 0, "Ubiquiti", "NanoBridge, M5" ], + [ "0x168c", "0xffff", "0x0777", "0xe2b9", 6, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe2c2", 10, 0, "Ubiquiti", "NanoBeam, M2, Int" ], + [ "0x168c", "0xffff", "0x0777", "0xe2c3", 6, 0, "Ubiquiti", "Bullet, M2, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe2c4", 6, 0, "Ubiquiti", "airOS, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe2d2", 12, 0, "Ubiquiti", "Bullet, M2, Titanium, HP" ], + [ "0x168c", "0xffff", "0x0777", "0xe2d4", 6, 0, "Ubiquiti", "airOS, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe2d5", 6, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe2e5", 4, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe302", 12, 0, "Ubiquiti", "PicoStation, M2"], + [ "0x168c", "0xffff", "0x0777", "0xe305", 6, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe345", 6, 0, "Ubiquiti", "WispStation, M5" ], + [ "0x168c", "0xffff", "0x0777", "0xe3a5", 5, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe3b5", 6, 0, "Ubiquiti", "airOS, XM/XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe3e5", 4, 0, "Ubiquiti", "PowerBeam, M5, 300" ], + [ "0x168c", "0xffff", "0x0777", "0xe402", 10, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe405", 1, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe4a2", 1, 0, "Ubiquiti", "AirRouter" ], + [ "0x168c", "0xffff", "0x0777", "0xe4a5", 1, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe4b2", 9, 0, "Ubiquiti", "AirRouter, HP" ], + [ "0x168c", "0xffff", "0x0777", "0xe4d5", 5, 0, "Ubiquiti", "Rocket, M5, Titanium" ], + [ "0x168c", "0xffff", "0x0777", "0xe4e5", 4, 0, "Ubiquiti", "PowerBeam, M5, 400" ], + [ "0x168c", "0xffff", "0x0777", "0xe5e5", 4, 0, "Ubiquiti", "airOS, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe6a2", 1, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe6b2", 1, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe6b5", 5, 0, "Ubiquiti", "Rocket, M5, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe6c2", 6, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe6e5", 4, 0, "Ubiquiti", "PowerBeam, M5, 400, ISO" ], + [ "0x168c", "0xffff", "0x0777", "0xe7f8", 2, 0, "Ubiquiti", "airOS, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe805", 5, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0xffff", "0x0777", "0xe812", 6, 0, "Ubiquiti", "NanoBeam, M2, 13" ], + [ "0x168c", "0xffff", "0x0777", "0xe815", 4, 0, "Ubiquiti", "NanoBeam, M5, 16" ], + [ "0x168c", "0xffff", "0x0777", "0xe825", 4, 0, "Ubiquiti", "NanoBeam, M5, 19" ], + [ "0x168c", "0xffff", "0x0777", "0xe835", 6, 0, "Ubiquiti", "AirGrid, M5, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe845", 1, 0, "Ubiquiti", "NanoStation, Loco, M5, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe855", 5, 0, "Ubiquiti", "NanoStation, M5, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe865", 6, 0, "Ubiquiti", "LiteBeam, M5" ], + [ "0x168c", "0xffff", "0x0777", "0xe866", 6, 0, "Ubiquiti", "NanoStation, M2, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe867", 2, 0, "Ubiquiti", "NanoStation, Loco, M2, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe868", 7, 0, "Ubiquiti", "Rocket, M2, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe869", 2, 0, "Ubiquiti", "airOS, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe875", 4, 0, "Ubiquiti", "airOS, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe879", 2, 0, "Ubiquiti", "airOS, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe885", 4, 0, "Ubiquiti", "PowerBeam, M5, 620, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe895", 4, 0, "Ubiquiti", "airOS, XW" ], + [ "0x168c", "0xffff", "0x0777", "0xe8a5", 1, 0, "Ubiquiti", "NanoStation, Loco, M5"], + [ "0x168c", "0xffff", "0x0777", "0xe8b5", 5, 0, "Ubiquiti", "airOS, XM" ], + [ "0x168c", "0x001b", "0x0777", "0x3002", 10, 0, "Ubiquiti", "XR2" ], + [ "0x168c", "0x001b", "0x7777", "0x3002", 10, 0, "Ubiquiti", "XR2" ], + [ "0x168c", "0x001b", "0x0777", "0x3b02", 10, 0, "Ubiquiti", "XR2.3" ], + [ "0x168c", "0x001b", "0x0777", "0x3c02", 10, 0, "Ubiquiti", "XR2.6" ], + [ "0x168c", "0x001b", "0x0777", "0x3b03", 10, 0, "Ubiquiti", "XR3-2.8" ], + [ "0x168c", "0x001b", "0x0777", "0x3c03", 10, 0, "Ubiquiti", "XR3-3.6" ], + [ "0x168c", "0x001b", "0x0777", "0x3003", 10, 0, "Ubiquiti", "XR3" ], + [ "0x168c", "0x001b", "0x0777", "0x3004", 10, 0, "Ubiquiti", "XR4" ], + [ "0x168c", "0x001b", "0x0777", "0x3005", 10, 0, "Ubiquiti", "XR5" ], + [ "0x168c", "0x001b", "0x7777", "0x3005", 10, 0, "Ubiquiti", "XR5" ], + [ "0x168c", "0x001b", "0x0777", "0x3007", 10, 0, "Ubiquiti", "XR7" ], + [ "0x168c", "0x001b", "0x0777", "0x3009", 10, -1520, "Ubiquiti", "XR9" ], + [ "0x168c", "0x001b", "0x168c", "0x2063", 0, 0, "Atheros", "AR5413" ], + [ "0x168c", "0x0013", "0x168c", "0x1042", 1, 0, "Ubiquiti", "SRC" ], + [ "0x168c", "0x0013", "0x0777", "0x2041", 10, 0, "Ubiquiti", "SR2" ], + [ "0x168c", "0x0013", "0x0777", "0x2004", 6, 0, "Ubiquiti", "SR4" ], + [ "0x168c", "0x0013", "0x7777", "0x2004", 6, 0, "Ubiquiti", "SR4" ], + [ "0x168c", "0x0013", "0x0777", "0x1004", 6, 0, "Ubiquiti", "SR4C" ], + [ "0x168c", "0x0013", "0x7777", "0x1004", 6, 0, "Ubiquiti", "SR4C" ], + [ "0x168c", "0x0013", "0x168c", "0x2042", 7, 0, "Ubiquiti", "SR5" ], + [ "0x168c", "0x0013", "0x7777", "0x2009", 12, -1500, "Ubiquiti", "SR9" ], + [ "0x168c", "0x0027", "0x168c", "0x2082", 7, 0, "Ubiquiti", "SR71A" ], + [ "0x168c", "0x0027", "0x0777", "0x4082", 7, 0, "Ubiquiti", "SR71" ], + [ "0x168c", "0x0029", "0x0777", "0x4005", 7, 0, "Ubiquiti", "SR71-15" ], + [ "0x168c", "0x002a", "0x0777", "0xe302", 12, 0, "Ubiquiti", "PicoStation, M2" ], + [ "0x168c", "0x002a", "0x0777", "0xe012", 12, 0, "Ubiquiti", "NanoStation, M2" ], + [ "0x168c", "0x002a", "0x0777", "0xe005", 5, 0, "Ubiquiti", "NanoStation, M5" ], + [ "0x168c", "0x002a", "0x0777", "0xe202", 12, 0, "Ubiquiti", "Bullet, M2" ], + [ "0x168c", "0x002a", "0x0777", "0xe805", 5, 0, "Ubiquiti", "Bullet, M5" ], + [ "0x168c", "0x002a", "0x0777", "0xe345", 0, 0, "Ubiquiti", "WispStation, M5" ], + [ "0x168c", "0x0029", "0x168c", "0xa094", 0, 0, "Atheros", "AR9220" ], + [ "0x168c", "0x0029", "0x168c", "0xa095", 0, 0, "Atheros", "AR9223" ], + [ "0x168c", "0x002a", "0x168c", "0xa093", 0, 0, "Atheros", "AR9280" ], + [ "0x168c", "0x002b", "0x168c", "0xa091", 0, 0, "Atheros", "AR9285" ], + [ "0x168c", "0x002d", "0x168c", "0x209a", 0, 0, "Atheros", "AR9287" ], + [ "0x168c", "0x002e", "0x1a3b", "0x1121", 0, 0, "Atheros", "AR9287" ], + [ "0x168c", "0x002e", "0x0777", "0xe0a2", 8, 0, "Ubiquiti", "NanoStation, Loco, M2, (XM)" ], + [ "0x168c", "0x002e", "0x168c", "0x30a4", 0, 0, "Atheros", "AR9287" ], + [ "0x168c", "0x002e", "0x168c", "0xa199", 0, 0, "Atheros", "AR9287" ], + [ "0x168c", "0x0030", "0x168c", "0x3112", 0, 0, "Atheros", "AR9380" ], + [ "0x168c", "0x0030", "0x168c", "0x3114", 0, 0, "Atheros", "AR9390" ], + [ "0x168c", "0x0033", "0x168c", "0xa120", 0, 0, "Atheros", "AR9580" ], + [ "0x168c", "0x0033", "0x168c", "0xa136", 0, 0, "Atheros", "AR9580" ], + [ "0x168c", "0x0033", "0x168c", "0x3123", 0, 0, "Atheros", "AR9590" ], + [ "0x168c", "0x0033", "0x19b6", "0xd014", 0, 0, "MikroTik", "R11e-5HnD" ], + [ "0x168c", "0x0033", "0x19b6", "0xd057", 0, 0, "MikroTik", "R11e-5HnDr2" ], + [ "0x168c", "0x0033", "0x19b6", "0xd016", 0, 0, "MikroTik", "R11e-2HPnD" ], + [ "0x168c", "0x0034", "0x17aa", "0x3214", 0, 0, "Atheros", "AR9462" ], + [ "0x168c", "0x003c", "0x0000", "0x0000", 0, 0, "Qualcomm, Atheros", "QCA9880" ], + [ "0x168c", "0x003c", "0x168c", "0x3223", 0, 0, "Qualcomm, Atheros", "QCA9880" ], + [ "0x168c", "0x003c", "0x1a56", "0x1420", 0, 0, "Qualcomm, Atheros", "QCA9862" ], + [ "0x168c", "0x003c", "0x19b6", "0xd03c", 0, 0, "Mikrotik", "R11e-5HacT" ], + [ "0x168c", "0x003c", "0x19b6", "0xd075", 0, 0, "Mikrotik", "R11e-5HacD" ], + [ "0x168c", "0x003e", "0x168c", "0x3361", 0, 0, "Qualcomm, Atheros", "QCA6174" ], + [ "0x168c", "0x0040", "0x168c", "0x0002", 0, 0, "Qualcomm, Atheros", "QCA9990" ], + [ "0x168c", "0x0046", "0x0777", "0xe535", 0, 0, "Qualcomm, Atheros", "QCA9994" ], + [ "0x168c", "0x0046", "0x0777", "0xe5a2", 0, 0, "Qualcomm, Atheros", "QCA9994" ], + [ "0x168c", "0x0050", "0x0000", "0x0000", 0, 0, "Qualcomm, Atheros", "QCA9887" ], + [ "0x168c", "0x0056", "0x0000", "0x0000", 0, 0, "Qualcomm, Atheros", "QCA9886" ], + [ "0x17cb", "0x1104", "0x17cb", "0x1104", 0, 0, "Qualcomm, Atheros", "QCN6024/9024/9074" ], + [ "0x1814", "0x3051", "0x1814", "0x0007", 0, 0, "Ralink", "Rt3051" ], + [ "0x1814", "0x3052", "0x1814", "0x0008", 0, 0, "Ralink", "Rt3052" ], + [ "0x1814", "0x3350", "0x1814", "0x000b", 0, 0, "Ralink", "Rt3350" ], + [ "0x1814", "0x3662", "0x1814", "0x000d", 0, 0, "Ralink", "Rt3662" ], + [ "0x11ab", "0x2a55", "0x11ab", "0x0000", 0, 0, "Marvell", "88W8864" ], + [ "0x02df", "0x9135", "0x0000", "0x0000", 0, 0, "Marvell", "88W8887" ], + [ "0x11ab", "0x2b40", "0x11ab", "0x0000", 0, 0, "Marvell", "88W8964" ], + [ "0x02df", "0x9141", "0x0000", "0x0000", 0, 0, "Marvell", "88W8997" ], + [ "0x14c3", "0x0608", "0x14c3", "0x0608", 0, 0, "AMD", "RZ608" ], + [ "0x14c3", "0x7603", "0x14c3", "0x7603", 0, 0, "MediaTek", "MT7603E" ], + [ "0x14c3", "0x7610", "0x14c3", "0x7610", 0, 0, "MediaTek", "MT7610E" ], + [ "0x14c3", "0x7612", "0x14c3", "0x7612", 0, 0, "MediaTek", "MT7612E" ], + [ "0x14c3", "0x7663", "0x14c3", "0x7663", 0, 0, "MediaTek", "MT7613BE" ], + [ "0x14c3", "0x7615", "0x7615", "0x14c3", 0, 0, "MediaTek", "MT7615E" ], + [ "0x14c3", "0x7628", "0x14c3", "0x0004", 0, 0, "MediaTek", "MT76x8" ], + [ "0x14c3", "0x7650", "0x14c3", "0x7650", 0, 0, "MediaTek", "MT7610E" ], + [ "0x14c3", "0x7662", "0x14c3", "0x7662", 0, 0, "MediaTek", "MT76x2E" ], + [ "0x14c3", "0x7915", "0x14c3", "0x7915", 0, 0, "MediaTek", "MT7915E" ], + [ "0x14c3", "0x7906", "0x14c3", "0x7906", 0, 0, "MediaTek", "MT7916AN" ], + [ "0x14c3", "0x7990", "0x14C3", "0x6639", 0, 0, "MediaTek", "MT7996E" ], + [ "0x14c3", "0x7992", "0x14C3", "0x7992", 0, 0, "MediaTek", "MT7992E" ], + [ "0x14e4", "0xaa52", "0x14e4", "0xaa52", 0, 0, "Broadcom", "BCM43602" ], + [ "0x02d0", "0xa9a6", "0x0000", "0x0000", 0, 0, "Cypress", "CYW43455" ], + [ "0x02d0", "0x4345", "0x0000", "0x0000", 0, 0, "Cypress", "CYW43455" ], + [ "0x1ae9", "0x0310", "0x1ae9", "0x0000", 0, 0, "Wilocity", "Wil6210" ], + [ "0x0000", "0x0000", "0x148f", "0x7601", 0, 0, "MediaTek", "MT7601U" ], + [ "0x0000", "0x0000", "0x0e8d", "0x7961", 0, 0, "MediaTek", "MT7921AU" ], + [ "0x0000", "0x0000", "0x0b05", "0x1833", 0, 0, "ASUS", "USB-AC54" ], + [ "0x0000", "0x0000", "0x0b05", "0x17eb", 0, 0, "ASUS", "USB-AC55" ], + [ "0x0000", "0x0000", "0x0b05", "0x180b", 0, 0, "ASUS", "USB-N53, B1" ], + [ "0x0000", "0x0000", "0x0e8d", "0x7612", 0, 0, "Aukey", "USBAC1200" ], + [ "0x0000", "0x0000", "0x057c", "0x8503", 0, 0, "AVM", "FRITZ!WLAN, AC860" ], + [ "0x0000", "0x0000", "0x7392", "0xb711", 0, 0, "Edimax", "EW-7722UAC" ], + [ "0x0000", "0x0000", "0x0e8d", "0x7632", 0, 0, "High, Cloud", "HC-M7662BU1" ], + [ "0x0000", "0x0000", "0x2c4e", "0x0103", 0, 0, "Mercury", "UD13" ], + [ "0x0000", "0x0000", "0x0846", "0x9053", 0, 0, "Netgear", "A6210" ], + [ "0x0000", "0x0000", "0x045e", "0x02e6", 0, 0, "Microsoft", "XBox, One, Wireless, Adapter" ], + [ "0x0000", "0x0000", "0x045e", "0x02fe", 0, 0, "Microsoft", "XBox, One, Wireless, Adapter" ], + [ "0x0000", "0x0000", "0x148f", "0x7610", 0, 0, "MediaTek", "MT7610U" ], + [ "0x0000", "0x0000", "0x13b1", "0x003e", 0, 0, "Linksys", "AE6000" ], + [ "0x0000", "0x0000", "0x0e8d", "0x7610", 0, 0, "Sabrent", "NTWLAC" ], + [ "0x0000", "0x0000", "0x7392", "0xa711", 0, 0, "Edimax", "7711MAC" ], + [ "0x0000", "0x0000", "0x148f", "0x761a", 0, 0, "TP-Link", "TL-WDN5200" ], + [ "0x0000", "0x0000", "0x0b05", "0x17d1", 0, 0, "ASUS", "USB-AC51" ], + [ "0x0000", "0x0000", "0x0b05", "0x17db", 0, 0, "ASUS", "USB-AC50" ], + [ "0x0000", "0x0000", "0x0df6", "0x0075", 0, 0, "Sitecom", "WLA-3100" ], + [ "0x0000", "0x0000", "0x2019", "0xab31", 0, 0, "Planex", "GW-450D" ], + [ "0x0000", "0x0000", "0x2001", "0x3d02", 0, 0, "D-Link", "DWA-171, rev, B1" ], + [ "0x0000", "0x0000", "0x0586", "0x3425", 0, 0, "Zyxel", "NWD6505" ], + [ "0x0000", "0x0000", "0x07b8", "0x7610", 0, 0, "AboCom", "AU7212" ], + [ "0x0000", "0x0000", "0x04bb", "0x0951", 0, 0, "I-O, DATA", "WN-AC433UK" ], + [ "0x0000", "0x0000", "0x057c", "0x8502", 0, 0, "AVM", "FRITZ!WLAN, AC430" ], + [ "0x0000", "0x0000", "0x293c", "0x5702", 0, 0, "Comcast", "Xfinity, KXW02AAA" ], + [ "0x0000", "0x0000", "0x20f4", "0x806b", 0, 0, "TRENDnet", "TEW-806UBH" ], + [ "0x0000", "0x0000", "0x7392", "0xc711", 0, 0, "Devolo", "WiFi, Stick, ac" ], + [ "0x0000", "0x0000", "0x0df6", "0x0079", 0, 0, "Sitecom", "WL-356" ], + [ "0x0000", "0x0000", "0x2357", "0x0123", 0, 0, "TP-Link", "T2UHP, US, v1" ], + [ "0x0000", "0x0000", "0x2357", "0x010b", 0, 0, "TP-Link", "T2UHP, UN, v1" ], + [ "0x0000", "0x0000", "0x2357", "0x0105", 0, 0, "TP-Link", "Archer, T1U" ], + [ "0x0000", "0x0000", "0x0e8d", "0x7630", 0, 0, "MediaTek", "MT7630U" ], + [ "0x0000", "0x0000", "0x0e8d", "0x7650", 0, 0, "MediaTek", "MT7650U" ], + [ "0x0000", "0x0000", "0x0e8d", "0x7663", 0, 0, "MediaTek", "MT7663U" ], + [ "0x0000", "0x0000", "0x043e", "0x310c", 0, 0, "LG", "LGSBWAC02" ], + [ "0x0000", "0x0000", "0x0bda", "0x8176", 0, 0, "Realtek", "RTL8188CU" ], + [ "0x0000", "0x0000", "0x0bda", "0xf179", 0, 0, "Realtek", "RTL8188FTV" ] + ], + "compatible": { + "qca,ar9130-wmac": [ "Atheros", "AR9130" ], + "qca,ar9330-wmac": [ "Atheros", "AR9330" ], + "qca,ar9340-wmac": [ "Atheros", "AR9340" ], + "qca,qca9530-wmac": [ "Qualcomm Atheros", "QCA9530" ], + "qca,qca9550-wmac": [ "Qualcomm Atheros", "QCA9550" ], + "qca,qca9560-wmac": [ "Qualcomm Atheros", "QCA9560" ], + "qcom,ipq4019-wifi": [ "Qualcomm Atheros", "IPQ4019" ], + "qcom,ipq6018-wifi": [ "Qualcomm Atheros", "IPQ6018" ], + "qcom,ipq8074-wifi": [ "Qualcomm Atheros", "IPQ8074" ], + "mediatek,mt7622-wmac": [ "MediaTek", "MT7622" ], + "mediatek,mt7628-wmac": [ "MediaTek", "MT7628" ], + "mediatek,mt7981-wmac": [ "MediaTek", "MT7981" ], + "mediatek,mt7986-wmac": [ "MediaTek", "MT7986" ], + "ralink,rt2880-wmac": [ "Ralink", "Rt2880" ], + "ralink,rt3050-wmac": [ "Ralink", "Rt3050" ], + "ralink,rt3352-wmac": [ "Ralink", "Rt3352" ], + "ralink,rt3883-wmac": [ "Ralink", "Rt3883" ], + "ralink,rt5350-wmac": [ "Ralink", "Rt5350" ], + "ralink,rt7620-wmac": [ "MediaTek", "MT7620" ] + } +} diff --git a/package/network/services/hostapd/files/hostapd-full.config b/package/network/services/hostapd/files/hostapd-full.config index 9076ebc44f95df..2ac2a312d177c6 100644 --- a/package/network/services/hostapd/files/hostapd-full.config +++ b/package/network/services/hostapd/files/hostapd-full.config @@ -94,10 +94,10 @@ CONFIG_EAP_TTLS=y #CONFIG_EAP_PAX=y # EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK) -#CONFIG_EAP_PSK=y +CONFIG_EAP_PSK=y # EAP-pwd for the integrated EAP server (secure authentication with a password) -#CONFIG_EAP_PWD=y +CONFIG_EAP_PWD=y # EAP-SAKE for the integrated EAP server #CONFIG_EAP_SAKE=y diff --git a/package/network/services/hostapd/files/hostapd.uc b/package/network/services/hostapd/files/hostapd.uc index 2d9ce2874901d2..c1db91e4d4f944 100644 --- a/package/network/services/hostapd/files/hostapd.uc +++ b/package/network/services/hostapd/files/hostapd.uc @@ -45,6 +45,7 @@ hostapd.data.bss_info_fields = { wpa_pairwise: true, auth_algs: true, ieee80211w: true, + owe_transition_ifname: true, }; function iface_remove(cfg) diff --git a/package/network/services/hostapd/files/wpad.json b/package/network/services/hostapd/files/wpad.json index c73f3d98bd1d4c..3dc7bd3c988b92 100644 --- a/package/network/services/hostapd/files/wpad.json +++ b/package/network/services/hostapd/files/wpad.json @@ -1,22 +1,27 @@ { "bounding": [ "CAP_NET_ADMIN", + "CAP_NET_BIND_SERVICE", "CAP_NET_RAW" ], "effective": [ "CAP_NET_ADMIN", + "CAP_NET_BIND_SERVICE", "CAP_NET_RAW" ], "ambient": [ "CAP_NET_ADMIN", + "CAP_NET_BIND_SERVICE", "CAP_NET_RAW" ], "permitted": [ "CAP_NET_ADMIN", + "CAP_NET_BIND_SERVICE", "CAP_NET_RAW" ], "inheritable": [ "CAP_NET_ADMIN", + "CAP_NET_BIND_SERVICE", "CAP_NET_RAW" ] } diff --git a/package/network/services/hostapd/patches/763-radius-wispr.patch b/package/network/services/hostapd/patches/763-radius-wispr.patch new file mode 100644 index 00000000000000..da81a623e76c25 --- /dev/null +++ b/package/network/services/hostapd/patches/763-radius-wispr.patch @@ -0,0 +1,105 @@ +--- a/src/ap/ieee802_1x.c ++++ b/src/ap/ieee802_1x.c +@@ -2035,6 +2035,25 @@ static int ieee802_1x_update_vlan(struct + } + #endif /* CONFIG_NO_VLAN */ + ++static int ieee802_1x_update_wispr(struct hostapd_data *hapd, ++ struct sta_info *sta, ++ struct radius_msg *msg) ++{ ++ memset(sta->bandwidth, 0, sizeof(sta->bandwidth)); ++ ++ if (radius_msg_get_wispr(msg, sta->bandwidth)) ++ return 0; ++ ++ if (!sta->bandwidth[0] && !sta->bandwidth[1]) ++ return 0; ++ ++ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, ++ HOSTAPD_LEVEL_INFO, ++ "received wispr bandwidth from RADIUS server %d/%d", ++ sta->bandwidth[0], sta->bandwidth[1]); ++ ++ return 0; ++} + + /** + * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server +@@ -2151,6 +2170,7 @@ ieee802_1x_receive_auth(struct radius_ms + ieee802_1x_check_hs20(hapd, sta, msg, + session_timeout_set ? + (int) session_timeout : -1); ++ ieee802_1x_update_wispr(hapd, sta, msg); + break; + case RADIUS_CODE_ACCESS_REJECT: + sm->eap_if->aaaFail = true; +--- a/src/ap/sta_info.h ++++ b/src/ap/sta_info.h +@@ -95,6 +95,7 @@ struct sta_info { + u8 supported_rates[WLAN_SUPP_RATES_MAX]; + int supported_rates_len; + u8 qosinfo; /* Valid when WLAN_STA_WMM is set */ ++ u32 bandwidth[2]; + + #ifdef CONFIG_MESH + enum mesh_plink_state plink_state; +--- a/src/radius/radius.c ++++ b/src/radius/radius.c +@@ -1339,6 +1339,35 @@ radius_msg_get_cisco_keys(struct radius_ + return keys; + } + ++#define RADIUS_VENDOR_ID_WISPR 14122 ++#define RADIUS_WISPR_AV_BW_UP 7 ++#define RADIUS_WISPR_AV_BW_DOWN 8 ++ ++int ++radius_msg_get_wispr(struct radius_msg *msg, u32 *bandwidth) ++{ ++ int i; ++ ++ if (msg == NULL || bandwidth == NULL) ++ return 1; ++ ++ for (i = 0; i < 2; i++) { ++ size_t keylen; ++ u8 *key; ++ ++ key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_WISPR, ++ RADIUS_WISPR_AV_BW_UP + i, &keylen); ++ if (!key) ++ continue; ++ ++ if (keylen == 4) ++ bandwidth[i] = ntohl(*((u32 *)key)); ++ os_free(key); ++ } ++ ++ return 0; ++} ++ + + int radius_msg_add_mppe_keys(struct radius_msg *msg, + const u8 *req_authenticator, +--- a/src/radius/radius.h ++++ b/src/radius/radius.h +@@ -233,6 +233,10 @@ enum { + RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL = 10, + }; + ++#define RADIUS_VENDOR_ID_WISPR 14122 ++#define RADIUS_WISPR_AV_BW_UP 7 ++#define RADIUS_WISPR_AV_BW_DOWN 8 ++ + #ifdef _MSC_VER + #pragma pack(pop) + #endif /* _MSC_VER */ +@@ -306,6 +310,7 @@ radius_msg_get_ms_keys(struct radius_msg + struct radius_ms_mppe_keys * + radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, + const u8 *secret, size_t secret_len); ++int radius_msg_get_wispr(struct radius_msg *msg, u32 *bandwidth); + int radius_msg_add_mppe_keys(struct radius_msg *msg, + const u8 *req_authenticator, + const u8 *secret, size_t secret_len, diff --git a/package/network/services/hostapd/src/src/ap/ubus.c b/package/network/services/hostapd/src/src/ap/ubus.c index 22567207556599..395e2c2dbce3f8 100644 --- a/package/network/services/hostapd/src/src/ap/ubus.c +++ b/package/network/services/hostapd/src/src/ap/ubus.c @@ -369,6 +369,7 @@ hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj, &op_class, &channel); blob_buf_init(&b, 0); + blobmsg_add_string(&b, "driver", hapd->driver->name); blobmsg_add_string(&b, "status", hostapd_state_text(hapd->iface->state)); blobmsg_printf(&b, "bssid", MACSTR, MAC2STR(hapd->conf->bssid)); @@ -1657,6 +1658,85 @@ static int avl_compare_macaddr(const void *k1, const void *k2, void *ptr) return memcmp(k1, k2, ETH_ALEN); } +static int +hostapd_wired_get_clients(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj); + struct hostap_sta_driver_data sta_driver_data; + struct sta_info *sta; + void *list, *c; + char mac_buf[20]; + static const struct { + const char *name; + uint32_t flag; + } sta_flags[] = { + { "authorized", WLAN_STA_AUTHORIZED }, + }; + + blob_buf_init(&b, 0); + list = blobmsg_open_table(&b, "clients"); + for (sta = hapd->sta_list; sta; sta = sta->next) { + void *r; + int i; + + sprintf(mac_buf, MACSTR, MAC2STR(sta->addr)); + c = blobmsg_open_table(&b, mac_buf); + for (i = 0; i < ARRAY_SIZE(sta_flags); i++) + blobmsg_add_u8(&b, sta_flags[i].name, + !!(sta->flags & sta_flags[i].flag)); + + blobmsg_close_table(&b, c); + } + blobmsg_close_array(&b, list); + ubus_send_reply(ctx, req, b.head); + + return 0; +} + +static int +hostapd_wired_get_status(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj); + char iface_name[17]; + + blob_buf_init(&b, 0); + blobmsg_add_string(&b, "driver", hapd->driver->name); + blobmsg_add_string(&b, "status", hostapd_state_text(hapd->iface->state)); + + snprintf(iface_name, 17, "%s", hapd->iface->phy); + blobmsg_add_string(&b, "iface", iface_name); + + ubus_send_reply(ctx, req, b.head); + + return 0; +} + +static int +hostapd_wired_del_clients(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj); + + hostapd_free_stas(hapd); + + return 0; +} + +static const struct ubus_method wired_methods[] = { + UBUS_METHOD_NOARG("reload", hostapd_bss_reload), + UBUS_METHOD_NOARG("get_clients", hostapd_wired_get_clients), + UBUS_METHOD_NOARG("del_clients", hostapd_wired_del_clients), + UBUS_METHOD_NOARG("get_status", hostapd_wired_get_status), +}; + +static struct ubus_object_type wired_object_type = + UBUS_OBJECT_TYPE("hostapd_wired", wired_methods); + void hostapd_ubus_add_bss(struct hostapd_data *hapd) { struct ubus_object *obj = &hapd->ubus.obj; @@ -1676,9 +1756,15 @@ void hostapd_ubus_add_bss(struct hostapd_data *hapd) avl_init(&hapd->ubus.banned, avl_compare_macaddr, false, NULL); obj->name = name; - obj->type = &bss_object_type; - obj->methods = bss_object_type.methods; - obj->n_methods = bss_object_type.n_methods; + if (!strcmp(hapd->driver->name, "wired")) { + obj->type = &wired_object_type; + obj->methods = wired_object_type.methods; + obj->n_methods = wired_object_type.n_methods; + } else { + obj->type = &bss_object_type; + obj->methods = bss_object_type.methods; + obj->n_methods = bss_object_type.n_methods; + } ret = ubus_add_object(ctx, obj); hostapd_ubus_ref_inc(); } @@ -1876,6 +1962,13 @@ void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info * blobmsg_add_string(&b, "ifname", hapd->conf->iface); if (auth_alg) blobmsg_add_string(&b, "auth-alg", auth_alg); + if (sta->bandwidth[0] || sta->bandwidth[1]) { + void *r = blobmsg_open_array(&b, "rate-limit"); + + blobmsg_add_u32(&b, "", sta->bandwidth[0]); + blobmsg_add_u32(&b, "", sta->bandwidth[1]); + blobmsg_close_array(&b, r); + } ubus_notify(ctx, &hapd->ubus.obj, "sta-authorized", b.head, -1); } diff --git a/package/network/utils/iwinfo/Makefile b/package/network/utils/iwinfo/Makefile index d81ed62620afd6..fe160f6ef326aa 100644 --- a/package/network/utils/iwinfo/Makefile +++ b/package/network/utils/iwinfo/Makefile @@ -18,6 +18,7 @@ PKG_MAINTAINER:=Jo-Philipp Wich PKG_LICENSE:=GPL-2.0 PKG_BUILD_FLAGS:=no-lto +PKG_CONFIG_DEPENDS:=CONFIG_WIFI_SCRIPTS_UCODE IWINFO_ABI_VERSION:=20230701 @@ -62,7 +63,7 @@ define Package/iwinfo SECTION:=utils CATEGORY:=Utilities TITLE:=Generalized Wireless Information utility - DEPENDS:=+libiwinfo + DEPENDS:=+libiwinfo @!WIFI_SCRIPTS_UCODE endef define Package/iwinfo/description diff --git a/package/system/fstools/Makefile b/package/system/fstools/Makefile index 419cdfff9aea2c..2f30915bf98525 100644 --- a/package/system/fstools/Makefile +++ b/package/system/fstools/Makefile @@ -12,9 +12,9 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/fstools.git -PKG_MIRROR_HASH:=5f04ce2b346d9a48468180dd9601ca0fcc83896ebf5466855578e766646e14a1 -PKG_SOURCE_DATE:=2024-07-14 -PKG_SOURCE_VERSION:=408c2cc48e6694446c89da7f8121b399063e1067 +PKG_MIRROR_HASH:=b0de38a758cccdb234d909eda3bf4de40d260f75000f27d30e7d1bc4158b1094 +PKG_SOURCE_DATE:=2024-12-02 +PKG_SOURCE_VERSION:=49d36ba2d1ada4ca177612cfbe904beb286dcab7 CMAKE_INSTALL:=1 PKG_LICENSE:=GPL-2.0 @@ -95,9 +95,10 @@ endef define Package/fstools/install $(INSTALL_DIR) $(1)/sbin $(1)/lib - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{mount_root,jffs2reset} $(1)/sbin/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/{mount_root,factoryreset} $(1)/sbin/ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libfstools.so $(1)/lib/ - $(LN) jffs2reset $(1)/sbin/jffs2mark + $(LN) factoryreset $(1)/sbin/jffs2mark + $(LN) factoryreset $(1)/sbin/jffs2reset endef define Package/snapshot-tool/install diff --git a/package/system/rpcd/Makefile b/package/system/rpcd/Makefile index da031db8498d0f..447bec1ac4e0f6 100644 --- a/package/system/rpcd/Makefile +++ b/package/system/rpcd/Makefile @@ -12,9 +12,9 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/rpcd.git -PKG_MIRROR_HASH:=67b2cb985d8712a3e5a17ebf8c74fd35d553c8f9a4197616f9a3649a8740cc33 -PKG_SOURCE_DATE:=2024-09-17 -PKG_SOURCE_VERSION:=9f4b86e70352ab9ca6aa272d096419acc53e2390 +PKG_MIRROR_HASH:=081058ace6445fc8bf67e49f51e1bc87bf36bd0a38b34e6ff8976d7260bf2c9f +PKG_SOURCE_DATE:=2024-12-02 +PKG_SOURCE_VERSION:=cc9a471c32e106fa9ee045540613fefdc31c5cd2 PKG_MAINTAINER:=Jo-Philipp Wich PKG_LICENSE:=ISC diff --git a/package/utils/ucode/Makefile b/package/utils/ucode/Makefile index 6ee0cf2a1d56b9..a68dea81507242 100644 --- a/package/utils/ucode/Makefile +++ b/package/utils/ucode/Makefile @@ -8,17 +8,18 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ucode -PKG_RELEASE:=3 +PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=https://github.com/jow-/ucode.git -PKG_SOURCE_DATE:=2024-07-22 -PKG_SOURCE_VERSION:=b610860dd4a0591ff586dd71a50f556a0ddafced -PKG_MIRROR_HASH:=a5ec51dd989174422d3b19b022ff4f863d57eb559c9f08d54c0d10651f598357 +PKG_SOURCE_DATE:=2024-12-02 +PKG_SOURCE_VERSION:=b0b5d93846a1fb9d1d94992d5fdf508ef345e87d +PKG_MIRROR_HASH:=b43fcb38a85469552d5fb641ade271c346634a52c3628155d3215953ff2c25e1 PKG_MAINTAINER:=Jo-Philipp Wich PKG_LICENSE:=ISC PKG_ABI_VERSION:=20230711 +PKG_BUILD_DEPENDS:=libmd HOST_BUILD_DEPENDS:=libjson-c/host include $(INCLUDE_DIR)/package.mk @@ -51,7 +52,8 @@ CMAKE_HOST_OPTIONS += \ -DUCI_SUPPORT=OFF \ -DULOOP_SUPPORT=OFF \ -DDEBUG_SUPPORT=ON \ - -DLOG_SUPPORT=OFF + -DLOG_SUPPORT=OFF \ + -DDIGEST_SUPPORT=OFF define Package/ucode/default @@ -178,6 +180,10 @@ $(eval $(call UcodeModule, \ uloop, ULOOP_SUPPORT, +libubox, \ The uloop module allows ucode scripts to interact with OpenWrt uloop event loop implementation.)) +$(eval $(call UcodeModule, \ + digest, DIGEST_SUPPORT, , \ + The digest module allows ucode scripts to use libmd digests.)) + $(eval $(call BuildPackage,libucode)) $(eval $(call BuildPackage,ucode)) diff --git a/package/utils/ucode/patches/100-nl80211_vif_radio_mask.patch b/package/utils/ucode/patches/100-nl80211_vif_radio_mask.patch deleted file mode 100644 index 22e05f7c620518..00000000000000 --- a/package/utils/ucode/patches/100-nl80211_vif_radio_mask.patch +++ /dev/null @@ -1,40 +0,0 @@ ---- a/include/linux/nl80211.h -+++ b/include/linux/nl80211.h -@@ -2868,6 +2868,9 @@ enum nl80211_commands { - * nested item, it contains attributes defined in - * &enum nl80211_if_combination_attrs. - * -+ * @NL80211_ATTR_VIF_RADIO_MASK: Bitmask of allowed radios (u32). -+ * A value of 0 means all radios. -+ * - * @NUM_NL80211_ATTR: total number of nl80211_attrs available - * @NL80211_ATTR_MAX: highest attribute number currently defined - * @__NL80211_ATTR_AFTER_LAST: internal use -@@ -3416,6 +3419,8 @@ enum nl80211_attrs { - NL80211_ATTR_WIPHY_RADIOS, - NL80211_ATTR_WIPHY_INTERFACE_COMBINATIONS, - -+ NL80211_ATTR_VIF_RADIO_MASK, -+ - /* add attributes here, update the policy in nl80211.c */ - - __NL80211_ATTR_AFTER_LAST, ---- a/lib/nl80211.c -+++ b/lib/nl80211.c -@@ -829,7 +829,7 @@ static const uc_nl_nested_spec_t nl80211 - - static const uc_nl_nested_spec_t nl80211_msg = { - .headsize = 0, -- .nattrs = 128, -+ .nattrs = 129, - .attrs = { - { NL80211_ATTR_4ADDR, "4addr", DT_U8, 0, NULL }, - { NL80211_ATTR_AIRTIME_WEIGHT, "airtime_weight", DT_U16, 0, NULL }, -@@ -959,6 +959,7 @@ static const uc_nl_nested_spec_t nl80211 - { NL80211_ATTR_MAX_AP_ASSOC_STA, "max_ap_assoc", DT_U16, 0, NULL }, - { NL80211_ATTR_SURVEY_INFO, "survey_info", DT_NESTED, 0, &nl80211_survey_info_nla }, - { NL80211_ATTR_WIPHY_RADIOS, "radios", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_wiphy_radio_nla }, -+ { NL80211_ATTR_VIF_RADIO_MASK, "vif_radio_mask", DT_U32, 0, NULL }, - } - }; - diff --git a/scripts/metadata.pm b/scripts/metadata.pm index ecfe42c0bc926c..dec9e62dff1295 100644 --- a/scripts/metadata.pm +++ b/scripts/metadata.pm @@ -136,6 +136,7 @@ sub parse_target_metadata($) { /^Linux-Kernel-Arch:\s*(.+)\s*$/ and $target->{karch} = $1; /^Default-Subtarget:\s*(.+)\s*$/ and $target->{def_subtarget} = $1; /^Default-Packages:\s*(.+)\s*$/ and $target->{packages} = [ split(/\s+/, $1) ]; + /^Target-Default-Profile:\s*(.+)\s*$/ and $target->{default_profile} = $1; /^Target-Profile:\s*(.+)\s*$/ and do { $profile = { id => $1, diff --git a/scripts/target-metadata.pl b/scripts/target-metadata.pl index 0c17e2e3273df6..ce96d1e7d538a1 100755 --- a/scripts/target-metadata.pl +++ b/scripts/target-metadata.pl @@ -179,7 +179,7 @@ () print <{profiles}->[0]; + foreach my $p (@{$target->{profiles}}) { + last unless $target->{default_profile}; + my $name = $p->{id}; + $name =~ s/^DEVICE_//; + next unless $name eq $target->{default_profile}; + $profile = $p; + last; + } $profile or next; print <{conf}_$profile->{id} if TARGET_$target->{conf} && !BUILDBOT diff --git a/target/linux/mediatek/filogic/config-6.6 b/target/linux/mediatek/filogic/config-6.6 index 85e7367f41cfe5..e0a715a56b187d 100644 --- a/target/linux/mediatek/filogic/config-6.6 +++ b/target/linux/mediatek/filogic/config-6.6 @@ -226,6 +226,7 @@ CONFIG_JBD2=y CONFIG_JUMP_LABEL=y CONFIG_LEDS_PWM=y CONFIG_LEDS_SMARTRG_LED=y +CONFIG_LEDS_TRIGGER_PATTERN=y CONFIG_LIBFDT=y CONFIG_LOCK_DEBUGGING_SUPPORT=y CONFIG_LOCK_SPIN_ON_OWNER=y diff --git a/target/linux/mediatek/filogic/target.mk b/target/linux/mediatek/filogic/target.mk index d1637e06af700e..52ce25de1ee2f8 100644 --- a/target/linux/mediatek/filogic/target.mk +++ b/target/linux/mediatek/filogic/target.mk @@ -4,6 +4,7 @@ BOARDNAME:=Filogic 8x0 (MT798x) CPU_TYPE:=cortex-a53 DEFAULT_PACKAGES += fitblk kmod-phy-aquantia kmod-crypto-hw-safexcel wpad-basic-mbedtls uboot-envtools KERNELNAME:=Image dtbs +DEFAULT_PROFILE:=openwrt_one define Target/Description Build firmware images for MediaTek Filogic ARM based boards.