diff --git a/package/kernel/mac80211/broadcom.mk b/package/kernel/mac80211/broadcom.mk index 13da62a6f46..d0b08890881 100644 --- a/package/kernel/mac80211/broadcom.mk +++ b/package/kernel/mac80211/broadcom.mk @@ -416,7 +416,10 @@ define KernelPackage/brcmfmac DEPENDS+= @USB_SUPPORT +kmod-cfg80211 +@DRIVER_11AC_SUPPORT \ +kmod-brcmutil +BRCMFMAC_SDIO:kmod-mmc @!TARGET_uml \ +BRCMFMAC_USB:kmod-usb-core +BRCMFMAC_USB:brcmfmac-firmware-usb - FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko + FILES:= \ + $(PKG_BUILD_DIR)/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko \ + $(foreach type,bca cyw wcc, \ + $(PKG_BUILD_DIR)/drivers/net/wireless/broadcom/brcm80211/brcmfmac/$(type)/brcmfmac-$(type).ko) AUTOLOAD:=$(call AutoProbe,brcmfmac) endef diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh index 3b88af46795..7d3ab4dc01b 100644 --- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh +++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh @@ -27,6 +27,7 @@ drv_mac80211_init_device_config() { config_add_string distance config_add_int beacon_int chanbw frag rts config_add_int rxantenna txantenna txpower min_tx_power + config_add_int num_global_macaddr multiple_bssid config_add_boolean noscan ht_coex acs_exclude_dfs background_radar config_add_array ht_capab config_add_array channels @@ -487,6 +488,8 @@ ${channel:+channel=$channel} ${channel_list:+chanlist=$channel_list} ${hostapd_noscan:+noscan=1} ${tx_burst:+tx_queue_data2_burst=$tx_burst} +mbssid=$multiple_bssid +#num_global_macaddr=$num_global_macaddr $base_cfg EOF @@ -517,6 +520,7 @@ mac80211_hostapd_setup_bss() { cat >> /var/run/hostapd-$phy.conf < /dev/null ubus call wpa_supplicant config_set '{ "phy": "'"$phy"'", "config": [] }' > /dev/null - wdev_tool "$phy" '{}' + wdev_tool "$phy" set_config '{}' } drv_mac80211_setup() { @@ -1080,7 +1048,8 @@ drv_mac80211_setup() { country chanbw distance \ txpower \ rxantenna txantenna \ - frag rts beacon_int:100 htmode + frag rts beacon_int:100 htmode \ + num_global_macaddr:1 multiple_bssid:0 json_get_values basic_rate_list basic_rate json_get_values scan_list scan_list json_select .. @@ -1174,7 +1143,7 @@ drv_mac80211_setup() { [ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_start "$phy" json_set_namespace wdev_uc prev - wdev_tool "$phy" "$(json_dump)" $active_ifnames + wdev_tool "$phy" set_config "$(json_dump)" $active_ifnames json_set_namespace "$prev" for_each_interface "ap sta adhoc mesh monitor" mac80211_set_vif_txpower diff --git a/package/kernel/mac80211/patches/subsys/130-disable_auto_vif.patch b/package/kernel/mac80211/patches/subsys/130-disable_auto_vif.patch new file mode 100644 index 00000000000..9d8f781ac41 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/130-disable_auto_vif.patch @@ -0,0 +1,27 @@ +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -1396,24 +1396,6 @@ int ieee80211_register_hw(struct ieee802 + debugfs_hw_add(local); + rate_control_add_debugfs(local); + +- rtnl_lock(); +- wiphy_lock(hw->wiphy); +- +- /* add one default STA interface if supported */ +- if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) && +- !ieee80211_hw_check(hw, NO_AUTO_VIF)) { +- struct vif_params params = {0}; +- +- result = ieee80211_if_add(local, "wlan%d", NET_NAME_ENUM, NULL, +- NL80211_IFTYPE_STATION, ¶ms); +- if (result) +- wiphy_warn(local->hw.wiphy, +- "Failed to add default virtual iface\n"); +- } +- +- wiphy_unlock(hw->wiphy); +- rtnl_unlock(); +- + #ifdef CONFIG_INET + local->ifa_notifier.notifier_call = ieee80211_ifa_changed; + result = register_inetaddr_notifier(&local->ifa_notifier); diff --git a/package/network/services/hostapd/Makefile b/package/network/services/hostapd/Makefile index 4bc1b94d1f0..0bf628af61a 100644 --- a/package/network/services/hostapd/Makefile +++ b/package/network/services/hostapd/Makefile @@ -9,9 +9,9 @@ PKG_RELEASE:=2 PKG_SOURCE_URL:=http://w1.fi/hostap.git PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2023-06-22 -PKG_SOURCE_VERSION:=599d00be9de2846c6ea18c1487d8329522ade22b -PKG_MIRROR_HASH:=828810c558ea181e45ed0c8b940f5c41e55775e2979a15aed8cf0ab17dd7723c +PKG_SOURCE_DATE:=2023-09-08 +PKG_SOURCE_VERSION:=e5ccbfc69ecf297590341ae8b461edba9d8e964c +PKG_MIRROR_HASH:=fcc6550f46c7f8bbdbf71e63f8f699b9a0878565ad1b90a17855f5ec21283b8f PKG_MAINTAINER:=Felix Fietkau PKG_LICENSE:=BSD-3-Clause diff --git a/package/network/services/hostapd/files/common.uc b/package/network/services/hostapd/files/common.uc index 74c07855c95..ccffe3eb436 100644 --- a/package/network/services/hostapd/files/common.uc +++ b/package/network/services/hostapd/files/common.uc @@ -1,6 +1,6 @@ import * as nl80211 from "nl80211"; import * as rtnl from "rtnl"; -import { readfile } from "fs"; +import { readfile, glob, basename, readlink } from "fs"; const iftypes = { ap: nl80211.const.NL80211_IFTYPE_AP, @@ -94,6 +94,156 @@ function wdev_create(phy, name, data) return null; } +function phy_sysfs_file(phy, name) +{ + return trim(readfile(`/sys/class/ieee80211/${phy}/${name}`)); +} + +function macaddr_split(str) +{ + return map(split(str, ":"), (val) => hex(val)); +} + +function macaddr_join(addr) +{ + return join(":", map(addr, (val) => sprintf("%02x", val))); +} + +function wdev_macaddr(wdev) +{ + return trim(readfile(`/sys/class/net/${wdev}/address`)); +} + +const phy_proto = { + macaddr_init: function(used, options) { + this.macaddr_options = options ?? {}; + this.macaddr_list = {}; + + if (type(used) == "object") + for (let addr in used) + this.macaddr_list[addr] = used[addr]; + else + for (let addr in used) + this.macaddr_list[addr] = -1; + + this.for_each_wdev((wdev) => { + let macaddr = wdev_macaddr(wdev); + this.macaddr_list[macaddr] ??= -1; + }); + + return this.macaddr_list; + }, + + macaddr_generate: function(data) { + let phy = this.name; + let idx = int(data.id ?? 0); + let mbssid = int(data.mbssid ?? 0) > 0; + let num_global = int(data.num_global ?? 1); + let use_global = !mbssid && idx < num_global; + + let base_addr = phy_sysfs_file(phy, "macaddress"); + if (!base_addr) + return null; + + if (!idx && !mbssid) + return base_addr; + + let base_mask = phy_sysfs_file(phy, "address_mask"); + if (!base_mask) + return null; + + if (base_mask == "00:00:00:00:00:00" && idx >= num_global) { + let addrs = split(phy_sysfs_file(phy, "addresses"), "\n"); + + if (idx < length(addrs)) + return addrs[idx]; + + base_mask = "ff:ff:ff:ff:ff:ff"; + } + + let addr = macaddr_split(base_addr); + let mask = macaddr_split(base_mask); + let type; + + if (mbssid) + type = "b5"; + else if (use_global) + type = "add"; + else if (mask[0] > 0) + type = "b1"; + else if (mask[5] < 0xff) + type = "b5"; + else + type = "add"; + + switch (type) { + case "b1": + if (!(addr[0] & 2)) + idx--; + addr[0] |= 2; + addr[0] ^= idx << 2; + break; + case "b5": + if (mbssid) + addr[0] |= 2; + addr[5] ^= idx; + break; + default: + for (let i = 5; i > 0; i--) { + addr[i] += idx; + if (addr[i] < 256) + break; + addr[i] %= 256; + } + break; + } + + return macaddr_join(addr); + }, + + macaddr_next: function(val) { + let data = this.macaddr_options ?? {}; + let list = this.macaddr_list; + + for (let i = 0; i < 32; i++) { + data.id = i; + + let mac = this.macaddr_generate(data); + if (!mac) + return null; + + if (list[mac] != null) + continue; + + list[mac] = val != null ? val : -1; + return mac; + } + }, + + for_each_wdev: function(cb) { + let wdevs = glob(`/sys/class/ieee80211/${this.name}/device/net/*`); + wdevs = map(wdevs, (arg) => basename(arg)); + for (let wdev in wdevs) { + if (basename(readlink(`/sys/class/net/${wdev}/phy80211`)) != this.name) + continue; + + cb(wdev); + } + } +}; + +function phy_open(phy) +{ + let phyidx = readfile(`/sys/class/ieee80211/${phy}/index`); + if (!phyidx) + return null; + + return proto({ + name: phy, + idx: int(phyidx) + }, phy_proto); +} + const vlist_proto = { update: function(values, arg) { let data = this.data; @@ -165,4 +315,4 @@ function vlist_new(cb) { }, vlist_proto); } -export { wdev_remove, wdev_create, is_equal, vlist_new, phy_is_fullmac }; +export { wdev_remove, wdev_create, is_equal, vlist_new, phy_is_fullmac, phy_open }; diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh index a0945fdc53e..271c1f7becd 100644 --- a/package/network/services/hostapd/files/hostapd.sh +++ b/package/network/services/hostapd/files/hostapd.sh @@ -632,8 +632,7 @@ hostapd_set_bss_options() { [ -n "$wpa_strict_rekey" ] && append bss_conf "wpa_strict_rekey=$wpa_strict_rekey" "$N" } - set_default nasid "${macaddr//\:}" - append bss_conf "nas_identifier=$nasid" "$N" + [ -n "$nasid" ] && append bss_conf "nas_identifier=$nasid" "$N" [ -n "$acct_interval" ] && \ append bss_conf "radius_acct_interim_interval=$acct_interval" "$N" diff --git a/package/network/services/hostapd/files/hostapd.uc b/package/network/services/hostapd/files/hostapd.uc index 384c5c2eb08..9b356dcc309 100644 --- a/package/network/services/hostapd/files/hostapd.uc +++ b/package/network/services/hostapd/files/hostapd.uc @@ -1,6 +1,6 @@ let libubus = require("ubus"); import { open, readfile } from "fs"; -import { wdev_create, wdev_remove, is_equal, vlist_new, phy_is_fullmac } from "common"; +import { wdev_create, wdev_remove, is_equal, vlist_new, phy_is_fullmac, phy_open } from "common"; let ubus = libubus.connect(); @@ -41,10 +41,13 @@ channel=${config.radio.channel} for (let i = 0; i < length(config.bss); i++) { let bss = config.bss[i]; let type = i > 0 ? "bss" : "interface"; + let nasid = bss.nasid ?? replace(bss.bssid, ":", ""); str += ` ${type}=${bss.ifname} +bssid=${bss.bssid} ${join("\n", bss.data)} +nas_identifier=${nasid} `; if (start_disabled) str += ` @@ -108,8 +111,22 @@ function iface_add(phy, config, phy_status) return iface.start(freq_info) >= 0; } -function iface_restart(phy, config, old_config) +function iface_config_macaddr_list(config) { + let macaddr_list = {}; + for (let i = 0; i < length(config.bss); i++) { + let bss = config.bss[i]; + if (!bss.default_macaddr) + macaddr_list[bss.bssid] = i; + } + + return macaddr_list; +} + +function iface_restart(phydev, config, old_config) +{ + let phy = phydev.name; + iface_remove(old_config); iface_remove(config); @@ -118,6 +135,13 @@ function iface_restart(phy, config, old_config) return; } + phydev.macaddr_init(iface_config_macaddr_list(config)); + for (let i = 0; i < length(config.bss); i++) { + let bss = config.bss[i]; + if (bss.default_macaddr) + bss.bssid = phydev.macaddr_next(); + } + let bss = config.bss[0]; let err = wdev_create(phy, bss.ifname, { mode: "ap" }); if (err) @@ -175,8 +199,64 @@ function bss_reload_psk(bss, config, old_config) hostapd.printf(`Reload WPA PSK file for bss ${config.ifname}: ${ret}`); } -function iface_reload_config(phy, config, old_config) +function remove_file_fields(config) { + return filter(config, (line) => !hostapd.data.file_fields[split(line, "=")[0]]); +} + +function bss_remove_file_fields(config) +{ + let new_cfg = {}; + + for (let key in config) + new_cfg[key] = config[key]; + new_cfg.data = remove_file_fields(new_cfg.data); + new_cfg.hash = {}; + for (let key in config.hash) + new_cfg.hash[key] = config.hash[key]; + delete new_cfg.hash.wpa_psk_file; + + return new_cfg; +} + +function bss_config_hash(config) +{ + return hostapd.sha1(remove_file_fields(config) + ""); +} + +function bss_find_existing(config, prev_config, prev_hash) +{ + let hash = bss_config_hash(config.data); + + for (let i = 0; i < length(prev_config.bss); i++) { + if (!prev_hash[i] || hash != prev_hash[i]) + continue; + + prev_hash[i] = null; + return i; + } + + return -1; +} + +function get_config_bss(config, idx) +{ + if (!config.bss[idx]) { + hostapd.printf(`Invalid bss index ${idx}`); + return null; + } + + let ifname = config.bss[idx].ifname; + if (!ifname) + hostapd.printf(`Could not find bss ${config.bss[idx].ifname}`); + + return hostapd.bss[ifname]; +} + +function iface_reload_config(phydev, config, old_config) +{ + let phy = phydev.name; + if (!old_config || !is_equal(old_config.radio, config.radio)) return false; @@ -186,82 +266,231 @@ function iface_reload_config(phy, config, old_config) if (!old_config.bss || !old_config.bss[0]) return false; - if (config.bss[0].ifname != old_config.bss[0].ifname) - return false; - - let iface_name = config.bss[0].ifname; + let iface_name = old_config.bss[0].ifname; let iface = hostapd.interfaces[iface_name]; - if (!iface) + if (!iface) { + hostapd.printf(`Could not find previous interface ${iface_name}`); return false; + } let first_bss = hostapd.bss[iface_name]; - if (!first_bss) + if (!first_bss) { + hostapd.printf(`Could not find bss of previous interface ${iface_name}`); return false; + } + + let macaddr_list = iface_config_macaddr_list(config); + let bss_list = []; + let bss_list_cfg = []; + let prev_bss_hash = []; + + for (let bss in old_config.bss) { + let hash = bss_config_hash(bss.data); + push(prev_bss_hash, bss_config_hash(bss.data)); + } + + // Step 1: find (possibly renamed) interfaces with the same config + // and store them in the new order (with gaps) + for (let i = 0; i < length(config.bss); i++) { + let prev; + + // For fullmac devices, the first interface needs to be preserved, + // since it's treated as the master + if (!i && phy_is_fullmac(phy)) { + prev = 0; + prev_bss_hash[0] = null; + } else { + prev = bss_find_existing(config.bss[i], old_config, prev_bss_hash); + } + if (prev < 0) + continue; + + let cur_config = config.bss[i]; + let prev_config = old_config.bss[prev]; + + let prev_bss = get_config_bss(old_config, prev); + if (!prev_bss) + return false; + + // try to preserve MAC address of this BSS by reassigning another + // BSS if necessary + if (cur_config.default_macaddr && + !macaddr_list[prev_config.bssid]) { + macaddr_list[prev_config.bssid] = i; + cur_config.bssid = prev_config.bssid; + } + + bss_list[i] = prev_bss; + bss_list_cfg[i] = old_config.bss[prev]; + } + + if (config.mbssid && !bss_list_cfg[0]) { + hostapd.printf("First BSS changed with MBSSID enabled"); + return false; + } + + // Step 2: if none were found, rename and preserve the first one + if (length(bss_list) == 0) { + // can't change the bssid of the first bss + if (config.bss[0].bssid != old_config.bss[0].bssid) { + if (!config.bss[0].default_macaddr) { + hostapd.printf(`BSSID of first interface changed: ${lc(old_config.bss[0].bssid)} -> ${lc(config.bss[0].bssid)}`); + return false; + } + + config.bss[0].bssid = old_config.bss[0].bssid; + } + + let prev_bss = get_config_bss(old_config, 0); + if (!prev_bss) + return false; + + macaddr_list[config.bss[0].bssid] = 0; + bss_list[0] = prev_bss; + bss_list_cfg[0] = old_config.bss[0]; + prev_bss_hash[0] = null; + } + + // Step 3: delete all unused old interfaces + for (let i = 0; i < length(prev_bss_hash); i++) { + if (!prev_bss_hash[i]) + continue; + + let prev_bss = get_config_bss(old_config, i); + if (!prev_bss) + return false; + + let ifname = old_config.bss[i].ifname; + hostapd.printf(`Remove bss '${ifname}' on phy '${phy}'`); + prev_bss.delete(); + wdev_remove(ifname); + } + + // Step 4: rename preserved interfaces, use temporary name on duplicates + let rename_list = []; + for (let i = 0; i < length(bss_list); i++) { + if (!bss_list[i]) + continue; + + let old_ifname = bss_list_cfg[i].ifname; + let new_ifname = config.bss[i].ifname; + if (old_ifname == new_ifname) + continue; + + if (hostapd.bss[new_ifname]) { + new_ifname = "tmp_" + substr(hostapd.sha1(new_ifname), 0, 8); + push(rename_list, i); + } + + hostapd.printf(`Rename bss ${old_ifname} to ${new_ifname}`); + if (!bss_list[i].rename(new_ifname)) { + hostapd.printf(`Failed to rename bss ${old_ifname} to ${new_ifname}`); + return false; + } + + bss_list_cfg[i].ifname = new_ifname; + } + + // Step 5: rename interfaces with temporary names + for (let i in rename_list) { + let new_ifname = config.bss[i].ifname; + if (!bss_list[i].rename(new_ifname)) { + hostapd.printf(`Failed to rename bss to ${new_ifname}`); + return false; + } + bss_list_cfg[i].ifname = new_ifname; + } + + // Step 6: assign BSSID for newly created interfaces + let macaddr_data = { + num_global: config.num_global_macaddr ?? 1, + mbssid: config.mbssid ?? 0, + }; + macaddr_list = phydev.macaddr_init(macaddr_list, macaddr_data); + for (let i = 0; i < length(config.bss); i++) { + if (bss_list[i]) + continue; + let bsscfg = config.bss[i]; + + let mac_idx = macaddr_list[bsscfg.bssid]; + if (mac_idx < 0) + macaddr_list[bsscfg.bssid] = i; + if (mac_idx == i) + continue; + + // statically assigned bssid of the new interface is in conflict + // with the bssid of a reused interface. reassign the reused interface + if (!bsscfg.default_macaddr) { + // can't update bssid of the first BSS, need to restart + if (!mac_idx < 0) + return false; + + bsscfg = config.bss[mac_idx]; + } + + let addr = phydev.macaddr_next(i); + if (!addr) { + hostapd.printf(`Failed to generate mac address for phy ${phy}`); + return false; + } + bsscfg.bssid = addr; + } let config_inline = iface_gen_config(phy, config); - bss_reload_psk(first_bss, config.bss[0], old_config.bss[0]); - if (!is_equal(config.bss[0], old_config.bss[0])) { - if (phy_is_fullmac(phy)) - return false; + // Step 7: fill in the gaps with new interfaces + for (let i = 0; i < length(config.bss); i++) { + let ifname = config.bss[i].ifname; + let bss = bss_list[i]; - if (config.bss[0].bssid != old_config.bss[0].bssid) + if (bss) + continue; + + hostapd.printf(`Add bss ${ifname} on phy ${phy}`); + bss_list[i] = iface.add_bss(config_inline, i); + if (!bss_list[i]) { + hostapd.printf(`Failed to add new bss ${ifname} on phy ${phy}`); return false; + } + } + + // Step 8: update interface bss order + if (!iface.set_bss_order(bss_list)) { + hostapd.printf(`Failed to update BSS order on phy '${phy}'`); + return false; + } + + // Step 9: update config + for (let i = 0; i < length(config.bss); i++) { + if (!bss_list_cfg[i]) + continue; + + let ifname = config.bss[i].ifname; + let bss = bss_list[i]; + + if (is_equal(config.bss[i], bss_list_cfg[i])) + continue; + + if (is_equal(bss_remove_file_fields(config.bss[i]), + bss_remove_file_fields(bss_list_cfg[i]))) { + hostapd.printf(`Update config data files for bss ${ifname}`); + if (bss.set_config(config_inline, i, true) < 0) { + hostapd.printf(`Failed to update config data files for bss ${ifname}`); + return false; + } + bss.ctrl("RELOAD_WPA_PSK"); + continue; + } + + bss_reload_psk(bss, config.bss[i], bss_list_cfg[i]); + if (is_equal(config.bss[i], bss_list_cfg[i])) + continue; hostapd.printf(`Reload config for bss '${config.bss[0].ifname}' on phy '${phy}'`); - if (first_bss.set_config(config_inline, 0) < 0) { - hostapd.printf(`Failed to set config`); - return false; - } - } - - let new_cfg = array_to_obj(config.bss, "ifname", 1); - let old_cfg = array_to_obj(old_config.bss, "ifname", 1); - - for (let name in old_cfg) { - let bss = hostapd.bss[name]; - if (!bss) { - hostapd.printf(`bss '${name}' not found`); - return false; - } - - if (!new_cfg[name]) { - hostapd.printf(`Remove bss '${name}' on phy '${phy}'`); - bss.delete(); - wdev_remove(name); - continue; - } - - let new_cfg_data = new_cfg[name]; - delete new_cfg[name]; - - if (is_equal(old_cfg[name], new_cfg_data)) - continue; - - hostapd.printf(`Reload config for bss '${name}' on phy '${phy}'`); - let idx = find_array_idx(config.bss, "ifname", name); - if (idx < 0) { - hostapd.printf(`bss index not found`); - return false; - } - - if (bss.set_config(config_inline, idx) < 0) { - hostapd.printf(`Failed to set config`); - return false; - } - } - - for (let name in new_cfg) { - hostapd.printf(`Add bss '${name}' on phy '${phy}'`); - - let idx = find_array_idx(config.bss, "ifname", name); - if (idx < 0) { - hostapd.printf(`bss index not found`); - return false; - } - - if (iface.add_bss(config_inline, idx) < 0) { - hostapd.printf(`Failed to add bss`); + hostapd.printf(`old: ${bss_remove_file_fields(bss_list_cfg[i])}`); + hostapd.printf(`new: ${bss_remove_file_fields(config.bss[i])}`); + if (bss.set_config(config_inline, i) < 0) { + hostapd.printf(`Failed to set config for bss ${ifname}`); return false; } } @@ -269,6 +498,14 @@ function iface_reload_config(phy, config, old_config) return true; } +function iface_update_supplicant_macaddr(phy, config) +{ + let macaddr_list = []; + for (let i = 0; i < length(config.bss); i++) + push(macaddr_list, config.bss[i].bssid); + ubus.call("wpa_supplicant", "phy_set_macaddr_list", { phy: phy, macaddr: macaddr_list }); +} + function iface_set_config(phy, config) { let old_config = hostapd.data.config[phy]; @@ -278,14 +515,28 @@ function iface_set_config(phy, config) if (!config) return iface_remove(old_config); - let ret = iface_reload_config(phy, config, old_config); - if (ret) { - hostapd.printf(`Reloaded settings for phy ${phy}`); - return 0; + let phydev = phy_open(phy); + if (!phydev) { + hostapd.printf(`Failed to open phy ${phy}`); + return false; + } + + try { + let ret = iface_reload_config(phydev, config, old_config); + if (ret) { + iface_update_supplicant_macaddr(phy, config); + hostapd.printf(`Reloaded settings for phy ${phy}`); + return 0; + } + } catch (e) { + hostapd.printf(`Error reloading config: ${e}\n${e.stacktrace[0].context}`); } hostapd.printf(`Restart interface for phy ${phy}`); - return iface_restart(phy, config, old_config); + let ret = iface_restart(phydev, config, old_config); + iface_update_supplicant_macaddr(phy, config); + + return ret; } function config_add_bss(config, name) @@ -332,16 +583,28 @@ function iface_load_config(filename) continue; } + if (val[0] == "#num_global_macaddr" || + val[0] == "mbssid") + config[val[0]] = int(val[1]); + push(config.radio.data, line); } while ((line = trim(f.read("line"))) != null) { + if (line == "#default_macaddr") + bss.default_macaddr = true; + let val = split(line, "=", 2); if (!val[0]) continue; - if (val[0] == "bssid") - bss.bssid = val[1]; + if (val[0] == "bssid") { + bss.bssid = lc(val[1]); + continue; + } + + if (val[0] == "nas_identifier") + bss.nasid = val[1]; if (val[0] == "bss") { bss = config_add_bss(config, val[1]); @@ -358,27 +621,33 @@ function iface_load_config(filename) return config; } +function ex_wrap(func) { + return (req) => { + try { + let ret = func(req); + return ret; + } catch(e) { + hostapd.printf(`Exception in ubus function: ${e}\n${e.stacktrace[0].context}`); + } + return libubus.STATUS_UNKNOWN_ERROR; + }; +} let main_obj = { reload: { args: { phy: "", }, - call: function(req) { - try { - let phy_list = req.args.phy ? [ req.args.phy ] : keys(hostapd.data.config); - for (let phy_name in phy_list) { - let phy = hostapd.data.config[phy_name]; - let config = iface_load_config(phy.orig_file); - iface_set_config(phy_name, config); - } - } catch(e) { - hostapd.printf(`Error reloading config: ${e}\n${e.stacktrace[0].context}`); - return libubus.STATUS_INVALID_ARGUMENT; + call: ex_wrap(function(req) { + let phy_list = req.args.phy ? [ req.args.phy ] : keys(hostapd.data.config); + for (let phy_name in phy_list) { + let phy = hostapd.data.config[phy_name]; + let config = iface_load_config(phy.orig_file); + iface_set_config(phy_name, config); } return 0; - } + }) }, apsta_state: { args: { @@ -389,7 +658,7 @@ let main_obj = { csa: true, csa_count: 0, }, - call: function(req) { + call: ex_wrap(function(req) { if (req.args.up == null || !req.args.phy) return libubus.STATUS_INVALID_ARGUMENT; @@ -426,7 +695,28 @@ let main_obj = { return libubus.STATUS_UNKNOWN_ERROR; return 0; - } + }) + }, + config_get_macaddr_list: { + args: { + phy: "" + }, + call: ex_wrap(function(req) { + let phy = req.args.phy; + if (!phy) + return libubus.STATUS_INVALID_ARGUMENT; + + let ret = { + macaddr: [], + }; + + let config = hostapd.data.config[phy]; + if (!config) + return ret; + + ret.macaddr = map(config.bss, (bss) => bss.bssid); + return ret; + }) }, config_set: { args: { @@ -434,7 +724,7 @@ let main_obj = { config: "", prev_config: "", }, - call: function(req) { + call: ex_wrap(function(req) { let phy = req.args.phy; let file = req.args.config; let prev_file = req.args.prev_config; @@ -442,34 +732,29 @@ let main_obj = { if (!phy) return libubus.STATUS_INVALID_ARGUMENT; - try { - if (prev_file && !hostapd.data.config[phy]) { - let config = iface_load_config(prev_file); - if (config) - config.radio.data = []; - hostapd.data.config[phy] = config; - } - - let config = iface_load_config(file); - - hostapd.printf(`Set new config for phy ${phy}: ${file}`); - iface_set_config(phy, config); - } catch(e) { - hostapd.printf(`Error loading config: ${e}\n${e.stacktrace[0].context}`); - return libubus.STATUS_INVALID_ARGUMENT; + if (prev_file && !hostapd.data.config[phy]) { + let config = iface_load_config(prev_file); + if (config) + config.radio.data = []; + hostapd.data.config[phy] = config; } + let config = iface_load_config(file); + + hostapd.printf(`Set new config for phy ${phy}: ${file}`); + iface_set_config(phy, config); + return { pid: hostapd.getpid() }; - } + }) }, config_add: { args: { iface: "", config: "", }, - call: function(req) { + call: ex_wrap(function(req) { if (!req.args.iface || !req.args.config) return libubus.STATUS_INVALID_ARGUMENT; @@ -479,19 +764,19 @@ let main_obj = { return { pid: hostapd.getpid() }; - } + }) }, config_remove: { args: { iface: "" }, - call: function(req) { + call: ex_wrap(function(req) { if (!req.args.iface) return libubus.STATUS_INVALID_ARGUMENT; hostapd.remove_iface(req.args.iface); return 0; - } + }) }, }; diff --git a/package/network/services/hostapd/files/wdev.uc b/package/network/services/hostapd/files/wdev.uc index 78037a9d271..8a031b40b9e 100644 --- a/package/network/services/hostapd/files/wdev.uc +++ b/package/network/services/hostapd/files/wdev.uc @@ -1,11 +1,14 @@ #!/usr/bin/env ucode 'use strict'; -import { vlist_new, is_equal, wdev_create, wdev_remove } from "/usr/share/hostap/common.uc"; +import { vlist_new, is_equal, wdev_create, wdev_remove, phy_open } from "/usr/share/hostap/common.uc"; import { readfile, writefile, basename, readlink, glob } from "fs"; +let libubus = require("ubus"); let keep_devices = {}; let phy = shift(ARGV); -let new_config = shift(ARGV); +let command = shift(ARGV); +let phydev; + const mesh_params = [ "mesh_retry_timeout", "mesh_confirm_timeout", "mesh_holding_timeout", "mesh_max_peer_links", "mesh_max_retries", "mesh_ttl", "mesh_element_ttl", "mesh_hwmp_max_preq_retries", @@ -33,6 +36,11 @@ function iface_start(wdev) system([ "ip", "link", "set", "dev", ifname, "down" ]); wdev_remove(ifname); } + let wdev_config = {}; + for (let key in wdev) + wdev_config[key] = wdev[key]; + if (!wdev_config.macaddr && wdev.mode != "monitor") + wdev_config.macaddr = phydev.macaddr_next(); wdev_create(phy, ifname, wdev); system([ "ip", "link", "set", "dev", ifname, "up" ]); if (wdev.freq) @@ -114,43 +122,86 @@ function add_existing(phy, config) } } +function usage() +{ + warn(`Usage: ${basename(sourcepath())} [] -let statefile = `/var/run/wdev-${phy}.json`; - -for (let dev in ARGV) - keep_devices[dev] = true; - -if (!phy || !new_config) { - warn(`Usage: ${basename(sourcepath())} [ [ - get phy MAC address for vif index +`); exit(1); } -if (!readfile(`/sys/class/ieee80211/${phy}/index`)) { +const commands = { + set_config: function(args) { + let statefile = `/var/run/wdev-${phy}.json`; + + let new_config = shift(args); + for (let dev in ARGV) + keep_devices[dev] = true; + + if (!new_config) + usage(); + + new_config = json(new_config); + if (!new_config) { + warn("Invalid configuration\n"); + exit(1); + } + + let old_config = readfile(statefile); + if (old_config) + old_config = json(old_config); + + let config = vlist_new(iface_cb); + if (type(old_config) == "object") + config.data = old_config; + + add_existing(phy, config.data); + add_ifname(config.data); + drop_inactive(config.data); + + let ubus = libubus.connect(); + let data = ubus.call("hostapd", "config_get_macaddr_list", { phy: phy }); + let macaddr_list = []; + if (type(data) == "object" && data.macaddr) + macaddr_list = data.macaddr; + ubus.disconnect(); + phydev.macaddr_init(macaddr_list); + + add_ifname(new_config); + config.update(new_config); + + drop_inactive(config.data); + delete_ifname(config.data); + writefile(statefile, sprintf("%J", config.data)); + }, + get_macaddr: function(args) { + let data = {}; + + for (let arg in args) { + arg = split(arg, "=", 2); + data[arg[0]] = arg[1]; + } + + let macaddr = phydev.macaddr_generate(data); + if (!macaddr) { + warn(`Could not get MAC address for phy ${phy}\n`); + exit(1); + } + + print(macaddr + "\n"); + }, +}; + +if (!phy || !command | !commands[command]) + usage(); + +phydev = phy_open(phy); +if (!phydev) { warn(`PHY ${phy} does not exist\n`); exit(1); } -new_config = json(new_config); -if (!new_config) { - warn("Invalid configuration\n"); - exit(1); -} - -let old_config = readfile(statefile); -if (old_config) - old_config = json(old_config); - -let config = vlist_new(iface_cb); -if (type(old_config) == "object") - config.data = old_config; - -add_existing(phy, config.data); -add_ifname(config.data); -drop_inactive(config.data); - -add_ifname(new_config); -config.update(new_config); - -drop_inactive(config.data); -delete_ifname(config.data); -writefile(statefile, sprintf("%J", config.data)); +commands[command](ARGV); diff --git a/package/network/services/hostapd/files/wpa_supplicant.uc b/package/network/services/hostapd/files/wpa_supplicant.uc index f8a3fcb5253..cb5f41b1af3 100644 --- a/package/network/services/hostapd/files/wpa_supplicant.uc +++ b/package/network/services/hostapd/files/wpa_supplicant.uc @@ -1,11 +1,12 @@ let libubus = require("ubus"); import { open, readfile } from "fs"; -import { wdev_create, wdev_remove, is_equal, vlist_new } from "common"; +import { wdev_create, wdev_remove, is_equal, vlist_new, phy_open } from "common"; let ubus = libubus.connect(); wpas.data.config = {}; wpas.data.iface_phy = {}; +wpas.data.macaddr_list = {}; function iface_stop(iface) { @@ -20,16 +21,23 @@ function iface_stop(iface) iface.running = false; } -function iface_start(phy, iface) +function iface_start(phydev, iface, macaddr_list) { + let phy = phydev.name; + if (iface.running) return; let ifname = iface.config.iface; + let wdev_config = {}; + for (let field in iface.config) + wdev_config[field] = iface.config[field]; + if (!wdev_config.macaddr) + wdev_config.macaddr = phydev.macaddr_next(); wpas.data.iface_phy[ifname] = phy; wdev_remove(ifname); - let ret = wdev_create(phy, ifname, iface.config); + let ret = wdev_create(phy, ifname, wdev_config); if (ret) wpas.printf(`Failed to create device ${ifname}: ${ret}`); wpas.add_iface(iface.config); @@ -78,9 +86,22 @@ function set_config(phy_name, config_list) function start_pending(phy_name) { let phy = wpas.data.config[phy_name]; + let ubus = wpas.data.ubus; + + if (!phy || !phy.data) + return; + + let phydev = phy_open(phy_name); + if (!phydev) { + wpas.printf(`Could not open phy ${phy_name}`); + return; + } + + let macaddr_list = wpas.data.macaddr_list[phy_name]; + phydev.macaddr_init(macaddr_list); for (let ifname in phy.data) - iface_start(phy_name, phy.data[ifname]); + iface_start(phydev, phy.data[ifname]); } let main_obj = { @@ -111,6 +132,20 @@ let main_obj = { return 0; } }, + phy_set_macaddr_list: { + args: { + phy: "", + macaddr: [], + }, + call: function(req) { + let phy = req.args.phy; + if (!phy) + return libubus.STATUS_INVALID_ARGUMENT; + + wpas.data.macaddr_list[phy] = req.args.macaddr; + return 0; + } + }, phy_status: { args: { phy: "" diff --git a/package/network/services/hostapd/patches/011-mesh-use-deterministic-channel-on-channel-switch.patch b/package/network/services/hostapd/patches/011-mesh-use-deterministic-channel-on-channel-switch.patch index 9b11f0e8031..07b7a5971d3 100644 --- a/package/network/services/hostapd/patches/011-mesh-use-deterministic-channel-on-channel-switch.patch +++ b/package/network/services/hostapd/patches/011-mesh-use-deterministic-channel-on-channel-switch.patch @@ -29,7 +29,7 @@ Signed-off-by: Markus Theil enum dfs_channel_type { -@@ -521,9 +522,14 @@ dfs_get_valid_channel(struct hostapd_ifa +@@ -526,9 +527,14 @@ dfs_get_valid_channel(struct hostapd_ifa int num_available_chandefs; int chan_idx, chan_idx2; int sec_chan_idx_80p80 = -1; @@ -44,7 +44,7 @@ Signed-off-by: Markus Theil wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); *secondary_channel = 0; *oper_centr_freq_seg0_idx = 0; -@@ -543,8 +549,20 @@ dfs_get_valid_channel(struct hostapd_ifa +@@ -548,8 +554,20 @@ dfs_get_valid_channel(struct hostapd_ifa if (num_available_chandefs == 0) return NULL; @@ -68,7 +68,7 @@ Signed-off-by: Markus Theil if (!chan) { --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c -@@ -10977,6 +10977,10 @@ static int nl80211_switch_channel(void * +@@ -11017,6 +11017,10 @@ static int nl80211_switch_channel(void * if (ret) goto error; diff --git a/package/network/services/hostapd/patches/021-fix-sta-add-after-previous-connection.patch b/package/network/services/hostapd/patches/021-fix-sta-add-after-previous-connection.patch index 4ee43b5186a..edf599e3e28 100644 --- a/package/network/services/hostapd/patches/021-fix-sta-add-after-previous-connection.patch +++ b/package/network/services/hostapd/patches/021-fix-sta-add-after-previous-connection.patch @@ -1,6 +1,6 @@ --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c -@@ -4601,6 +4601,13 @@ static int add_associated_sta(struct hos +@@ -4621,6 +4621,13 @@ static int add_associated_sta(struct hos * drivers to accept the STA parameter configuration. Since this is * after a new FT-over-DS exchange, a new TK has been derived, so key * reinstallation is not a concern for this case. @@ -14,7 +14,7 @@ */ wpa_printf(MSG_DEBUG, "Add associated STA " MACSTR " (added_unassoc=%d auth_alg=%u ft_over_ds=%u reassoc=%d authorized=%d ft_tk=%d fils_tk=%d)", -@@ -4614,7 +4621,8 @@ static int add_associated_sta(struct hos +@@ -4634,7 +4641,8 @@ static int add_associated_sta(struct hos (!(sta->flags & WLAN_STA_AUTHORIZED) || (reassoc && sta->ft_over_ds && sta->auth_alg == WLAN_AUTH_FT) || (!wpa_auth_sta_ft_tk_already_set(sta->wpa_sm) && diff --git a/package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch b/package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch index 19248e80d8c..ef2bb408fb2 100644 --- a/package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch +++ b/package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch @@ -92,7 +92,7 @@ Signed-off-by: Felix Fietkau if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) { wpa_printf(MSG_DEBUG, -@@ -11843,13 +11840,14 @@ static int wpa_driver_br_add_ip_neigh(vo +@@ -11883,13 +11880,14 @@ static int wpa_driver_br_add_ip_neigh(vo const u8 *ipaddr, int prefixlen, const u8 *addr) { @@ -112,7 +112,7 @@ Signed-off-by: Felix Fietkau int res; if (!ipaddr || prefixlen == 0 || !addr) -@@ -11868,85 +11866,66 @@ static int wpa_driver_br_add_ip_neigh(vo +@@ -11908,85 +11906,66 @@ static int wpa_driver_br_add_ip_neigh(vo } if (version == 4) { @@ -220,7 +220,7 @@ Signed-off-by: Felix Fietkau addrsize = 16; } else { return -EINVAL; -@@ -11964,41 +11943,30 @@ static int wpa_driver_br_delete_ip_neigh +@@ -12004,41 +11983,30 @@ static int wpa_driver_br_delete_ip_neigh return -1; } diff --git a/package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch b/package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch index f98d3806dc1..b7bf9e351e0 100644 --- a/package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch +++ b/package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch @@ -16,7 +16,7 @@ Signed-off-by: Felix Fietkau --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c -@@ -3012,15 +3012,6 @@ static void handle_auth(struct hostapd_d +@@ -3020,15 +3020,6 @@ static void handle_auth(struct hostapd_d seq_ctrl); return; } diff --git a/package/network/services/hostapd/patches/140-tests-Makefile-make-run-tests-with-CONFIG_TLS.patch b/package/network/services/hostapd/patches/140-tests-Makefile-make-run-tests-with-CONFIG_TLS.patch index 148c268f9ca..e967cff427e 100644 --- a/package/network/services/hostapd/patches/140-tests-Makefile-make-run-tests-with-CONFIG_TLS.patch +++ b/package/network/services/hostapd/patches/140-tests-Makefile-make-run-tests-with-CONFIG_TLS.patch @@ -903,7 +903,7 @@ Signed-off-by: Glenn Strauss for exp, flags in tests: hapd.disable() hapd.set("tls_flags", flags) -@@ -7115,6 +7173,7 @@ def test_ap_wpa2_eap_assoc_rsn(dev, apde +@@ -7138,6 +7196,7 @@ def test_ap_wpa2_eap_assoc_rsn(dev, apde def test_eap_tls_ext_cert_check(dev, apdev): """EAP-TLS and external server certification validation""" # With internal server certificate chain validation @@ -911,7 +911,7 @@ Signed-off-by: Glenn Strauss id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TLS", identity="tls user", ca_cert="auth_serv/ca.pem", -@@ -7127,6 +7186,7 @@ def test_eap_tls_ext_cert_check(dev, apd +@@ -7150,6 +7209,7 @@ def test_eap_tls_ext_cert_check(dev, apd def test_eap_ttls_ext_cert_check(dev, apdev): """EAP-TTLS and external server certification validation""" # Without internal server certificate chain validation @@ -919,7 +919,7 @@ Signed-off-by: Glenn Strauss id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS", identity="pap user", anonymous_identity="ttls", password="password", phase2="auth=PAP", -@@ -7137,6 +7197,7 @@ def test_eap_ttls_ext_cert_check(dev, ap +@@ -7160,6 +7220,7 @@ def test_eap_ttls_ext_cert_check(dev, ap def test_eap_peap_ext_cert_check(dev, apdev): """EAP-PEAP and external server certification validation""" # With internal server certificate chain validation @@ -927,7 +927,7 @@ Signed-off-by: Glenn Strauss id = dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="PEAP", identity="user", anonymous_identity="peap", ca_cert="auth_serv/ca.pem", -@@ -7147,6 +7208,7 @@ def test_eap_peap_ext_cert_check(dev, ap +@@ -7170,6 +7231,7 @@ def test_eap_peap_ext_cert_check(dev, ap def test_eap_fast_ext_cert_check(dev, apdev): """EAP-FAST and external server certification validation""" @@ -935,7 +935,7 @@ Signed-off-by: Glenn Strauss check_eap_capa(dev[0], "FAST") # With internal server certificate chain validation dev[0].request("SET blob fast_pac_auth_ext ") -@@ -7161,10 +7223,6 @@ def test_eap_fast_ext_cert_check(dev, ap +@@ -7184,10 +7246,6 @@ def test_eap_fast_ext_cert_check(dev, ap run_ext_cert_check(dev, apdev, id) def run_ext_cert_check(dev, apdev, net_id): @@ -948,7 +948,7 @@ Signed-off-by: Glenn Strauss --- a/tests/hwsim/test_ap_ft.py +++ b/tests/hwsim/test_ap_ft.py -@@ -2471,11 +2471,11 @@ def test_ap_ft_ap_oom5(dev, apdev): +@@ -2474,11 +2474,11 @@ def test_ap_ft_ap_oom5(dev, apdev): # This will fail to roam dev[0].roam(bssid1, check_bssid=False) @@ -1138,7 +1138,7 @@ Signed-off-by: Glenn Strauss heavy_groups = [14, 15, 16] suitable_groups = [15, 16, 17, 18, 19, 20, 21] groups = [str(g) for g in sae_groups] -@@ -2188,6 +2193,8 @@ def run_sae_pwe_group(dev, apdev, group) +@@ -2193,6 +2198,8 @@ def run_sae_pwe_group(dev, apdev, group) logger.info("Add Brainpool EC groups since OpenSSL is new enough") elif tls.startswith("wolfSSL"): logger.info("Make sure Brainpool EC groups were enabled when compiling wolfSSL") diff --git a/package/network/services/hostapd/patches/170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch b/package/network/services/hostapd/patches/170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch index 710a3c851e1..b0151b071f6 100644 --- a/package/network/services/hostapd/patches/170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch +++ b/package/network/services/hostapd/patches/170-hostapd-update-cfs0-and-cfs1-for-160MHz.patch @@ -120,7 +120,7 @@ Signed-off-by: P Praneesh * Convert 80+80 MHz channel width to new style as interop --- a/src/common/hw_features_common.c +++ b/src/common/hw_features_common.c -@@ -808,6 +808,7 @@ int ieee80211ac_cap_check(u32 hw, u32 co +@@ -811,6 +811,7 @@ int ieee80211ac_cap_check(u32 hw, u32 co VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB); VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN); VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN); @@ -130,7 +130,7 @@ Signed-off-by: P Praneesh #undef VHT_CAP_CHECK_MAX --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h -@@ -1348,6 +1348,8 @@ struct ieee80211_ampe_ie { +@@ -1349,6 +1349,8 @@ struct ieee80211_ampe_ie { #define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB ((u32) BIT(26) | BIT(27)) #define VHT_CAP_RX_ANTENNA_PATTERN ((u32) BIT(28)) #define VHT_CAP_TX_ANTENNA_PATTERN ((u32) BIT(29)) diff --git a/package/network/services/hostapd/patches/180-BSS-coloring-fix-CCA-with-multiple-BSS.patch b/package/network/services/hostapd/patches/180-BSS-coloring-fix-CCA-with-multiple-BSS.patch deleted file mode 100644 index 7b0435a4533..00000000000 --- a/package/network/services/hostapd/patches/180-BSS-coloring-fix-CCA-with-multiple-BSS.patch +++ /dev/null @@ -1,103 +0,0 @@ -From: Felix Fietkau -Date: Mon, 7 Aug 2023 21:55:57 +0200 -Subject: [PATCH] BSS coloring: fix CCA with multiple BSS - -Pass bss->ctx instead of drv->ctx in order to avoid multiple reports for -the first bss. The first report would otherwise clear hapd->cca_color and -subsequent reports would cause the iface bss color to be set to 0. -In order to avoid any issues with cancellations, only overwrite the color -based on hapd->cca_color if it was actually set. - -Fixes: 33c4dd26cd11 ("BSS coloring: Handle the collision and CCA events coming from the kernel") -Signed-off-by: Felix Fietkau ---- - ---- a/src/ap/drv_callbacks.c -+++ b/src/ap/drv_callbacks.c -@@ -2260,7 +2260,8 @@ void wpa_supplicant_event(void *ctx, enu - case EVENT_CCA_NOTIFY: - wpa_printf(MSG_DEBUG, "CCA finished on on %s", - hapd->conf->iface); -- hapd->iface->conf->he_op.he_bss_color = hapd->cca_color; -+ if (hapd->cca_color) -+ hapd->iface->conf->he_op.he_bss_color = hapd->cca_color; - hostapd_cleanup_cca_params(hapd); - break; - #endif /* CONFIG_IEEE80211AX */ ---- a/src/drivers/driver_nl80211_event.c -+++ b/src/drivers/driver_nl80211_event.c -@@ -3653,7 +3653,7 @@ static void nl80211_assoc_comeback(struc - - #ifdef CONFIG_IEEE80211AX - --static void nl80211_obss_color_collision(struct wpa_driver_nl80211_data *drv, -+static void nl80211_obss_color_collision(struct i802_bss *bss, - struct nlattr *tb[]) - { - union wpa_event_data data; -@@ -3667,37 +3667,37 @@ static void nl80211_obss_color_collision - - wpa_printf(MSG_DEBUG, "nl80211: BSS color collision - bitmap %08llx", - (long long unsigned int) data.bss_color_collision.bitmap); -- wpa_supplicant_event(drv->ctx, EVENT_BSS_COLOR_COLLISION, &data); -+ wpa_supplicant_event(bss->ctx, EVENT_BSS_COLOR_COLLISION, &data); - } - - - static void --nl80211_color_change_announcement_started(struct wpa_driver_nl80211_data *drv) -+nl80211_color_change_announcement_started(struct i802_bss *bss) - { - union wpa_event_data data = {}; - - wpa_printf(MSG_DEBUG, "nl80211: CCA started"); -- wpa_supplicant_event(drv->ctx, EVENT_CCA_STARTED_NOTIFY, &data); -+ wpa_supplicant_event(bss->ctx, EVENT_CCA_STARTED_NOTIFY, &data); - } - - - static void --nl80211_color_change_announcement_aborted(struct wpa_driver_nl80211_data *drv) -+nl80211_color_change_announcement_aborted(struct i802_bss *bss) - { - union wpa_event_data data = {}; - - wpa_printf(MSG_DEBUG, "nl80211: CCA aborted"); -- wpa_supplicant_event(drv->ctx, EVENT_CCA_ABORTED_NOTIFY, &data); -+ wpa_supplicant_event(bss->ctx, EVENT_CCA_ABORTED_NOTIFY, &data); - } - - - static void --nl80211_color_change_announcement_completed(struct wpa_driver_nl80211_data *drv) -+nl80211_color_change_announcement_completed(struct i802_bss *bss) - { - union wpa_event_data data = {}; - - wpa_printf(MSG_DEBUG, "nl80211: CCA completed"); -- wpa_supplicant_event(drv->ctx, EVENT_CCA_NOTIFY, &data); -+ wpa_supplicant_event(bss->ctx, EVENT_CCA_NOTIFY, &data); - } - - #endif /* CONFIG_IEEE80211AX */ -@@ -3957,16 +3957,16 @@ static void do_process_drv_event(struct - break; - #ifdef CONFIG_IEEE80211AX - case NL80211_CMD_OBSS_COLOR_COLLISION: -- nl80211_obss_color_collision(drv, tb); -+ nl80211_obss_color_collision(bss, tb); - break; - case NL80211_CMD_COLOR_CHANGE_STARTED: -- nl80211_color_change_announcement_started(drv); -+ nl80211_color_change_announcement_started(bss); - break; - case NL80211_CMD_COLOR_CHANGE_ABORTED: -- nl80211_color_change_announcement_aborted(drv); -+ nl80211_color_change_announcement_aborted(bss); - break; - case NL80211_CMD_COLOR_CHANGE_COMPLETED: -- nl80211_color_change_announcement_completed(drv); -+ nl80211_color_change_announcement_completed(bss); - break; - #endif /* CONFIG_IEEE80211AX */ - default: diff --git a/package/network/services/hostapd/patches/200-multicall.patch b/package/network/services/hostapd/patches/200-multicall.patch index 8ebbed0c32c..e3ed00f2ded 100644 --- a/package/network/services/hostapd/patches/200-multicall.patch +++ b/package/network/services/hostapd/patches/200-multicall.patch @@ -156,7 +156,7 @@ wpa_cli.exe: wpa_cli --- a/src/drivers/driver.h +++ b/src/drivers/driver.h -@@ -6651,8 +6651,8 @@ union wpa_event_data { +@@ -6667,8 +6667,8 @@ union wpa_event_data { * Driver wrapper code should call this function whenever an event is received * from the driver. */ @@ -167,7 +167,7 @@ /** * wpa_supplicant_event_global - Report a driver event for wpa_supplicant -@@ -6664,7 +6664,7 @@ void wpa_supplicant_event(void *ctx, enu +@@ -6680,7 +6680,7 @@ void wpa_supplicant_event(void *ctx, enu * Same as wpa_supplicant_event(), but we search for the interface in * wpa_global. */ @@ -178,7 +178,7 @@ /* --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c -@@ -1994,8 +1994,8 @@ err: +@@ -2184,8 +2184,8 @@ err: #endif /* CONFIG_OWE */ @@ -189,7 +189,7 @@ { struct hostapd_data *hapd = ctx; #ifndef CONFIG_NO_STDOUT_DEBUG -@@ -2272,7 +2272,7 @@ void wpa_supplicant_event(void *ctx, enu +@@ -2489,7 +2489,7 @@ void wpa_supplicant_event(void *ctx, enu } @@ -231,7 +231,7 @@ os_memset(&global, 0, sizeof(global)); --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c -@@ -5345,8 +5345,8 @@ static void wpas_link_reconfig(struct wp +@@ -5353,8 +5353,8 @@ static void wpas_link_reconfig(struct wp } @@ -242,7 +242,7 @@ { struct wpa_supplicant *wpa_s = ctx; int resched; -@@ -6264,7 +6264,7 @@ void wpa_supplicant_event(void *ctx, enu +@@ -6272,7 +6272,7 @@ void wpa_supplicant_event(void *ctx, enu } @@ -253,7 +253,7 @@ struct wpa_supplicant *wpa_s; --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c -@@ -7435,7 +7435,6 @@ struct wpa_interface * wpa_supplicant_ma +@@ -7462,7 +7462,6 @@ struct wpa_interface * wpa_supplicant_ma return NULL; } @@ -261,7 +261,7 @@ /** * wpa_supplicant_match_existing - Match existing interfaces * @global: Pointer to global data from wpa_supplicant_init() -@@ -7470,6 +7469,11 @@ static int wpa_supplicant_match_existing +@@ -7497,6 +7496,11 @@ static int wpa_supplicant_match_existing #endif /* CONFIG_MATCH_IFACE */ @@ -273,7 +273,7 @@ /** * wpa_supplicant_add_iface - Add a new network interface -@@ -7726,6 +7730,8 @@ struct wpa_global * wpa_supplicant_init( +@@ -7753,6 +7757,8 @@ struct wpa_global * wpa_supplicant_init( #ifndef CONFIG_NO_WPA_MSG wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb); #endif /* CONFIG_NO_WPA_MSG */ @@ -284,7 +284,7 @@ wpa_debug_open_file(params->wpa_debug_file_path); --- a/hostapd/main.c +++ b/hostapd/main.c -@@ -685,6 +685,11 @@ fail: +@@ -698,6 +698,11 @@ fail: return -1; } @@ -296,7 +296,7 @@ #ifdef CONFIG_WPS static int gen_uuid(const char *txt_addr) -@@ -778,6 +783,8 @@ int main(int argc, char *argv[]) +@@ -791,6 +796,8 @@ int main(int argc, char *argv[]) return -1; #endif /* CONFIG_DPP */ diff --git a/package/network/services/hostapd/patches/300-noscan.patch b/package/network/services/hostapd/patches/300-noscan.patch index 1ea89043e89..3b5f4325de0 100644 --- a/package/network/services/hostapd/patches/300-noscan.patch +++ b/package/network/services/hostapd/patches/300-noscan.patch @@ -13,7 +13,7 @@ } else if (os_strcmp(buf, "ht_capab") == 0) { --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h -@@ -1072,6 +1072,8 @@ struct hostapd_config { +@@ -1075,6 +1075,8 @@ struct hostapd_config { int ht_op_mode_fixed; u16 ht_capab; @@ -24,7 +24,7 @@ int no_pri_sec_switch; --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c -@@ -517,7 +517,8 @@ static int ieee80211n_check_40mhz(struct +@@ -546,7 +546,8 @@ static int ieee80211n_check_40mhz(struct int ret; /* Check that HT40 is used and PRI / SEC switch is allowed */ diff --git a/package/network/services/hostapd/patches/310-rescan_immediately.patch b/package/network/services/hostapd/patches/310-rescan_immediately.patch index a47546d38fc..e12b2059b3e 100644 --- a/package/network/services/hostapd/patches/310-rescan_immediately.patch +++ b/package/network/services/hostapd/patches/310-rescan_immediately.patch @@ -1,6 +1,6 @@ --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c -@@ -5740,7 +5740,7 @@ wpa_supplicant_alloc(struct wpa_supplica +@@ -5767,7 +5767,7 @@ wpa_supplicant_alloc(struct wpa_supplica if (wpa_s == NULL) return NULL; wpa_s->scan_req = INITIAL_SCAN_REQ; diff --git a/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch b/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch index 54a736fe915..f7720fce2fa 100644 --- a/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch +++ b/package/network/services/hostapd/patches/380-disable_ctrl_iface_mib.patch @@ -51,7 +51,7 @@ if (wpa_s->ap_iface) { pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos, end - pos, -@@ -11964,6 +11964,7 @@ char * wpa_supplicant_ctrl_iface_process +@@ -12087,6 +12087,7 @@ char * wpa_supplicant_ctrl_iface_process reply_len = -1; } else if (os_strncmp(buf, "NOTE ", 5) == 0) { wpa_printf(MSG_INFO, "NOTE: %s", buf + 5); @@ -59,7 +59,7 @@ } else if (os_strcmp(buf, "MIB") == 0) { reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size); if (reply_len >= 0) { -@@ -11976,6 +11977,7 @@ char * wpa_supplicant_ctrl_iface_process +@@ -12099,6 +12100,7 @@ char * wpa_supplicant_ctrl_iface_process reply_size - reply_len); #endif /* CONFIG_MACSEC */ } @@ -67,7 +67,7 @@ } else if (os_strncmp(buf, "STATUS", 6) == 0) { reply_len = wpa_supplicant_ctrl_iface_status( wpa_s, buf + 6, reply, reply_size); -@@ -12464,6 +12466,7 @@ char * wpa_supplicant_ctrl_iface_process +@@ -12587,6 +12589,7 @@ char * wpa_supplicant_ctrl_iface_process reply_len = wpa_supplicant_ctrl_iface_bss( wpa_s, buf + 4, reply, reply_size); #ifdef CONFIG_AP @@ -75,7 +75,7 @@ } else if (os_strcmp(buf, "STA-FIRST") == 0) { reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size); } else if (os_strncmp(buf, "STA ", 4) == 0) { -@@ -12472,12 +12475,15 @@ char * wpa_supplicant_ctrl_iface_process +@@ -12595,12 +12598,15 @@ char * wpa_supplicant_ctrl_iface_process } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) { reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply, reply_size); diff --git a/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch b/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch index 40c39ff29c7..4592c341277 100644 --- a/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch +++ b/package/network/services/hostapd/patches/390-wpa_ie_cap_workaround.patch @@ -1,6 +1,6 @@ --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c -@@ -2719,6 +2719,31 @@ u32 wpa_akm_to_suite(int akm) +@@ -2841,6 +2841,31 @@ u32 wpa_akm_to_suite(int akm) } @@ -32,7 +32,7 @@ int wpa_compare_rsn_ie(int ft_initial_assoc, const u8 *ie1, size_t ie1len, const u8 *ie2, size_t ie2len) -@@ -2726,8 +2751,19 @@ int wpa_compare_rsn_ie(int ft_initial_as +@@ -2848,8 +2873,19 @@ int wpa_compare_rsn_ie(int ft_initial_as if (ie1 == NULL || ie2 == NULL) return -1; diff --git a/package/network/services/hostapd/patches/420-indicate-features.patch b/package/network/services/hostapd/patches/420-indicate-features.patch index 3b28b6e7524..07df8e5a9af 100644 --- a/package/network/services/hostapd/patches/420-indicate-features.patch +++ b/package/network/services/hostapd/patches/420-indicate-features.patch @@ -9,7 +9,7 @@ struct hapd_global { void **drv_priv; -@@ -786,7 +786,7 @@ int main(int argc, char *argv[]) +@@ -799,7 +799,7 @@ int main(int argc, char *argv[]) wpa_supplicant_event = hostapd_wpa_event; wpa_supplicant_event_global = hostapd_wpa_event_global; for (;;) { @@ -18,7 +18,7 @@ if (c < 0) break; switch (c) { -@@ -823,6 +823,8 @@ int main(int argc, char *argv[]) +@@ -836,6 +836,8 @@ int main(int argc, char *argv[]) break; #endif /* CONFIG_DEBUG_LINUX_TRACING */ case 'v': diff --git a/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch b/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch index e50c609d976..c6fe54efed0 100644 --- a/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch +++ b/package/network/services/hostapd/patches/460-wpa_supplicant-add-new-config-params-to-be-used-with.patch @@ -174,7 +174,7 @@ Signed-hostap: Antonio Quartulli * macsec_policy - Determines the policy for MACsec secure session --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c -@@ -4149,6 +4149,12 @@ static void wpas_start_assoc_cb(struct w +@@ -4175,6 +4175,12 @@ static void wpas_start_assoc_cb(struct w params.beacon_int = ssid->beacon_int; else params.beacon_int = wpa_s->conf->beacon_int; diff --git a/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch b/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch index be9e0507d6d..f13e0569844 100644 --- a/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch +++ b/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch @@ -29,7 +29,7 @@ Tested-by: Simon Wunderlich struct wpa_driver_set_key_params { --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c -@@ -11626,6 +11626,18 @@ static int nl80211_put_mesh_id(struct nl +@@ -11666,6 +11666,18 @@ static int nl80211_put_mesh_id(struct nl } @@ -48,7 +48,7 @@ Tested-by: Simon Wunderlich static int nl80211_put_mesh_config(struct nl_msg *msg, struct wpa_driver_mesh_bss_params *params) { -@@ -11687,6 +11699,7 @@ static int nl80211_join_mesh(struct i802 +@@ -11727,6 +11739,7 @@ static int nl80211_join_mesh(struct i802 nl80211_put_basic_rates(msg, params->basic_rates) || nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) || nl80211_put_beacon_int(msg, params->beacon_int) || diff --git a/package/network/services/hostapd/patches/600-ubus_support.patch b/package/network/services/hostapd/patches/600-ubus_support.patch index 5b2745a3bee..bc80ef0e813 100644 --- a/package/network/services/hostapd/patches/600-ubus_support.patch +++ b/package/network/services/hostapd/patches/600-ubus_support.patch @@ -84,7 +84,7 @@ __func__, driver, drv_priv); --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c -@@ -2778,7 +2778,7 @@ static void handle_auth(struct hostapd_d +@@ -2786,7 +2786,7 @@ static void handle_auth(struct hostapd_d u16 auth_alg, auth_transaction, status_code; u16 resp = WLAN_STATUS_SUCCESS; struct sta_info *sta = NULL; @@ -93,7 +93,7 @@ u16 fc; const u8 *challenge = NULL; u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; -@@ -2787,6 +2787,11 @@ static void handle_auth(struct hostapd_d +@@ -2795,6 +2795,11 @@ static void handle_auth(struct hostapd_d struct radius_sta rad_info; const u8 *dst, *sa, *bssid; bool mld_sta = false; @@ -105,7 +105,7 @@ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)", -@@ -2978,6 +2983,13 @@ static void handle_auth(struct hostapd_d +@@ -2986,6 +2991,13 @@ static void handle_auth(struct hostapd_d resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } @@ -119,7 +119,7 @@ if (res == HOSTAPD_ACL_PENDING) return; -@@ -5141,7 +5153,7 @@ static void handle_assoc(struct hostapd_ +@@ -5161,7 +5173,7 @@ static void handle_assoc(struct hostapd_ int resp = WLAN_STATUS_SUCCESS; u16 reply_res = WLAN_STATUS_UNSPECIFIED_FAILURE; const u8 *pos; @@ -128,7 +128,7 @@ struct sta_info *sta; u8 *tmp = NULL; #ifdef CONFIG_FILS -@@ -5354,6 +5366,11 @@ static void handle_assoc(struct hostapd_ +@@ -5374,6 +5386,11 @@ static void handle_assoc(struct hostapd_ left = res; } #endif /* CONFIG_FILS */ @@ -140,7 +140,7 @@ /* followed by SSID and Supported rates; and HT capabilities if 802.11n * is used */ -@@ -5452,6 +5469,13 @@ static void handle_assoc(struct hostapd_ +@@ -5472,6 +5489,13 @@ static void handle_assoc(struct hostapd_ } #endif /* CONFIG_FILS */ @@ -154,7 +154,7 @@ fail: /* -@@ -5733,6 +5757,7 @@ static void handle_disassoc(struct hosta +@@ -5753,6 +5777,7 @@ static void handle_disassoc(struct hosta (unsigned long) len); return; } @@ -162,7 +162,7 @@ sta = ap_get_sta(hapd, mgmt->sa); if (!sta) { -@@ -5764,6 +5789,8 @@ static void handle_deauth(struct hostapd +@@ -5784,6 +5809,8 @@ static void handle_deauth(struct hostapd /* Clear the PTKSA cache entries for PASN */ ptksa_cache_flush(hapd->ptksa, mgmt->sa, WPA_CIPHER_NONE); @@ -201,7 +201,7 @@ --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c -@@ -145,6 +145,10 @@ int hostapd_notif_assoc(struct hostapd_d +@@ -260,6 +260,10 @@ int hostapd_notif_assoc(struct hostapd_d u16 reason = WLAN_REASON_UNSPECIFIED; int status = WLAN_STATUS_SUCCESS; const u8 *p2p_dev_addr = NULL; @@ -212,7 +212,7 @@ if (addr == NULL) { /* -@@ -237,6 +241,12 @@ int hostapd_notif_assoc(struct hostapd_d +@@ -396,6 +400,12 @@ int hostapd_notif_assoc(struct hostapd_d goto fail; } @@ -348,7 +348,7 @@ CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c -@@ -7566,6 +7566,8 @@ struct wpa_supplicant * wpa_supplicant_a +@@ -7593,6 +7593,8 @@ struct wpa_supplicant * wpa_supplicant_a } #endif /* CONFIG_P2P */ @@ -357,7 +357,7 @@ return wpa_s; } -@@ -7592,6 +7594,8 @@ int wpa_supplicant_remove_iface(struct w +@@ -7619,6 +7621,8 @@ int wpa_supplicant_remove_iface(struct w struct wpa_supplicant *parent = wpa_s->parent; #endif /* CONFIG_MESH */ @@ -366,7 +366,7 @@ /* Remove interface from the global list of interfaces */ prev = global->ifaces; if (prev == wpa_s) { -@@ -7938,8 +7942,12 @@ int wpa_supplicant_run(struct wpa_global +@@ -7965,8 +7969,12 @@ int wpa_supplicant_run(struct wpa_global eloop_register_signal_terminate(wpa_supplicant_terminate, global); eloop_register_signal_reconfig(wpa_supplicant_reconfig, global); @@ -398,7 +398,7 @@ }; -@@ -650,6 +653,7 @@ struct wpa_supplicant { +@@ -685,6 +688,7 @@ struct wpa_supplicant { unsigned char own_addr[ETH_ALEN]; unsigned char perm_addr[ETH_ALEN]; char ifname[100]; @@ -508,7 +508,7 @@ --- a/src/ap/dfs.c +++ b/src/ap/dfs.c -@@ -1211,6 +1211,8 @@ int hostapd_dfs_pre_cac_expired(struct h +@@ -1216,6 +1216,8 @@ int hostapd_dfs_pre_cac_expired(struct h "freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", freq, ht_enabled, chan_offset, chan_width, cf1, cf2); diff --git a/package/network/services/hostapd/patches/601-ucode_support.patch b/package/network/services/hostapd/patches/601-ucode_support.patch index e0bbf1337da..0e5eb6f104d 100644 --- a/package/network/services/hostapd/patches/601-ucode_support.patch +++ b/package/network/services/hostapd/patches/601-ucode_support.patch @@ -26,7 +26,7 @@ ifdef CONFIG_CODE_COVERAGE --- a/hostapd/main.c +++ b/hostapd/main.c -@@ -994,6 +994,7 @@ int main(int argc, char *argv[]) +@@ -1007,6 +1007,7 @@ int main(int argc, char *argv[]) } hostapd_global_ctrl_iface_init(&interfaces); @@ -34,7 +34,7 @@ if (hostapd_global_run(&interfaces, daemonize, pid_file)) { wpa_printf(MSG_ERROR, "Failed to start eloop"); -@@ -1003,6 +1004,7 @@ int main(int argc, char *argv[]) +@@ -1016,6 +1017,7 @@ int main(int argc, char *argv[]) ret = 0; out: @@ -186,7 +186,7 @@ #ifdef CONFIG_BGSCAN if (state == WPA_COMPLETED && wpa_s->current_ssid != wpa_s->bgscan_ssid) -@@ -7567,6 +7568,7 @@ struct wpa_supplicant * wpa_supplicant_a +@@ -7594,6 +7595,7 @@ struct wpa_supplicant * wpa_supplicant_a #endif /* CONFIG_P2P */ wpas_ubus_add_bss(wpa_s); @@ -194,7 +194,7 @@ return wpa_s; } -@@ -7594,6 +7596,7 @@ int wpa_supplicant_remove_iface(struct w +@@ -7621,6 +7623,7 @@ int wpa_supplicant_remove_iface(struct w struct wpa_supplicant *parent = wpa_s->parent; #endif /* CONFIG_MESH */ @@ -202,7 +202,7 @@ wpas_ubus_free_bss(wpa_s); /* Remove interface from the global list of interfaces */ -@@ -7904,6 +7907,7 @@ struct wpa_global * wpa_supplicant_init( +@@ -7931,6 +7934,7 @@ struct wpa_global * wpa_supplicant_init( eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0, wpas_periodic, global, NULL); @@ -210,7 +210,7 @@ return global; } -@@ -7942,12 +7946,8 @@ int wpa_supplicant_run(struct wpa_global +@@ -7969,12 +7973,8 @@ int wpa_supplicant_run(struct wpa_global eloop_register_signal_terminate(wpa_supplicant_terminate, global); eloop_register_signal_reconfig(wpa_supplicant_reconfig, global); @@ -223,7 +223,7 @@ return 0; } -@@ -7980,6 +7980,8 @@ void wpa_supplicant_deinit(struct wpa_gl +@@ -8007,6 +8007,8 @@ void wpa_supplicant_deinit(struct wpa_gl wpas_notify_supplicant_deinitialized(global); @@ -242,7 +242,7 @@ extern const char *const wpa_supplicant_version; extern const char *const wpa_supplicant_license; -@@ -654,6 +655,7 @@ struct wpa_supplicant { +@@ -689,6 +690,7 @@ struct wpa_supplicant { unsigned char perm_addr[ETH_ALEN]; char ifname[100]; struct wpas_ubus_bss ubus; @@ -270,7 +270,33 @@ --- a/src/drivers/driver.h +++ b/src/drivers/driver.h -@@ -6426,6 +6426,7 @@ union wpa_event_data { +@@ -3787,6 +3787,25 @@ struct wpa_driver_ops { + const char *ifname); + + /** ++ * if_rename - Rename a virtual interface ++ * @priv: Private driver interface data ++ * @type: Interface type ++ * @ifname: Interface name of the virtual interface to be renamed ++ * (NULL when renaming the AP BSS interface) ++ * @new_name: New interface name of the virtual interface ++ * Returns: 0 on success, -1 on failure ++ */ ++ int (*if_rename)(void *priv, enum wpa_driver_if_type type, ++ const char *ifname, const char *new_name); ++ ++ /** ++ * set_first_bss - Make a virtual interface the first (primary) bss ++ * @priv: Private driver interface data ++ * Returns: 0 on success, -1 on failure ++ */ ++ int (*set_first_bss)(void *priv); ++ ++ /** + * set_sta_vlan - Bind a station into a specific interface (AP only) + * @priv: Private driver interface data + * @ifname: Interface (main or virtual BSS or VLAN) +@@ -6440,6 +6459,7 @@ union wpa_event_data { /** * struct ch_switch @@ -278,7 +304,7 @@ * @freq: Frequency of new channel in MHz * @ht_enabled: Whether this is an HT channel * @ch_offset: Secondary channel offset -@@ -6436,6 +6437,7 @@ union wpa_event_data { +@@ -6450,6 +6470,7 @@ union wpa_event_data { * @punct_bitmap: Puncturing bitmap */ struct ch_switch { @@ -305,7 +331,7 @@ if (finished) bss->flink->freq = data.ch_switch.freq; -@@ -3848,6 +3851,7 @@ static void do_process_drv_event(struct +@@ -3912,6 +3915,7 @@ static void do_process_drv_event(struct tb[NL80211_ATTR_CENTER_FREQ1], tb[NL80211_ATTR_CENTER_FREQ2], tb[NL80211_ATTR_PUNCT_BITMAP], @@ -313,7 +339,7 @@ 0); break; case NL80211_CMD_CH_SWITCH_NOTIFY: -@@ -3860,6 +3864,7 @@ static void do_process_drv_event(struct +@@ -3924,6 +3928,7 @@ static void do_process_drv_event(struct tb[NL80211_ATTR_CENTER_FREQ1], tb[NL80211_ATTR_CENTER_FREQ2], tb[NL80211_ATTR_PUNCT_BITMAP], @@ -323,7 +349,7 @@ case NL80211_CMD_DISCONNECT: --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c -@@ -5381,6 +5381,7 @@ void supplicant_event(void *ctx, enum wp +@@ -5389,6 +5389,7 @@ void supplicant_event(void *ctx, enum wp event_to_string(event), event); #endif /* CONFIG_NO_STDOUT_DEBUG */ @@ -331,3 +357,187 @@ switch (event) { case EVENT_AUTH: #ifdef CONFIG_FST +--- a/src/ap/ap_drv_ops.h ++++ b/src/ap/ap_drv_ops.h +@@ -393,6 +393,23 @@ static inline int hostapd_drv_stop_ap(st + return hapd->driver->stop_ap(hapd->drv_priv); + } + ++static inline int hostapd_drv_if_rename(struct hostapd_data *hapd, ++ enum wpa_driver_if_type type, ++ const char *ifname, ++ const char *new_name) ++{ ++ if (!hapd->driver || !hapd->driver->if_rename || !hapd->drv_priv) ++ return -1; ++ return hapd->driver->if_rename(hapd->drv_priv, type, ifname, new_name); ++} ++ ++static inline int hostapd_drv_set_first_bss(struct hostapd_data *hapd) ++{ ++ if (!hapd->driver || !hapd->driver->set_first_bss || !hapd->drv_priv) ++ return 0; ++ return hapd->driver->set_first_bss(hapd->drv_priv); ++} ++ + static inline int hostapd_drv_channel_info(struct hostapd_data *hapd, + struct wpa_channel_info *ci) + { +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -1333,7 +1333,7 @@ static void wpa_driver_nl80211_event_rtm + } + wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)", + namebuf, ifname); +- if (os_strcmp(drv->first_bss->ifname, ifname) != 0) { ++ if (drv->first_bss->ifindex != ifi->ifi_index) { + wpa_printf(MSG_DEBUG, + "nl80211: Not the main interface (%s) - do not indicate interface down", + drv->first_bss->ifname); +@@ -1369,7 +1369,7 @@ static void wpa_driver_nl80211_event_rtm + } + wpa_printf(MSG_DEBUG, "nl80211: Interface up (%s/%s)", + namebuf, ifname); +- if (os_strcmp(drv->first_bss->ifname, ifname) != 0) { ++ if (drv->first_bss->ifindex != ifi->ifi_index) { + wpa_printf(MSG_DEBUG, + "nl80211: Not the main interface (%s) - do not indicate interface up", + drv->first_bss->ifname); +@@ -8432,6 +8432,7 @@ static void *i802_init(struct hostapd_da + char master_ifname[IFNAMSIZ]; + int ifindex, br_ifindex = 0; + int br_added = 0; ++ int err; + + bss = wpa_driver_nl80211_drv_init(hapd, params->ifname, + params->global_priv, 1, +@@ -8491,21 +8492,17 @@ static void *i802_init(struct hostapd_da + (params->num_bridge == 0 || !params->bridge[0])) + add_ifidx(drv, br_ifindex, drv->ifindex); + +- if (bss->added_if_into_bridge || bss->already_in_bridge) { +- int err; +- +- drv->rtnl_sk = nl_socket_alloc(); +- if (drv->rtnl_sk == NULL) { +- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock"); +- goto failed; +- } ++ drv->rtnl_sk = nl_socket_alloc(); ++ if (drv->rtnl_sk == NULL) { ++ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock"); ++ goto failed; ++ } + +- err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE); +- if (err) { +- wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s", +- nl_geterror(err)); +- goto failed; +- } ++ err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE); ++ if (err) { ++ wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s", ++ nl_geterror(err)); ++ goto failed; + } + + if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) { +@@ -8874,6 +8871,50 @@ static int wpa_driver_nl80211_if_remove( + return 0; + } + ++static int wpa_driver_nl80211_if_rename(struct i802_bss *bss, ++ enum wpa_driver_if_type type, ++ const char *ifname, const char *new_name) ++{ ++ struct wpa_driver_nl80211_data *drv = bss->drv; ++ struct ifinfomsg ifi = { ++ .ifi_family = AF_UNSPEC, ++ .ifi_index = bss->ifindex, ++ }; ++ struct nl_msg *msg; ++ int res = -ENOMEM; ++ ++ if (ifname) ++ ifi.ifi_index = if_nametoindex(ifname); ++ ++ msg = nlmsg_alloc_simple(RTM_SETLINK, 0); ++ if (!msg) ++ return res; ++ ++ if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) ++ goto out; ++ ++ if (nla_put_string(msg, IFLA_IFNAME, new_name)) ++ goto out; ++ ++ res = nl_send_auto_complete(drv->rtnl_sk, msg); ++ if (res < 0) ++ goto out; ++ ++ res = nl_wait_for_ack(drv->rtnl_sk); ++ if (res) { ++ wpa_printf(MSG_INFO, ++ "nl80211: Renaming device %s to %s failed: %s", ++ ifname ? ifname : bss->ifname, new_name, nl_geterror(res)); ++ goto out; ++ } ++ ++ if (type == WPA_IF_AP_BSS && !ifname) ++ os_strlcpy(bss->ifname, new_name, sizeof(bss->ifname)); ++ ++out: ++ nlmsg_free(msg); ++ return res; ++} + + static int cookie_handler(struct nl_msg *msg, void *arg) + { +@@ -10512,6 +10553,37 @@ static int driver_nl80211_if_remove(void + } + + ++static int driver_nl80211_if_rename(void *priv, enum wpa_driver_if_type type, ++ const char *ifname, const char *new_name) ++{ ++ struct i802_bss *bss = priv; ++ return wpa_driver_nl80211_if_rename(bss, type, ifname, new_name); ++} ++ ++ ++static int driver_nl80211_set_first_bss(void *priv) ++{ ++ struct i802_bss *bss = priv, *tbss; ++ struct wpa_driver_nl80211_data *drv = bss->drv; ++ ++ if (drv->first_bss == bss) ++ return 0; ++ ++ for (tbss = drv->first_bss; tbss; tbss = tbss->next) { ++ if (tbss->next != bss) ++ continue; ++ ++ tbss->next = bss->next; ++ bss->next = drv->first_bss; ++ drv->first_bss = bss; ++ drv->ctx = bss->ctx; ++ return 0; ++ } ++ ++ return -1; ++} ++ ++ + static int driver_nl80211_send_mlme(void *priv, const u8 *data, + size_t data_len, int noack, + unsigned int freq, +@@ -13696,6 +13768,8 @@ const struct wpa_driver_ops wpa_driver_n + .set_acl = wpa_driver_nl80211_set_acl, + .if_add = wpa_driver_nl80211_if_add, + .if_remove = driver_nl80211_if_remove, ++ .if_rename = driver_nl80211_if_rename, ++ .set_first_bss = driver_nl80211_set_first_bss, + .send_mlme = driver_nl80211_send_mlme, + .get_hw_feature_data = nl80211_get_hw_feature_data, + .sta_add = wpa_driver_nl80211_sta_add, diff --git a/package/network/services/hostapd/patches/701-reload_config_inline.patch b/package/network/services/hostapd/patches/701-reload_config_inline.patch index 44c8892bae9..3c62bf670f5 100644 --- a/package/network/services/hostapd/patches/701-reload_config_inline.patch +++ b/package/network/services/hostapd/patches/701-reload_config_inline.patch @@ -1,6 +1,6 @@ --- a/hostapd/config_file.c +++ b/hostapd/config_file.c -@@ -4810,7 +4810,12 @@ struct hostapd_config * hostapd_config_r +@@ -4816,7 +4816,12 @@ struct hostapd_config * hostapd_config_r int errors = 0; size_t i; diff --git a/package/network/services/hostapd/patches/720-iface_max_num_sta.patch b/package/network/services/hostapd/patches/720-iface_max_num_sta.patch index 1aa4456a5f4..089c1ddc246 100644 --- a/package/network/services/hostapd/patches/720-iface_max_num_sta.patch +++ b/package/network/services/hostapd/patches/720-iface_max_num_sta.patch @@ -70,7 +70,7 @@ " since no room for additional STA", --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h -@@ -1036,6 +1036,8 @@ struct hostapd_config { +@@ -1039,6 +1039,8 @@ struct hostapd_config { unsigned int track_sta_max_num; unsigned int track_sta_max_age; diff --git a/package/network/services/hostapd/patches/740-snoop_iface.patch b/package/network/services/hostapd/patches/740-snoop_iface.patch index 004b8a0d392..67312e03142 100644 --- a/package/network/services/hostapd/patches/740-snoop_iface.patch +++ b/package/network/services/hostapd/patches/740-snoop_iface.patch @@ -104,7 +104,7 @@ static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd, --- a/src/drivers/driver.h +++ b/src/drivers/driver.h -@@ -4206,7 +4206,7 @@ struct wpa_driver_ops { +@@ -4209,7 +4209,7 @@ struct wpa_driver_ops { * Returns: 0 on success, negative (<0) on failure */ int (*br_set_net_param)(void *priv, enum drv_br_net_param param, @@ -115,7 +115,7 @@ * get_wowlan - Get wake-on-wireless status --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c -@@ -12127,7 +12127,7 @@ static const char * drv_br_net_param_str +@@ -12167,7 +12167,7 @@ static const char * drv_br_net_param_str static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param, @@ -124,7 +124,7 @@ { struct i802_bss *bss = priv; char path[128]; -@@ -12153,8 +12153,11 @@ static int wpa_driver_br_set_net_param(v +@@ -12193,8 +12193,11 @@ static int wpa_driver_br_set_net_param(v return -EINVAL; } diff --git a/package/network/services/hostapd/patches/770-radius_server.patch b/package/network/services/hostapd/patches/770-radius_server.patch index e4690c76b8b..8837a26257b 100644 --- a/package/network/services/hostapd/patches/770-radius_server.patch +++ b/package/network/services/hostapd/patches/770-radius_server.patch @@ -21,7 +21,7 @@ #ifndef CONFIG_NO_HOSTAPD_LOGGER static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, -@@ -758,6 +759,11 @@ int main(int argc, char *argv[]) +@@ -771,6 +772,11 @@ int main(int argc, char *argv[]) if (os_program_init()) return -1; diff --git a/package/network/services/hostapd/patches/990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch b/package/network/services/hostapd/patches/990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch index 51690def09c..5809a3b7e81 100644 --- a/package/network/services/hostapd/patches/990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch +++ b/package/network/services/hostapd/patches/990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch @@ -13,7 +13,7 @@ Signed-off-by: David Bauer --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c -@@ -12640,7 +12640,7 @@ char * wpa_supplicant_ctrl_iface_process +@@ -12763,7 +12763,7 @@ char * wpa_supplicant_ctrl_iface_process if (wpas_ctrl_iface_coloc_intf_report(wpa_s, buf + 18)) reply_len = -1; #endif /* CONFIG_WNM */ @@ -22,7 +22,7 @@ Signed-off-by: David Bauer } else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) { if (ap_ctrl_iface_disassoc_imminent(wpa_s, buf + 18)) reply_len = -1; -@@ -12650,7 +12650,7 @@ char * wpa_supplicant_ctrl_iface_process +@@ -12773,7 +12773,7 @@ char * wpa_supplicant_ctrl_iface_process } else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) { if (ap_ctrl_iface_bss_tm_req(wpa_s, buf + 11)) reply_len = -1; diff --git a/package/network/services/hostapd/src/src/ap/ucode.c b/package/network/services/hostapd/src/src/ap/ucode.c index 0326f6fc82d..849f8028e6f 100644 --- a/package/network/services/hostapd/src/src/ap/ucode.c +++ b/package/network/services/hostapd/src/src/ap/ucode.c @@ -8,6 +8,7 @@ #include "hw_features.h" #include "ap_drv_ops.h" #include "dfs.h" +#include "acs.h" #include static uc_resource_type_t *global_type, *bss_type, *iface_type; @@ -119,6 +120,7 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs) struct hostapd_config *conf; uc_value_t *file = uc_fn_arg(0); uc_value_t *index = uc_fn_arg(1); + uc_value_t *files_only = uc_fn_arg(2); unsigned int i, idx = 0; int ret = -1; @@ -130,9 +132,27 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs) iface = hapd->iface; conf = interfaces->config_read_cb(ucv_string_get(file)); - if (!conf || idx > conf->num_bss || !conf->bss[idx]) + if (!conf) goto out; + if (idx > conf->num_bss || !conf->bss[idx]) + goto free; + + if (ucv_boolean_get(files_only)) { + struct hostapd_bss_config *bss = conf->bss[idx]; + struct hostapd_bss_config *old_bss = hapd->conf; + +#define swap_field(name) \ + do { \ + void *ptr = old_bss->name; \ + old_bss->name = bss->name; \ + bss->name = ptr; \ + } while (0) + + swap_field(ssid.wpa_psk_file); + goto done; + } + hostapd_bss_deinit_no_free(hapd); hostapd_drv_stop_ap(hapd); hostapd_free_hapd_data(hapd); @@ -143,12 +163,14 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs) iface->conf->bss[i] = conf->bss[idx]; hapd->conf = conf->bss[idx]; conf->bss[idx] = old_bss; - hostapd_config_free(conf); - hostapd_setup_bss(hapd, hapd == iface->bss[0], !iface->conf->mbssid); + hostapd_setup_bss(hapd, hapd == iface->bss[0], true); + hostapd_ucode_update_interfaces(); +done: ret = 0; - +free: + hostapd_config_free(conf); out: return ucv_int64_new(ret); } @@ -179,10 +201,15 @@ uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs) struct hostapd_iface *iface; int i, idx; - if (!hapd || hapd == hapd->iface->bss[0]) + if (!hapd) return NULL; iface = hapd->iface; + if (iface->num_bss == 1) { + wpa_printf(MSG_ERROR, "trying to delete last bss of an iface: %s\n", hapd->conf->iface); + return NULL; + } + for (idx = 0; idx < iface->num_bss; idx++) if (iface->bss[idx] == hapd) break; @@ -192,8 +219,13 @@ uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs) for (i = idx + 1; i < iface->num_bss; i++) iface->bss[i - 1] = iface->bss[i]; + iface->num_bss--; + iface->bss[0]->interface_added = 0; + hostapd_drv_set_first_bss(iface->bss[0]); + hapd->interface_added = 1; + hostapd_drv_stop_ap(hapd); hostapd_bss_deinit(hapd); hostapd_remove_iface_bss_conf(iface->conf, hapd->conf); @@ -267,6 +299,58 @@ out: return ret; } +static uc_value_t * +uc_hostapd_iface_set_bss_order(uc_vm_t *vm, size_t nargs) +{ + struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface"); + uc_value_t *bss_list = uc_fn_arg(0); + struct hostapd_data **new_bss; + struct hostapd_bss_config **new_conf; + + if (!iface) + return NULL; + + if (ucv_type(bss_list) != UC_ARRAY || + ucv_array_length(bss_list) != iface->num_bss) + return NULL; + + new_bss = calloc(iface->num_bss, sizeof(*new_bss)); + new_conf = calloc(iface->num_bss, sizeof(*new_conf)); + for (size_t i = 0; i < iface->num_bss; i++) { + struct hostapd_data *bss; + + bss = ucv_resource_data(ucv_array_get(bss_list, i), "hostapd.bss"); + if (bss->iface != iface) + goto free; + + for (size_t k = 0; k < i; k++) + if (new_bss[k] == bss) + goto free; + + new_bss[i] = bss; + new_conf[i] = bss->conf; + } + + new_bss[0]->interface_added = 0; + for (size_t i = 1; i < iface->num_bss; i++) + new_bss[i]->interface_added = 1; + + free(iface->bss); + iface->bss = new_bss; + + free(iface->conf->bss); + iface->conf->bss = new_conf; + iface->conf->num_bss = iface->num_bss; + hostapd_drv_set_first_bss(iface->bss[0]); + + return ucv_boolean_new(true); + +free: + free(new_bss); + free(new_conf); + return NULL; +} + static uc_value_t * uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs) { @@ -298,6 +382,14 @@ uc_hostapd_iface_stop(uc_vm_t *vm, size_t nargs) struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface"); int i; +#ifdef CONFIG_ACS + if (iface->state == HAPD_IFACE_ACS) { + acs_cleanup(iface); + iface->scan_cb = NULL; + hostapd_disable_iface(iface); + } +#endif + for (i = 0; i < iface->num_bss; i++) { struct hostapd_data *hapd = iface->bss[i]; @@ -318,6 +410,7 @@ uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs) if (!iface) return NULL; + iface->freq = 0; if (!info) goto out; @@ -346,13 +439,30 @@ uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs) if (!errno) hostapd_set_oper_chwidth(conf, intval); + intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL)); + if (!errno) + iface->freq = intval; + conf->acs = 0; + out: - if (conf->channel) + switch (iface->state) { + case HAPD_IFACE_DISABLED: + break; + case HAPD_IFACE_ENABLED: + if (!hostapd_is_dfs_required(iface) || + hostapd_is_dfs_chan_available(iface)) + break; + wpa_printf(MSG_INFO, "DFS CAC required on new channel, restart interface"); + /* fallthrough */ + default: + hostapd_disable_iface(iface); + break; + } + + if (conf->channel && !iface->freq) iface->freq = hostapd_hw_get_freq(iface->bss[0], conf->channel); - if (hostapd_is_dfs_required(iface) && !hostapd_is_dfs_chan_available(iface)) { - wpa_printf(MSG_INFO, "DFS CAC required on new channel, restart interface"); - hostapd_disable_iface(iface); + if (iface->state != HAPD_IFACE_ENABLED) { hostapd_enable_iface(iface); return ucv_boolean_new(true); } @@ -428,6 +538,55 @@ uc_hostapd_iface_switch_channel(uc_vm_t *vm, size_t nargs) return ucv_boolean_new(!ret); } +static uc_value_t * +uc_hostapd_bss_rename(uc_vm_t *vm, size_t nargs) +{ + struct hostapd_data *hapd = uc_fn_thisval("hostapd.bss"); + uc_value_t *ifname_arg = uc_fn_arg(0); + char prev_ifname[IFNAMSIZ + 1]; + struct sta_info *sta; + const char *ifname; + int ret; + + if (!hapd || ucv_type(ifname_arg) != UC_STRING) + return NULL; + + os_strlcpy(prev_ifname, hapd->conf->iface, sizeof(prev_ifname)); + ifname = ucv_string_get(ifname_arg); + + hostapd_ubus_free_bss(hapd); + if (interfaces->ctrl_iface_deinit) + interfaces->ctrl_iface_deinit(hapd); + + ret = hostapd_drv_if_rename(hapd, WPA_IF_AP_BSS, NULL, ifname); + if (ret) + goto out; + + for (sta = hapd->sta_list; sta; sta = sta->next) { + char cur_name[IFNAMSIZ + 1], new_name[IFNAMSIZ + 1]; + + if (!(sta->flags & WLAN_STA_WDS) || sta->pending_wds_enable) + continue; + + snprintf(cur_name, sizeof(cur_name), "%s.sta%d", prev_ifname, sta->aid); + snprintf(new_name, sizeof(new_name), "%s.sta%d", ifname, sta->aid); + hostapd_drv_if_rename(hapd, WPA_IF_AP_VLAN, cur_name, new_name); + } + + if (!strncmp(hapd->conf->ssid.vlan, hapd->conf->iface, sizeof(hapd->conf->ssid.vlan))) + os_strlcpy(hapd->conf->ssid.vlan, ifname, sizeof(hapd->conf->ssid.vlan)); + os_strlcpy(hapd->conf->iface, ifname, sizeof(hapd->conf->iface)); + hostapd_ubus_add_bss(hapd); + + hostapd_ucode_update_interfaces(); +out: + if (interfaces->ctrl_iface_init) + interfaces->ctrl_iface_init(hapd); + + return ret ? NULL : ucv_boolean_new(true); +} + + int hostapd_ucode_init(struct hapd_interfaces *ifaces) { static const uc_function_list_t global_fns[] = { @@ -441,9 +600,11 @@ int hostapd_ucode_init(struct hapd_interfaces *ifaces) static const uc_function_list_t bss_fns[] = { { "ctrl", uc_hostapd_bss_ctrl }, { "set_config", uc_hostapd_bss_set_config }, + { "rename", uc_hostapd_bss_rename }, { "delete", uc_hostapd_bss_delete }, }; static const uc_function_list_t iface_fns[] = { + { "set_bss_order", uc_hostapd_iface_set_bss_order }, { "add_bss", uc_hostapd_iface_add_bss }, { "stop", uc_hostapd_iface_stop }, { "start", uc_hostapd_iface_start },