Compare commits

..

33 Commits

Author SHA1 Message Date
jaspreetsachdev
dd41f15987 Merge pull request #581 from Telecominfraproject/main
Merge the latest changes from main
2023-09-20 08:58:21 -04:00
John Crispin
007cfe9c16 ipq807x: update ifname rename patches
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-19 06:44:06 +02:00
Ken
52884b2835 ipq807x: CIG wf660ag: support both EMMC and SPI NOR+EMCC H/W
Using one firmware to support the board which has EMMC only and SPI NOR+EMMC equipped

Fixes: WIFI-12941
Signed-off-by: Ken <xshi@actiontec.com>
2023-09-18 16:19:17 +02:00
John Crispin
6a6af16f48 hostapd: add CSA event
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-18 15:58:39 +02:00
John Crispin
2818722b19 usteer2: improve gateway command handling
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-18 15:58:39 +02:00
John Crispin
194eba2d21 ucentral-schema: update to latest HEAD
e99eaf9 add rrm cmd handler

Signed-off-by: John Crispin <john@phrozen.org>
2023-09-18 15:58:39 +02:00
John Crispin
3d41a22fba ucentral-client: update to latest HEAD
3bbcd36 handle rrm command

Signed-off-by: John Crispin <john@phrozen.org>
2023-09-18 09:56:50 +02:00
John Crispin
acd4b79dd4 ipq807x: backport latest wifi hot-reload to v5.4 kernel
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-17 06:50:23 +02:00
John Crispin
befac1e065 netifd: backport vlan rewrite
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-16 17:29:49 +02:00
John Crispin
7e4e221ccb netifd: add dynamic interface patch
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-16 17:29:49 +02:00
Felix Fietkau
1d9b69ee6f hostapd: add vlan reload support and ap+sta fix
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2023-09-16 17:29:49 +02:00
Felix Fietkau
018f20119d netifd: add wireless vlan/sta fix
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2023-09-16 17:29:49 +02:00
Felix Fietkau
9a6e41adb8 hostapd: fix ucode reload issues
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2023-09-16 17:29:49 +02:00
Felix Fietkau
970b22856f mac80211: fix reconfiguration on DFS channels in non-ETSI regdomains
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2023-09-16 17:29:49 +02:00
Felix Fietkau
95032994fe hostapd: move ubus.c changes from patches to src
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2023-09-16 17:29:49 +02:00
John Crispin
48cda63dc5 hostapd: backport latest reload patches
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-16 17:29:49 +02:00
Ken
8e9f79964a ipq807x: Apply CE TX power to wf-186w
Apply CE TX power for WF186w and WF186H include FCC as well.

Fixes: WIFI-12920
Signed-off-by: Ken <xshi@actiontec.com>
2023-09-16 17:20:11 +02:00
John Crispin
3c7df86373 certificates: fix mounting on cig,wf186w|cig,wf186h
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-16 17:20:11 +02:00
Ken
38e6aee074 ipq807x: BSP patch for WF-186H
Fixes: WIFI-12922
Signed-off-by: Ken <xshi@actiontec.com>
2023-09-16 17:19:55 +02:00
John Crispin
0a13684bb6 ipq807x: fix certificates mounting in dual-boot scenario on yuncore,fap655
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-16 17:17:15 +02:00
John Crispin
e7ca6e8455 hostapd: fix ft-anonce behavior for broken clients
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-13 16:37:12 +02:00
John Crispin
f17e635d34 ucentral-schema: update to latest HEAD
f113e61 fix uci for network devices that have a dot in the name

Signed-off-by: John Crispin <john@phrozen.org>
2023-09-13 16:35:50 +02:00
John Crispin
90e78c6068 ucentral-schema: update to latest HEAD
58d7d72 fix beacon rates

Fixes: WIFI-12935
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-12 16:58:23 +02:00
John Crispin
550bb6fb7e hostapd: update the snooping patch
Fixes: WIFI-12929
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-12 16:18:01 +02:00
John Crispin
b3a0ebe534 ipq807x: disable SWITCHDEV support
It is not used by the firmware.

Signed-off-by: John Crispin <john@phrozen.org>
2023-09-12 16:16:43 +02:00
John Crispin
6d16e50bbe ipq807x: do not include kmod-qca-nss-drv-bridge-mgr
This was causing issues with bridge-vlans that have mixed tagged and untagged ports.

Signed-off-by: John Crispin <john@phrozen.org>
2023-09-12 16:16:04 +02:00
Paul White
513eec1c5f ipq807x: cig.wf186w: Add MPSK Dynamic VLAN support
When a MPSK VLAN netdev is created on the cig.wf186w board, this script
will configure switch0 via swconfig for the corresponding VLAN

Signed-off-by: Paul White <paul@shasta.cloud>
2023-09-12 04:15:24 +02:00
Paul White
6a797e8a64 ucentral-schema: cig.wf186w: wan_port set to eth0
Reset the ucentral UCI config 'event.config.wan_port' to eth0 for
the WF186W board

Signed-off-by: Paul White <paul@shasta.cloud>
2023-09-12 04:15:24 +02:00
John Crispin
082134bc43 ucentral-schema: update to latest HEAD
fd6a079 dhcp-relay: dhcp relay option 82 parameters

Signed-off-by: John Crispin <john@phrozen.org>
2023-09-11 07:31:55 +02:00
Arif Alam
03ec2de777 ucentral-event: dhcp relay option 82 parameters
Add the ability to configure circuit-id and remote-id sub-options.

Signed-off-by: Arif Alam <arif.alam@netexperience.com>
2023-09-11 07:29:17 +02:00
John Crispin
989d39d1f2 ucentral-schema: update to latest HEAD
a4c8a13 increase reassociation_deadline to 3s when using multi-psk

Fixes: WIFI-12598
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-06 16:15:11 +02:00
John Crispin
b6b298ad68 hostapd: fix association of clients on Open/VLAN SSIDs
Fixes: WIFI-12929
Signed-off-by: John Crispin <john@phrozen.org>
2023-09-06 16:14:42 +02:00
Ken
be1cb862f1 ipq807x: CIG WF-186w - Adjust the LAN ID to match printed labels
Fixes: WIFI-12915
Signed-off-by: Ken <xshi@actiontec.com>
2023-09-06 11:55:01 +02:00
87 changed files with 10504 additions and 937 deletions

View File

@@ -18,7 +18,7 @@ DEFAULT_PACKAGES += kmod-qca-nss-dp kmod-qca-ssdk swconfig \
kmod-usb-phy-ipq807x kmod-usb-dwc3-of-simple \
kmod-ath11k-ahb kmod-qrtr_mproc wpad \
kmod-gpio-button-hotplug kmod-bootconfig \
qca-thermald-10.4 qca-ssdk-shell kmod-qca-nss-drv-bridge-mgr \
qca-thermald-10.4 qca-ssdk-shell \
uboot-envtools
$(eval $(call BuildTarget))

View File

@@ -64,8 +64,11 @@ qcom_setup_interfaces()
ucidef_set_interface_wan "eth0"
;;
cig,wf186w)
ucidef_add_switch "switch0" "4:wan" "1:lan" "2:lan" "3:lan" "0:lan" "6@eth0"
ucidef_add_switch "switch0" "4:wan" "0:lan" "1:lan" "2:lan" "3:lan" "6@eth0"
;;
cig,wf186h)
ucidef_add_switch "switch0" "4:wan" "1:lan" "2:lan" "6@eth0"
;;
yuncore,fap650)
ucidef_set_interface_lan "eth3 eth2 eth1 eth0"
ucidef_set_interface_wan "eth4"
@@ -180,6 +183,15 @@ qcom_setup_macs()
# ip link set eth1 address $wan_mac
# ucidef_set_label_macaddr $wan_mac
;;
cig,wf186h)
mtd=$(find_mtd_chardev "0:APPSBLENV")
[ -z "$mtd" ] && return;
mac=$(grep BaseMacAddress= $mtd | cut -dx -f2)
[ -z "$mac" ] && return;
wan_mac=$(macaddr_canonicalize $mac)
ucidef_set_network_device_mac eth0 $wan_mac
ip link set eth0 address $wan_mac
;;
cybertan,eww631-a1|\
cybertan,eww631-b1)
mac=$(grep -i -m 1 BaseMacAddress= /dev/`cat /proc/mtd | grep APPSBLENV | cut -d: -f1` | cut -d= -f2)
@@ -203,9 +215,10 @@ qcom_setup_macs()
ucidef_set_label_macaddr $wan_mac
;;
cig,wf660a)
mmc_dev=$(echo $(find_mmc_part "0:APPSBLENV") | sed 's/^.\{5\}//')
[ -z mmc_dev ] && return
mac=$(grep BaseMacAddress= /dev/$mmc_dev | cut -dx -f2)
mmc_dev=$(find_mtd_chardev "0:APPSBLENV")
[ -z "$mmc_dev" ] && mmc_dev=$(find_mmc_part "0:APPSBLENV")
[ -z "$mmc_dev" ] && return
mac=$(grep BaseMacAddress= $mmc_dev | cut -dx -f2)
[ -z "$mac" ] && return;
wan_mac=$(macaddr_canonicalize $mac)
ucidef_set_network_device_mac eth0 $wan_mac

View File

@@ -61,8 +61,9 @@ ath11k_generate_macs_pax1800() {
ath11k_generate_macs_wf660a() {
touch /lib/firmware/ath11k-macs
mmc_dev=$(find_mmc_part 0:APPSBLENV)
[ -n $mmc_dev ] && mac=$(grep BaseMacAddress= $mmc_dev | cut -dx -f2)
mmc_dev=$(find_mtd_chardev "0:APPSBLENV")
[ -z "$mmc_dev" ] && mmc_dev=$(find_mmc_part "0:APPSBLENV")
[ -n "$mmc_dev" ] && mac=$(grep BaseMacAddress= $mmc_dev | cut -dx -f2)
eth=$(macaddr_canonicalize $mac)
mac1=$(macaddr_add $eth 1)
mac2=$(macaddr_add $eth 2)
@@ -85,6 +86,19 @@ ath11k_generate_macs_wf186w() {
echo -ne \\x${mac3//:/\\x} >> /lib/firmware/ath11k-macs
}
ath11k_generate_macs_wf186h() {
touch /lib/firmware/ath11k-macs
local dev=$(find_mtd_chardev "0:APPSBLENV")
mac=$(grep BaseMacAddress= $dev | cut -dx -f2)
eth=$(macaddr_canonicalize $mac)
mac1=$(macaddr_add $eth 2)
mac2=$(macaddr_add $eth 3)
mac3=$(macaddr_add $eth 4)
echo -ne \\x${mac1//:/\\x} >> /lib/firmware/ath11k-macs
echo -ne \\x${mac2//:/\\x} >> /lib/firmware/ath11k-macs
echo -ne \\x${mac3//:/\\x} >> /lib/firmware/ath11k-macs
}
caldata_die() {
echo "caldata: " "$*"
@@ -159,6 +173,7 @@ case "$FIRMWARE" in
ath11k/IPQ5018/hw1.0/caldata.bin)
case "$board" in
cig,wf186w|\
cig,wf186h|\
cybertan,eww622-a1|\
cybertan,eww631-a1|\
cybertan,eww631-b1|\
@@ -180,6 +195,7 @@ ath11k/IPQ5018/hw1.0/caldata.bin)
ath11k/qcn6122/hw1.0/caldata_1.bin)
case "$board" in
cig,wf186w|\
cig,wf186h|\
wallys,dr5018|\
hfcl,ion4xi_w|\
hfcl,ion4x_w|\
@@ -269,6 +285,9 @@ ath11k-macs)
cig,wf186w)
ath11k_generate_macs_wf186w
;;
cig,wf186h)
ath11k_generate_macs_wf186h
;;
esac
;;
*)

View File

@@ -0,0 +1,40 @@
#!/bin/sh
. /lib/functions.sh
debug() {
logger -t HOTPLUG-DVLAN "$*"
}
if [ "${INTERFACE:0:4}" != "wlan" ]; then
exit 0
fi
case "$(board_name)" in
"cig,wf186w")
wan_iface="eth0"
switch_dev="switch0"
switch_wan_port=4
switch_cpu_port=6
;;
*)
exit 0
esac
VSTR="$(echo $INTERFACE | egrep -o 'v([0-9]+)$')"
[ -z "$VSTR" ] && exit 0
VID="${VSTR:1}"
[ $VID -lt 1 -o $VID -gt 4096 ] && exit 0
if [ "$ACTION" = "add" ]; then
debug "[$INTERFACE] Dynamic VLAN $VID added, configuring switch"
swconfig dev ${switch_dev} vlan $VID set ports "${switch_wan_port}t ${switch_cpu_port}t"
elif [ "$ACTION" = "remove" ]; then
let cnt="$(bridge vlan show vid $VID | egrep "^wlan" | wc -l)"
debug "[$INTERFACE] Dynamic VLAN interface removed, references left = $cnt"
if [ $cnt -eq 0 ]; then
debug "[$INTERFACE] No more references, removing $VID from switch"
swconfig dev ${switch_dev} vlan $VID set ports ""
fi
fi

View File

@@ -52,7 +52,7 @@ do_flash_emmc() {
tar Oxf $tar_file ${board_dir}/$part | dd of=${emmcblock}
}
emmc_do_upgrade_bootconfig() {
spi_nor_emmc_do_upgrade_bootconfig() {
local tar_file="$1"
local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$')
@@ -84,11 +84,17 @@ emmc_do_upgrade_bootconfig() {
fi
for part in "0:BOOTCONFIG" "0:BOOTCONFIG1"; do
local emmcblock=$(find_mmc_part $part)
echo erase ${emmcblock}
dd if=/dev/zero of=${emmcblock} 2> /dev/null
echo update $emmcblock
dd if=/tmp/bootconfig of=${emmcblock} 2> /dev/null
local mtdchar=$(echo $(find_mtd_chardev $part) | sed 's/^.\{5\}//')
if [ -n "$mtdchar" ]; then
echo start to update $mtdchar
mtd -qq write /proc/boot_info/getbinary_bootconfig "/dev/${mtdchar}" 2>/dev/null && echo update mtd $mtdchar
else
emmcblock=$(find_mmc_part $part)
echo erase ${emmcblock}
dd if=/dev/zero of=${emmcblock} 2> /dev/null
echo update $emmcblock
dd if=/tmp/bootconfig of=${emmcblock} 2> /dev/null
fi
done
}
@@ -111,6 +117,7 @@ platform_check_image() {
board=$(board_name)
case $board in
cig,wf186w|\
cig,wf186h|\
cig,wf188|\
cig,wf660a|\
cig,wf188n|\
@@ -174,7 +181,7 @@ platform_do_upgrade() {
qca_do_upgrade $1
;;
cig,wf660a)
emmc_do_upgrade_bootconfig $1
spi_nor_emmc_do_upgrade_bootconfig $1
;;
motorola,q14)
emmc_do_upgrade $1
@@ -267,6 +274,7 @@ platform_do_upgrade() {
platform_do_upgrade_dualboot_datachk "$1"
;;
cig,wf186w|\
cig,wf186h|\
yuncore,ax840|\
yuncore,fap655)
[ -f /proc/boot_info/rootfs/upgradepartition ] && {

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "../../../arm64/boot/dts/qcom/qcom-ipq5018-cig-wf186h.dts"
/ {
pmuv8: pmu {
compatible = "arm,cortex-a7-pmu";
};
};

View File

@@ -0,0 +1,965 @@
/dts-v1/;
/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "qcom-ipq5018.dtsi"
/ {
#address-cells = <0x2>;
#size-cells = <0x2>;
model = "CIG wf186h";
compatible = "cig,wf186h","qcom,ipq5018-mp03.3", "qcom,ipq5018";
interrupt-parent = <&intc>;
aliases {
sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
serial0 = &blsp1_uart1;
serial1 = &blsp1_uart2;
ethernet0 = "/soc/dp1";
ethernet1 = "/soc/dp2";
};
chosen {
bootargs = "console=ttyMSM0,115200,n8 rw init=/init";
#ifdef __IPQ_MEM_PROFILE_256_MB__
bootargs-append = " swiotlb=1";
#else
bootargs-append = " swiotlb=1 coherent_pool=2M";
#endif
stdout-path = "serial0";
};
reserved-memory {
#ifdef __IPQ_MEM_PROFILE_256_MB__
/* 256 MB Profile
* +=========+==============+========================+
* | | | |
* | Region | Start Offset | Size |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | | | |
* | NSS | 0x40000000 | 8MB |
* | | | |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | | | |
* | | | |
* | | | |
* | Linux | 0x40800000 | Depends on total memory |
* | | | |
* | | | |
* | | | |
* + | | |
* +--------+--------------+-------------------------+
* | | | |
* | uboot | 0x4A600000 | 4MB |
* | | | |
* +--------+--------------+-------------------------+
* | SBL | 0x4AA00000 | 1MB |
* +--------+--------------+-------------------------+
* | smem | 0x4AB00000 | 1MB |
* +--------+--------------+-------------------------+
* | | | |
* | TZ | 0x4AC00000 | 4MB |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | | | |
* | | | |
* | Q6 | 0x4B000000 | 16MB |
* | code/ | | |
* | data | | |
* +--------+--------------+-------------------------+
* | | | |
* |IPQ5018 | 0x4C000000 | 13MB |
* | data | | |
* +--------+--------------+-------------------------+
* | M3 Dump| 0x4CD00000 | 1MB |
* +--------+--------------+-------------------------+
* | QDSS | 0x4CE00000 | 1MB |
* +--------+--------------+-------------------------+
* |QCN6122 | 0x4CF00000 | 15MB |
* | data | | |
* +--------+--------------+-------------------------+
* | M3 Dump| 0x4DE00000 | 1MB |
* +--------+--------------+-------------------------+
* | QDSS | 0x4DF00000 | 1MB |
* +--------+--------------+-------------------------+
* | | | |
* |QCN9000 | 0x4E000000 | 17MB |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | MHI1 | 0x4F100000 | 16MB |
* | | | |
* +--------+--------------+-------------------------+
* | |
* | Rest of the memory for Linux |
* | |
* +=================================================+
*/
q6_mem_regions: q6_mem_regions@4B000000 {
no-map;
reg = <0x0 0x4B000000 0x0 0x3000000>;
};
q6_code_data: q6_code_data@4B000000 {
no-map;
reg = <0x0 0x4B000000 0x0 01000000>;
};
q6_ipq5018_data: q6_ipq5018_data@4c000000 {
no-map;
reg = <0x0 0x4c000000 0x0 0xD00000>;
};
m3_dump: m3_dump@4CD00000 {
no-map;
reg = <0x0 0x4CD00000 0x0 0x100000>;
};
q6_etr_region:q6_etr_dump@4CE00000 {
no-map;
reg = <0x0 0x4CE00000 0x0 0x100000>;
};
q6_qcn6122_data1: q6_qcn6122_data1@4CF00000 {
no-map;
reg = <0x0 0x4CF00000 0x0 0xF00000>;
};
m3_dump_qcn6122_1: m3_dump_qcn6122_1@4DE00000 {
no-map;
reg = <0x0 0x4DE00000 0x0 0x100000>;
};
q6_qcn6122_etr_1: q6_qcn6122_etr_1@4DF00000 {
no-map;
reg = <0x0 0x4DF00000 0x0 0x100000>;
};
q6_qcn9000_region: qcn9000_pcie0@4E000000 {
no-map;
reg = <0x0 0x4E000000 0x0 0x01100000>;
};
mhi_region1: dma_pool1@4F100000 {
compatible = "shared-dma-pool";
no-map;
reg = <0x0 0x4F100000 0x0 0x01000000>;
};
#elif __IPQ_MEM_PROFILE_512_MB__
/* 512 MB Profile
* +=========+==============+========================+
* | | | |
* | Region | Start Offset | Size |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | | | |
* | NSS | 0x40000000 | 16MB |
* | | | |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | | | |
* | | | |
* | | | |
* | Linux | 0x41000000 | Depends on total memory |
* | | | |
* | | | |
* | | | |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | uboot | 0x4A600000 | 4MB |
* | | | |
* +--------+--------------+-------------------------+
* | SBL | 0x4AA00000 | 1MB |
* +--------+--------------+-------------------------+
* | smem | 0x4AB00000 | 1MB |
* +--------+--------------+-------------------------+
* | | | |
* | TZ | 0x4AC00000 | 4MB |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | | | |
* | Q6 | 0x4B000000 | 16MB |
* | code/ | | |
* | data | | |
* +--------+--------------+-------------------------+
* | | | |
* |IPQ5018 | 0x4C000000 | 14MB |
* | data | | |
* +--------+--------------+-------------------------+
* | M3 Dump| 0x4CE00000 | 1MB |
* +--------+--------------+-------------------------+
* | QDSS | 0x4CF00000 | 1MB |
* +--------+--------------+-------------------------+
* | caldb | 0x4D000000 | 2MB |
* +--------+--------------+-------------------------+
* |QCN6122 | 0x4D200000 | 16MB |
* | data | | |
* +--------+--------------+-------------------------+
* | M3 Dump| 0x4E200000 | 1MB |
* +--------+--------------+-------------------------+
* | QDSS | 0x4E300000 | 1MB |
* +--------+--------------+-------------------------+
* | caldb | 0x4E400000 | 5MB |
* +--------+--------------+-------------------------+
* | | | |
* |QCN9000 | 0x4E900000 | 30MB |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | MHI1 | 0x50700000 | 16MB |
* | | | |
* +--------+--------------+-------------------------+
* | |
* | Rest of the memory for Linux |
* | |
* +=================================================+
*/
q6_mem_regions: q6_mem_regions@4B000000 {
no-map;
reg = <0x0 0x4B000000 0x0 0x3900000>;
};
q6_code_data: q6_code_data@4B000000 {
no-map;
reg = <0x0 0x4B000000 0x0 01000000>;
};
q6_ipq5018_data: q6_ipq5018_data@4C000000 {
no-map;
reg = <0x0 0x4C000000 0x0 0xE00000>;
};
m3_dump: m3_dump@4CE00000 {
no-map;
reg = <0x0 0x4CE00000 0x0 0x100000>;
};
q6_etr_region: q6_etr_dump@4CF00000 {
no-map;
reg = <0x0 0x4CF00000 0x0 0x100000>;
};
q6_caldb_region: q6_caldb_region@4D000000 {
no-map;
reg = <0x0 0x4D000000 0x0 0x200000>;
};
q6_qcn6122_data1: q6_qcn6122_data1@4D200000 {
no-map;
reg = <0x0 0x4D200000 0x0 0x1000000>;
};
m3_dump_qcn6122_1: m3_dump_qcn6122_1@4E200000 {
no-map;
reg = <0x0 0x4E200000 0x0 0x100000>;
};
q6_qcn6122_etr_1: q6_qcn6122_etr_1@4E300000 {
no-map;
reg = <0x0 0x4E300000 0x0 0x100000>;
};
q6_qcn6122_caldb_1: q6_qcn6122_caldb_1@4E400000 {
no-map;
reg = <0x0 0x4E400000 0x0 0x500000>;
};
q6_qcn9000_region: qcn9000_pcie0@4E900000 {
no-map;
reg = <0x0 0x4E900000 0x0 0x01E00000>;
};
mhi_region1: dma_pool1@50700000 {
compatible = "shared-dma-pool";
no-map;
reg = <0x0 0x50700000 0x0 0x01000000>;
};
#else
/* 1G Profile
* +=========+==============+========================+
* | | | |
* | Region | Start Offset | Size |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | | | |
* | NSS | 0x40000000 | 16MB |
* | | | |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | | | |
* | | | |
* | | | |
* | Linux | 0x41000000 | Depends on total memory |
* | | | |
* | | | |
* | | | |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | uboot | 0x4A600000 | 4MB |
* | | | |
* +--------+--------------+-------------------------+
* | SBL | 0x4AA00000 | 1MB |
* +--------+--------------+-------------------------+
* | smem | 0x4AB00000 | 1MB |
* +--------+--------------+-------------------------+
* | | | |
* | TZ | 0x4AC00000 | 4MB |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | | | |
* | Q6 | 0x4B000000 | 16MB |
* | code/ | | |
* | data | | |
* +--------+--------------+-------------------------+
* | | | |
* |IPQ5018 | 0x4C000000 | 14MB |
* | data | | |
* +--------+--------------+-------------------------+
* | M3 Dump| 0x4CE00000 | 1MB |
* +--------+--------------+-------------------------+
* | QDSS | 0x4CF00000 | 1MB |
* +--------+--------------+-------------------------+
* | caldb | 0x4D000000 | 2MB |
* +--------+--------------+-------------------------+
* |QCN6122 | 0x4D200000 | 16MB |
* | data | | |
* +--------+--------------+-------------------------+
* | M3 Dump| 0x4E200000 | 1MB |
* +--------+--------------+-------------------------+
* | QDSS | 0x4E300000 | 1MB |
* +--------+--------------+-------------------------+
* | caldb | 0x4E400000 | 5MB |
* +--------+--------------+-------------------------+
* | | | |
* |QCN9000 | 0x4E900000 | 45MB |
* | | | |
* +--------+--------------+-------------------------+
* | | | |
* | MHI1 | 0x51600000 | 24MB |
* | | | |
* +--------+--------------+-------------------------+
* | |
* | Rest of the memory for Linux |
* | |
* +=================================================+
*/
q6_mem_regions: q6_mem_regions@4B000000 {
no-map;
reg = <0x0 0x4B000000 0x0 0x3900000>;
};
q6_code_data: q6_code_data@4B000000 {
no-map;
reg = <0x0 0x4B000000 0x0 01000000>;
};
q6_ipq5018_data: q6_ipq5018_data@4C000000 {
no-map;
reg = <0x0 0x4C000000 0x0 0xE00000>;
};
m3_dump: m3_dump@4CE00000 {
no-map;
reg = <0x0 0x4CE00000 0x0 0x100000>;
};
q6_etr_region: q6_etr_dump@4CF00000 {
no-map;
reg = <0x0 0x4CF00000 0x0 0x100000>;
};
q6_caldb_region: q6_caldb_region@4D000000 {
no-map;
reg = <0x0 0x4D000000 0x0 0x200000>;
};
q6_qcn6122_data1: q6_qcn6122_data1@4D200000 {
no-map;
reg = <0x0 0x4D200000 0x0 0x1000000>;
};
m3_dump_qcn6122_1: m3_dump_qcn6122_1@4E200000 {
no-map;
reg = <0x0 0x4E200000 0x0 0x100000>;
};
q6_qcn6122_etr_1: q6_qcn6122_etr_1@4E300000 {
no-map;
reg = <0x0 0x4E300000 0x0 0x100000>;
};
q6_qcn6122_caldb_1: q6_qcn6122_caldb_1@4E400000 {
no-map;
reg = <0x0 0x4E400000 0x0 0x500000>;
};
q6_qcn9000_region: qcn9000_pcie0@4E900000 {
no-map;
reg = <0x0 0x4E900000 0x0 0x02D00000>;
};
mhi_region1: dma_pool1@51600000 {
compatible = "shared-dma-pool";
no-map;
reg = <0x0 0x51600000 0x0 0x01800000>;
};
#endif
};
soc {
serial@78af000 {
status = "ok";
};
blsp1_uart2: serial@78b0000 {
pinctrl-0 = <&blsp1_uart_pins>;
pinctrl-names = "default";
status = "ok";
};
qpic_bam: dma@7984000{
status = "ok";
};
nand: qpic-nand@79b0000 {
pinctrl-0 = <&qspi_nand_pins>;
pinctrl-names = "default";
status = "ok";
};
spi_0: spi@78b5000 { /* BLSP1 QUP0 */
pinctrl-0 = <&blsp0_spi_pins>;
pinctrl-names = "default";
cs-select = <0>;
status = "ok";
m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
reg = <0>;
compatible = "n25q128a11";
linux,modalias = "m25p80", "n25q128a11";
spi-max-frequency = <50000000>;
use-default-sizes;
};
};
mdio0: mdio@88000 {
status = "ok";
ethernet-phy@0 {
reg = <7>;
};
};
mdio1: mdio@90000 {
status = "ok";
pinctrl-0 = <&mdio1_pins>;
pinctrl-names = "default";
phy-reset-gpio = <&tlmm 35 0>;
cig_clk_div = <0xff>;
ethernet-phy@0 {
reg = <0x1d>;
};
};
realtek@29{
compatible = "realtek,rtl8367s";
mii-bus = <&mdio1>;
realtek,extif0 = <0 0 10 1 1 1 1 1 2>;
switch = <&tlmm 35 0>;
phy-addr = <29>;
status = "ok";
};
ess-instance {
num_devices = <0x1>;
ess-switch@0x39c00000 {
compatible = "qcom,ess-switch-ipq50xx";
device_id = <0>;
switch_mac_mode = <0xf>; /* mac mode for uniphy instance*/
cmnblk_clk = "internal_96MHz"; /* cmnblk clk*/
qcom,port_phyinfo {
port@0 {
port_id = <1>;
phy_address = <7>;
};
port@1 {
port_id = <2>;
forced-speed = <1000>;
forced-duplex = <1>;
};
};
led_source@0 {
source = <0>;
mode = "normal";
speed = "all";
blink_en = "enable";
active = "high";
};
};
};
wifi0: wifi@c000000 {
status = "ok";
};
dp1 {
device_type = "network";
compatible = "qcom,nss-dp";
clocks = <&gcc GCC_SNOC_GMAC1_AXI_CLK>;
clock-names = "nss-snoc-gmac-axi-clk";
qcom,id = <2>;
reg = <0x39D00000 0x10000>;
interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
qcom,mactype = <2>;
local-mac-address = [000000000000];
phy-mode = "sgmii";
};
dp2 {
device_type = "network";
compatible = "qcom,nss-dp";
clocks = <&gcc GCC_SNOC_GMAC0_AXI_CLK>;
clock-names = "nss-snoc-gmac-axi-clk";
qcom,id = <1>;
reg = <0x39C00000 0x10000>;
interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
qcom,mactype = <2>;
qcom,link-poll = <1>;
qcom,phy-mdio-addr = <7>;
mdio-bus = <&mdio0>;
local-mac-address = [000000000000];
phy-mode = "sgmii";
};
qcom,test@0 {
status = "ok";
};
lpass: lpass@0xA000000{
status = "disabled";
};
pcm: pcm@0xA3C0000{
pinctrl-0 = <&audio_pins>;
pinctrl-names = "default";
status = "disabled";
};
gpio_keys {
compatible = "gpio-keys";
pinctrl-0 = <&button_pins>;
pinctrl-names = "default";
button@1 {
label = "rst";
linux,code = <KEY_RESTART>;
gpios = <&tlmm 27 GPIO_ACTIVE_LOW>;
linux,input-type = <1>;
debounce-interval = <60>;
};
};
pcm_lb: pcm_lb@0 {
status = "disabled";
};
};
thermal-zones {
status = "ok";
};
};
&tlmm {
pinctrl-0 = <&phy_led_pins>;
pinctrl-names = "default";
blsp1_uart_pins: blsp1_uart_pins {
blsp1_uart_rx_tx {
pins = "gpio31", "gpio33";
function = "blsp1_uart1";
bias-disable;
};
};
blsp0_spi_pins: blsp0_spi_pins {
mux {
pins = "gpio10", "gpio11", "gpio12", "gpio13";
function = "blsp0_spi";
drive-strength = <2>;
bias-disable;
};
};
qspi_nand_pins: qspi_nand_pins {
qspi_clock {
pins = "gpio9";
function = "qspi_clk";
drive-strength = <8>;
bias-disable;
};
qspi_cs {
pins = "gpio8";
function = "qspi_cs";
drive-strength = <8>;
bias-disable;
};
qspi_data_0 {
pins = "gpio7";
function = "qspi0";
drive-strength = <8>;
bias-disable;
};
qspi_data_1 {
pins = "gpio6";
function = "qspi1";
drive-strength = <8>;
bias-disable;
};
qspi_data_2 {
pins = "gpio5";
function = "qspi2";
drive-strength = <8>;
bias-disable;
};
qspi_data_3 {
pins = "gpio4";
function = "qspi3";
drive-strength = <8>;
bias-disable;
};
};
mdio1_pins: mdio_pinmux {
mux_0 {
pins = "gpio36";
function = "mdc";
drive-strength = <8>;
bias-pull-up;
};
mux_1 {
pins = "gpio37";
function = "mdio";
drive-strength = <8>;
bias-pull-up;
};
};
phy_led_pins: phy_led_pins {
gephy_led_pin {
pins = "gpio46";
function = "led0";
drive-strength = <8>;
bias-pull-down;
};
};
i2c_pins: i2c_pins {
i2c_scl {
pins = "gpio25";
function = "blsp2_i2c1";
drive-strength = <8>;
bias-disable;
};
i2c_sda {
pins = "gpio26";
function = "blsp2_i2c1";
drive-strength = <8>;
bias-disable;
};
};
button_pins: button_pins {
wps_button {
pins = "gpio38";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};
rst_button {
pins = "gpio27";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};
};
audio_pins: audio_pinmux {
mux_1 {
pins = "gpio24";
function = "audio_rxbclk";
drive-strength = <8>;
bias-pull-down;
};
mux_2 {
pins = "gpio25";
function = "audio_rxfsync";
drive-strength = <8>;
bias-pull-down;
};
mux_5 {
pins = "gpio28";
function = "audio_txbclk";
drive-strength = <8>;
bias-pull-down;
};
};
pwm_pins: pwm_pinmux {
mux_1 {
pins = "gpio0";
function = "pwm10";
drive-strength = <8>;
};
mux_2 {
pins = "gpio1";
function = "pwm20";
drive-strength = <8>;
};
mux_3 {
pins = "gpio45";
function = "pwm3";
drive-strength = <8>;
};
};
};
&soc {
pwm: pwm@0x1941010 {
pinctrl-0 = <&pwm_pins>;
pinctrl-names = "default";
used-pwm-indices = <1>, <1>, <1>, <1>;
dft-pwm-status = <1>, <0>, <0>, <0>;
status = "ok";
};
};
&usb3 {
status = "disabled";
device-power-gpio = <&tlmm 24 1>;
};
&eud {
status = "ok";
};
&pcie_x1 {
status = "ok";
perst-gpio = <&tlmm 18 1>;
};
&pcie_x2 {
status = "disabled";
perst-gpio = <&tlmm 15 1>;
};
&dwc_0 {
/delete-property/ #phy-cells;
/delete-property/ phys;
/delete-property/ phy-names;
};
&hs_m31phy_0 {
status = "ok";
};
&pcie_x1phy {
status = "disabled";
};
&pcie_x2phy {
status = "disabled";
};
&pcie_x1_rp {
status = "disabled";
mhi_0: qcom,mhi@0 {
reg = <0 0 0 0 0 >;
};
};
&pcie_x2_rp {
status = "disabled";
mhi_1: qcom,mhi@1 {
reg = <0 0 0 0 0 >;
qrtr_instance_id = <0x21>;
#address-cells = <0x2>;
#size-cells = <0x2>;
memory-region = <&mhi_region1>;
#if !defined(__CNSS2__)
base-addr = <0x4E900000>;
m3-dump-addr = <0x4FD00000>;
etr-addr = <0x4FE00000>;
qcom,caldb-addr = <0x4FF00000>;
qcom,tgt-mem-mode = <0x1>;
mhi,max-channels = <30>;
mhi,timeout = <10000>;
qcom,board_id = <0xa4>;
#endif
};
};
&wifi3 {
status = "ok";
};
&qfprom {
status = "ok";
};
&tsens {
status = "ok";
};
&qcom_q6v5_wcss {
qcom,multipd_arch;
memory-region = <&q6_mem_regions>;
qcom,share_bootargs;
qcom,bootargs_smem = <507>;
boot-args = <0x2 0x4 0x2 0x12 0x0 0x0>;
/* IPQ5018 */
q6v5_wcss_userpd1 {
m3_firmware = "IPQ5018/m3_fw.mdt";
interrupts-extended = <&wcss_smp2p_in 8 0>,
<&wcss_smp2p_in 9 0>,
<&wcss_smp2p_in 12 0>,
<&wcss_smp2p_in 11 0>;
interrupt-names ="fatal",
"ready",
"spawn_ack",
"stop-ack";
qcom,smem-states = <&wcss_smp2p_out 8>,
<&wcss_smp2p_out 9>,
<&wcss_smp2p_out 10>;
qcom,smem-state-names = "shutdown",
"stop",
"spawn";
qca,asid = <1>;
qca,auto-restart;
qca,int_radio;
#ifdef __IPQ_MEM_PROFILE_256_MB__
memory-region = <&q6_ipq5018_data>, <&m3_dump>,
<&q6_etr_region>;
#else
memory-region = <&q6_ipq5018_data>, <&m3_dump>,
<&q6_etr_region>, <&q6_caldb_region>;
#endif
};
/* QCN6122 5G */
q6v5_wcss_userpd2 {
m3_firmware = "qcn6122/m3_fw.mdt";
interrupts-extended = <&wcss_smp2p_in 16 0>,
<&wcss_smp2p_in 17 0>,
<&wcss_smp2p_in 20 0>,
<&wcss_smp2p_in 19 0>;
interrupt-names ="fatal",
"ready",
"spawn_ack",
"stop-ack";
qcom,smem-states = <&wcss_smp2p_out 16>,
<&wcss_smp2p_out 17>,
<&wcss_smp2p_out 18>;
qcom,smem-state-names = "shutdown",
"stop",
"spawn";
qca,asid = <2>;
qca,auto-restart;
#ifdef __IPQ_MEM_PROFILE_256_MB__
memory-region = <&q6_qcn6122_data1>, <&m3_dump_qcn6122_1>,
<&q6_qcn6122_etr_1>;
#else
memory-region = <&q6_qcn6122_data1>, <&m3_dump_qcn6122_1>,
<&q6_qcn6122_etr_1>, <&q6_qcn6122_caldb_1>;
#endif
};
};
&i2c_0 {
pinctrl-0 = <&i2c_pins>;
pinctrl-names = "default";
status = "disabled";
};
&qgic_msi_0 {
status = "ok";
};
&wifi0 {
/* IPQ5018 */
qcom,multipd_arch;
#ifdef __IPQ_MEM_PROFILE_256_MB__
qcom,tgt-mem-mode = <2>;
#else
qcom,tgt-mem-mode = <1>;
#endif
qcom,board_id = <0x24>;
qcom,bdf-addr = <0x0 0x4C000000 0x4C000000 0x0 0x0>;
#ifdef __CNSS2__
qcom,caldb-addr = <0x0 0x4D000000 0 0 0>;
#else
qcom,caldb-addr = <0x4D000000>;
m3-dump-addr = <0x4CE00000>;
#endif
qcom,caldb-size = <0x200000>;
qcom,userpd-subsys-name = "q6v5_wcss_userpd1";
status = "ok";
};
&wifi1 {
/* QCN6122 5G */
qcom,multipd_arch;
#ifdef __IPQ_MEM_PROFILE_256_MB__
qcom,tgt-mem-mode = <2>;
#else
qcom,tgt-mem-mode = <1>;
#endif
qcom,board_id = <0x60>;
qcom,bdf-addr = <0x0 0x4D200000 0x4CF00000 0x0 0x0>;
#ifdef __CNSS2__
qcom,caldb-addr = <0x0 0x4E400000 0 0 0>;
#else
qcom,caldb-addr = <0x4E400000>;
m3-dump-addr = <0x4E200000>;
#endif
qcom,caldb-size = <0x500000>;
qcom,userpd-subsys-name = "q6v5_wcss_userpd2";
status = "ok";
};

View File

@@ -28,6 +28,15 @@ define Device/cig_wf186w
endef
TARGET_DEVICES += cig_wf186w
define Device/cig_wf186h
DEVICE_TITLE := Cigtech WF-186h
DEVICE_DTS := qcom-ipq5018-cig-wf186h
SUPPORTED_DEVICES := cig,wf186h
DEVICE_PACKAGES := ath11k-wifi-cig-wf186h ath11k-firmware-ipq50xx-map-spruce
DEVICE_DTS_CONFIG := config@mp03.3
endef
TARGET_DEVICES += cig_wf186h
define Device/cybertan_eww622_a1
DEVICE_TITLE := CyberTan EWW622-A1
DEVICE_DTS := qcom-ipq5018-eww622-a1

View File

@@ -82,7 +82,7 @@ CONFIG_MIGRATION=y
CONFIG_MPILIB=y
CONFIG_MSM_SECURE_BUFFER=y
CONFIG_NEED_SG_DMA_LENGTH=y
CONFIG_NET_SWITCHDEV=y
# CONFIG_NET_SWITCHDEV is not set
CONFIG_NUM_ALT_PARTITION=16
CONFIG_OF_IOMMU=y
CONFIG_OID_REGISTRY=y

View File

@@ -4,7 +4,7 @@ CONFIG_ARCH_IPQ807x=y
CONFIG_IPQ_ADSS_807x=y
CONFIG_IPQ_APSS_807x=y
CONFIG_IPQ_GCC_807x=y
CONFIG_NET_SWITCHDEV=y
# CONFIG_NET_SWITCHDEV is not set
CONFIG_NUM_ALT_PARTITION=16
CONFIG_PINCTRL_IPQ807x=y
# CONFIG_IPC_LOGGING is not set

View File

@@ -0,0 +1,67 @@
From: Andy Ren <andy.ren@getcruise.com>
Date: Mon, 7 Nov 2022 09:42:42 -0800
Subject: [PATCH] net/core: Allow live renaming when an interface is up
Allow a network interface to be renamed when the interface
is up.
As described in the netconsole documentation [1], when netconsole is
used as a built-in, it will bring up the specified interface as soon as
possible. As a result, user space will not be able to rename the
interface since the kernel disallows renaming of interfaces that are
administratively up unless the 'IFF_LIVE_RENAME_OK' private flag was set
by the kernel.
The original solution [2] to this problem was to add a new parameter to
the netconsole configuration parameters that allows renaming of
the interface used by netconsole while it is administratively up.
However, during the discussion that followed, it became apparent that we
have no reason to keep the current restriction and instead we should
allow user space to rename interfaces regardless of their administrative
state:
1. The restriction was put in place over 20 years ago when renaming was
only possible via IOCTL and before rtnetlink started notifying user
space about such changes like it does today.
2. The 'IFF_LIVE_RENAME_OK' flag was added over 3 years ago in version
5.2 and no regressions were reported.
3. In-kernel listeners to 'NETDEV_CHANGENAME' do not seem to care about
the administrative state of interface.
Therefore, allow user space to rename running interfaces by removing the
restriction and the associated 'IFF_LIVE_RENAME_OK' flag. Help in
possible triage by emitting a message to the kernel log that an
interface was renamed while UP.
[1] https://www.kernel.org/doc/Documentation/networking/netconsole.rst
[2] https://lore.kernel.org/netdev/20221102002420.2613004-1-andy.ren@getcruise.com/
Signed-off-by: Andy Ren <andy.ren@getcruise.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1152,8 +1152,6 @@ int dev_change_name(struct net_device *d
BUG_ON(!dev_net(dev));
net = dev_net(dev);
- if (dev->flags & IFF_UP)
- return -EBUSY;
write_seqcount_begin(&devnet_rename_seq);
@@ -1171,7 +1169,8 @@ int dev_change_name(struct net_device *d
}
if (oldname[0] && !strchr(oldname, '%'))
- netdev_info(dev, "renamed from %s\n", oldname);
+ netdev_info(dev, "renamed from %s%s\n", oldname,
+ dev->flags & IFF_UP ? " (while UP)" : "");
old_assign_type = dev->name_assign_type;
dev->name_assign_type = NET_NAME_RENAMED;

View File

@@ -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;
@@ -150,7 +300,7 @@ function is_equal(val1, val2) {
if (!is_equal(val1[key], val2[key]))
return false;
for (let key in val2)
if (!val1[key])
if (val1[key] == null)
return false;
return true;
} else {
@@ -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 };

View File

@@ -725,8 +725,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_server" ] && {
append bss_conf "acct_server_addr=$acct_server" "$N"
@@ -772,9 +771,9 @@ hostapd_set_bss_options() {
# Here we make the assumption that if we're in open mode
# with WPS enabled, we got to be in unconfigured state.
wps_not_configured=1
vlan_possible=1
[ "$macfilter" = radius ] && {
append_radius_server
vlan_possible=1
}
;;
psk|sae|psk-sae)

View File

@@ -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();
@@ -31,7 +31,7 @@ function iface_remove(cfg)
wdev_remove(bss.ifname);
}
function iface_gen_config(phy, config)
function iface_gen_config(phy, config, start_disabled)
{
let str = `data:
${join("\n", config.radio.data)}
@@ -41,18 +41,92 @@ 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 += `
start_disabled=1
`;
}
return str;
}
function iface_restart(phy, config, old_config)
function iface_freq_info(iface, config, params)
{
let freq = params.frequency;
if (!freq)
return null;
let sec_offset = params.sec_chan_offset;
if (sec_offset != -1 && sec_offset != 1)
sec_offset = 0;
let width = 0;
for (let line in config.radio.data) {
if (!sec_offset && match(line, /^ht_capab=.*HT40/)) {
sec_offset = null; // auto-detect
continue;
}
let val = match(line, /^(vht_oper_chwidth|he_oper_chwidth)=(\d+)/);
if (!val)
continue;
val = int(val[2]);
if (val > width)
width = val;
}
if (freq < 4000)
width = 0;
return hostapd.freq_info(freq, sec_offset, width);
}
function iface_add(phy, config, phy_status)
{
let config_inline = iface_gen_config(phy, config, !!phy_status);
let bss = config.bss[0];
let ret = hostapd.add_iface(`bss_config=${bss.ifname}:${config_inline}`);
if (ret < 0)
return false;
if (!phy_status)
return true;
let iface = hostapd.interfaces[bss.ifname];
if (!iface)
return false;
let freq_info = iface_freq_info(iface, config, phy_status);
return iface.start(freq_info) >= 0;
}
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);
@@ -61,15 +135,29 @@ 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)
hostapd.printf(`Failed to create ${bss.ifname} on phy ${phy}: ${err}`);
let config_inline = iface_gen_config(phy, config);
let ubus = hostapd.data.ubus;
let phy_status = ubus.call("wpa_supplicant", "phy_status", { phy: phy });
if (phy_status && phy_status.state == "COMPLETED") {
if (iface_add(phy, config, phy_status))
return;
hostapd.printf(`Failed to bring up phy ${phy} ifname=${bss.ifname} with supplicant provided frequency`);
}
ubus.call("wpa_supplicant", "phy_set_state", { phy: phy, stop: true });
if (hostapd.add_iface(`bss_config=${bss.ifname}:${config_inline}`) < 0)
if (!iface_add(phy, config))
hostapd.printf(`hostapd.add_iface failed for phy ${phy} ifname=${bss.ifname}`);
ubus.call("wpa_supplicant", "phy_set_state", { phy: phy, stop: false });
}
@@ -111,8 +199,65 @@ 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;
delete new_cfg.hash.vlan_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;
@@ -122,82 +267,230 @@ 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(`Could not update config data files for bss ${ifname}`);
return false;
} else {
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`);
if (bss.set_config(config_inline, i) < 0) {
hostapd.printf(`Failed to set config for bss ${ifname}`);
return false;
}
}
@@ -205,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];
@@ -214,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)
@@ -268,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]);
@@ -294,28 +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: {
@@ -326,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;
@@ -344,34 +676,10 @@ let main_obj = {
return 0;
}
let freq = req.args.frequency;
if (!freq)
if (!req.args.frequency)
return libubus.STATUS_INVALID_ARGUMENT;
let sec_offset = req.args.sec_chan_offset;
if (sec_offset != -1 && sec_offset != 1)
sec_offset = 0;
let width = 0;
for (let line in config.radio.data) {
if (!sec_offset && match(line, /^ht_capab=.*HT40/)) {
sec_offset = null; // auto-detect
continue;
}
let val = match(line, /^(vht_oper_chwidth|he_oper_chwidth)=(\d+)/);
if (!val)
continue;
val = int(val[2]);
if (val > width)
width = val;
}
if (freq < 4000)
width = 0;
let freq_info = hostapd.freq_info(freq, sec_offset, width);
let freq_info = iface_freq_info(iface, config, req.args);
if (!freq_info)
return libubus.STATUS_UNKNOWN_ERROR;
@@ -380,14 +688,34 @@ let main_obj = {
freq_info.csa_count = req.args.csa_count ?? 10;
ret = iface.switch_channel(freq_info);
} else {
iface.stop();
ret = iface.start(freq_info);
}
if (!ret)
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: {
@@ -395,7 +723,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;
@@ -403,34 +731,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;
@@ -440,19 +763,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;
}
})
},
};

View File

@@ -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)
@@ -47,7 +55,7 @@ function iface_start(wdev)
system(cmd);
} else if (wdev.mode == "mesh") {
let cmd = [ "iw", "dev", ifname, "mesh", "join", wdev.ssid, "freq", wdev.freq, wdev.htmode ];
for (let key in [ "beacon-interval", "mcast-rate" ])
for (let key in [ "mcast-rate", "beacon-interval" ])
if (wdev[key])
push(cmd, key, wdev[key]);
system(cmd);
@@ -114,43 +122,86 @@ function add_existing(phy, config)
}
}
function usage()
{
warn(`Usage: ${basename(sourcepath())} <phy> <command> [<arguments>]
let statefile = `/var/run/wdev-${phy}.json`;
for (let dev in ARGV)
keep_devices[dev] = true;
if (!phy || !new_config) {
warn(`Usage: ${basename(sourcepath())} <phy> <config> [<device]...]\n`);
Commands:
set_config <config> [<device]...] - set phy configuration
get_macaddr <id> - get phy MAC address for vif index <id>
`);
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);

View File

@@ -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);
@@ -43,6 +51,11 @@ function iface_cb(new_if, old_if)
return;
}
if (new_if && old_if)
wpas.printf(`Update configuration for interface ${old_if.config.iface}`);
else if (old_if)
wpas.printf(`Remove interface ${old_if.config.iface}`);
if (old_if)
iface_stop(old_if);
}
@@ -73,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 = {
@@ -106,6 +132,55 @@ 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: ""
},
call: function(req) {
if (!req.args.phy)
return libubus.STATUS_INVALID_ARGUMENT;
let phy = wpas.data.config[req.args.phy];
if (!phy)
return libubus.STATUS_NOT_FOUND;
for (let ifname in phy.data) {
try {
let iface = wpas.interfaces[ifname];
if (!iface)
continue;
let status = iface.status();
if (!status)
continue;
if (status.state == "INTERFACE_DISABLED")
continue;
status.ifname = ifname;
return status;
} catch (e) {
continue;
}
}
return libubus.STATUS_NOT_FOUND;
}
},
config_set: {
args: {
phy: "",
@@ -116,6 +191,7 @@ let main_obj = {
if (!req.args.phy)
return libubus.STATUS_INVALID_ARGUMENT;
wpas.printf(`Set new config for phy ${req.args.phy}`);
try {
if (req.args.config)
set_config(req.args.phy, req.args.config);
@@ -188,6 +264,7 @@ function iface_hostapd_notify(phy, ifname, iface, state)
switch (state) {
case "DISCONNECTED":
case "AUTHENTICATING":
case "SCANNING":
msg.up = false;
break;
case "INTERFACE_DISABLED":

View File

@@ -0,0 +1,43 @@
From: Harshitha Prem <quic_hprem@quicinc.com>
Date: Wed, 22 Feb 2023 09:29:01 +0530
Subject: [PATCH] nl80211: Add frequency info in start AP command
When ACS is configured in multiple BSS case, sometimes a virtual AP
interface does not come up as the channel context information between
different BSSs of the same band does not match.
Same behavior is observed in case of multiple band/hardware under a
single wiphy, when we bring up multiple virtual interface in various
bands simultaneously and the kernel maps a random channel as it has more
than one channel context, e.g., say a 2.4 GHz channel to a 5 GHz virtual
AP interface when the start AP command is sent. This is because the
frequency information is not present in the command.
Add the frequency information into the start AP netlink command so that
the kernel maps the appropriate channel context by parsing it instead of
using a previous set channel information.
Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
---
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -167,6 +167,8 @@ static int nl80211_send_frame_cmd(struct
const u16 *csa_offs, size_t csa_offs_len);
static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
int report);
+static int nl80211_put_freq_params(struct nl_msg *msg,
+ const struct hostapd_freq_params *freq);
#define IFIDX_ANY -1
@@ -4717,6 +4719,9 @@ static int wpa_driver_nl80211_set_ap(voi
nla_nest_end(msg, spr);
}
+ if (params->freq && nl80211_put_freq_params(msg, params->freq) < 0)
+ goto fail;
+
if (params->freq && params->freq->he_enabled) {
struct nlattr *bss_color;

View File

@@ -0,0 +1,20 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 14 Sep 2023 10:53:50 +0200
Subject: [PATCH] driver_nl80211: fix setting QoS map on secondary BSSs
The setting is per-BSS, not per PHY
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -10045,7 +10045,7 @@ static int nl80211_set_qos_map(void *pri
wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
qos_map_set, qos_map_set_len);
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_QOS_MAP)) ||
nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) {
nlmsg_free(msg);
return -ENOBUFS;

View File

@@ -0,0 +1,18 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 14 Sep 2023 11:28:03 +0200
Subject: [PATCH] driver_nl80211: update drv->ifindex on removing the first
BSS
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -8003,6 +8003,7 @@ static int wpa_driver_nl80211_if_remove(
if (drv->first_bss->next) {
drv->first_bss = drv->first_bss->next;
drv->ctx = drv->first_bss->ctx;
+ drv->ifindex = drv->first_bss->ifindex;
os_free(bss);
} else {
wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");

View File

@@ -1,5 +1,7 @@
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
Index: hostapd-2021-02-20-59e9794c/hostapd/Makefile
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/hostapd/Makefile
+++ hostapd-2021-02-20-59e9794c/hostapd/Makefile
@@ -166,6 +166,12 @@ OBJS += ../src/common/hw_features_common
OBJS += ../src/eapol_auth/eapol_auth_sm.o
@@ -13,8 +15,10 @@
ifdef CONFIG_CODE_COVERAGE
CFLAGS += -O0 -fprofile-arcs -ftest-coverage
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
Index: hostapd-2021-02-20-59e9794c/src/ap/hostapd.h
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/hostapd.h
+++ hostapd-2021-02-20-59e9794c/src/ap/hostapd.h
@@ -17,6 +17,7 @@
#include "utils/list.h"
#include "ap_config.h"
@@ -39,8 +43,10 @@
void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
struct hostapd_iface * hostapd_alloc_iface(void);
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
Index: hostapd-2021-02-20-59e9794c/src/ap/hostapd.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/hostapd.c
+++ hostapd-2021-02-20-59e9794c/src/ap/hostapd.c
@@ -376,6 +376,7 @@ void hostapd_free_hapd_data(struct hosta
hapd->beacon_set_done = 0;
@@ -82,8 +88,10 @@
hostapd_interface_deinit(iface);
wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
__func__, driver, drv_priv);
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
Index: hostapd-2021-02-20-59e9794c/src/ap/ieee802_11.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/ieee802_11.c
+++ hostapd-2021-02-20-59e9794c/src/ap/ieee802_11.c
@@ -3421,13 +3421,18 @@ static void handle_auth(struct hostapd_d
u16 auth_alg, auth_transaction, status_code;
u16 resp = WLAN_STATUS_SUCCESS;
@@ -170,8 +178,10 @@
sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
Index: hostapd-2021-02-20-59e9794c/src/ap/beacon.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/beacon.c
+++ hostapd-2021-02-20-59e9794c/src/ap/beacon.c
@@ -823,6 +823,12 @@ void handle_probe_req(struct hostapd_dat
u16 csa_offs[2];
size_t csa_offs_len;
@@ -198,8 +208,10 @@
/* TODO: verify that supp_rates contains at least one matching rate
* with AP configuration */
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
Index: hostapd-2021-02-20-59e9794c/src/ap/drv_callbacks.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/drv_callbacks.c
+++ hostapd-2021-02-20-59e9794c/src/ap/drv_callbacks.c
@@ -145,6 +145,10 @@ int hostapd_notif_assoc(struct hostapd_d
u16 reason = WLAN_REASON_UNSPECIFIED;
int status = WLAN_STATUS_SUCCESS;
@@ -224,8 +236,22 @@
#ifdef CONFIG_P2P
if (elems.p2p) {
wpabuf_free(sta->p2p_ie);
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -981,9 +991,11 @@ void hostapd_event_ch_switch(struct host
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs);
+ hostapd_ubus_notify_csa(hapd, freq);
} else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs);
+ hostapd_ubus_notify_csa(hapd, freq);
} else if (is_dfs &&
hostapd_is_dfs_required(hapd->iface) &&
!hostapd_is_dfs_chan_available(hapd->iface) &&
Index: hostapd-2021-02-20-59e9794c/src/ap/sta_info.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/sta_info.c
+++ hostapd-2021-02-20-59e9794c/src/ap/sta_info.c
@@ -458,6 +458,7 @@ void ap_handle_timer(void *eloop_ctx, vo
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
@@ -304,8 +330,10 @@
if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx)
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
Index: hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_glue.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/wpa_auth_glue.c
+++ hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_glue.c
@@ -265,6 +265,7 @@ static void hostapd_wpa_auth_psk_failure
struct hostapd_data *hapd = ctx;
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR,
@@ -314,8 +342,10 @@
}
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/Makefile
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/wpa_supplicant/Makefile
+++ hostapd-2021-02-20-59e9794c/wpa_supplicant/Makefile
@@ -169,6 +169,13 @@ ifdef CONFIG_EAPOL_TEST
CFLAGS += -Werror -DEAPOL_TEST
endif
@@ -340,8 +370,10 @@
endif
CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/wpa_supplicant.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/wpa_supplicant/wpa_supplicant.c
+++ hostapd-2021-02-20-59e9794c/wpa_supplicant/wpa_supplicant.c
@@ -6943,6 +6943,8 @@ struct wpa_supplicant * wpa_supplicant_a
}
#endif /* CONFIG_P2P */
@@ -373,8 +405,10 @@
return 0;
}
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/wpa_supplicant_i.h
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/wpa_supplicant/wpa_supplicant_i.h
+++ hostapd-2021-02-20-59e9794c/wpa_supplicant/wpa_supplicant_i.h
@@ -19,6 +19,7 @@
#include "wps/wps_defs.h"
#include "config_ssid.h"
@@ -400,8 +434,10 @@
#ifdef CONFIG_MATCH_IFACE
int matched;
#endif /* CONFIG_MATCH_IFACE */
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/wps_supplicant.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/wpa_supplicant/wps_supplicant.c
+++ hostapd-2021-02-20-59e9794c/wpa_supplicant/wps_supplicant.c
@@ -33,6 +33,7 @@
#include "p2p/p2p.h"
#include "p2p_supplicant.h"
@@ -419,8 +455,10 @@
if (wpa_s->conf->wps_cred_processing == 1)
return 0;
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/main.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/wpa_supplicant/main.c
+++ hostapd-2021-02-20-59e9794c/wpa_supplicant/main.c
@@ -202,7 +202,7 @@ int main(int argc, char *argv[])
for (;;) {
@@ -440,8 +478,10 @@
case 'o':
params.override_driver = optarg;
break;
--- a/src/ap/rrm.c
+++ b/src/ap/rrm.c
Index: hostapd-2021-02-20-59e9794c/src/ap/rrm.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/rrm.c
+++ hostapd-2021-02-20-59e9794c/src/ap/rrm.c
@@ -89,6 +89,9 @@ static void hostapd_handle_beacon_report
return;
wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s",
@@ -452,8 +492,10 @@
}
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
Index: hostapd-2021-02-20-59e9794c/src/ap/vlan_init.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/vlan_init.c
+++ hostapd-2021-02-20-59e9794c/src/ap/vlan_init.c
@@ -22,6 +22,7 @@
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
int existsok)
@@ -490,8 +532,10 @@
return hostapd_vlan_if_remove(hapd, vlan->ifname);
}
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
Index: hostapd-2021-02-20-59e9794c/src/ap/dfs.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/dfs.c
+++ hostapd-2021-02-20-59e9794c/src/ap/dfs.c
@@ -1226,6 +1226,8 @@ int hostapd_dfs_nop_finished(struct host
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
@@ -501,8 +545,10 @@
/* Proceed only if DFS is not offloaded to the driver */
if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
return 0;
--- a/src/ap/airtime_policy.c
+++ b/src/ap/airtime_policy.c
Index: hostapd-2021-02-20-59e9794c/src/ap/airtime_policy.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/airtime_policy.c
+++ hostapd-2021-02-20-59e9794c/src/ap/airtime_policy.c
@@ -108,8 +108,14 @@ static void set_sta_weights(struct hosta
{
struct sta_info *sta;
@@ -532,8 +578,10 @@
if (weight)
return sta_set_airtime_weight(hapd, sta, weight);
}
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
Index: hostapd-2021-02-20-59e9794c/src/ap/sta_info.h
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/sta_info.h
+++ hostapd-2021-02-20-59e9794c/src/ap/sta_info.h
@@ -323,6 +323,7 @@ struct sta_info {
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_AIRTIME_POLICY
@@ -542,8 +590,10 @@
struct os_reltime backlogged_until;
#endif /* CONFIG_AIRTIME_POLICY */
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
Index: hostapd-2021-02-20-59e9794c/src/ap/wnm_ap.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/wnm_ap.c
+++ hostapd-2021-02-20-59e9794c/src/ap/wnm_ap.c
@@ -442,7 +442,8 @@ static void ieee802_11_rx_bss_trans_mgmt
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
@@ -582,8 +632,10 @@
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
}
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
Index: hostapd-2021-02-20-59e9794c/src/utils/eloop.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/utils/eloop.c
+++ hostapd-2021-02-20-59e9794c/src/utils/eloop.c
@@ -77,6 +77,9 @@ struct eloop_sock_table {
struct eloop_data {
int max_sock;
@@ -632,8 +684,10 @@
void eloop_terminate(void)
{
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
Index: hostapd-2021-02-20-59e9794c/src/utils/eloop.h
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/utils/eloop.h
+++ hostapd-2021-02-20-59e9794c/src/utils/eloop.h
@@ -65,6 +65,9 @@ typedef void (*eloop_timeout_handler)(vo
*/
typedef void (*eloop_signal_handler)(int sig, void *signal_ctx);
@@ -663,8 +717,10 @@
/**
* eloop_run - Start the event loop
*
Index: hostapd-2021-02-20-59e9794c/src/utils/uloop.c
===================================================================
--- /dev/null
+++ b/src/utils/uloop.c
+++ hostapd-2021-02-20-59e9794c/src/utils/uloop.c
@@ -0,0 +1,64 @@
+#include <libubox/uloop.h>
+#include "includes.h"

View File

@@ -287,7 +287,33 @@
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -5827,6 +5827,7 @@ union wpa_event_data {
@@ -3357,6 +3357,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)
@@ -5827,6 +5846,7 @@ union wpa_event_data {
/**
* struct ch_switch
@@ -295,7 +321,7 @@
* @freq: Frequency of new channel in MHz
* @ht_enabled: Whether this is an HT channel
* @ch_offset: Secondary channel offset
@@ -5835,6 +5836,7 @@ union wpa_event_data {
@@ -5835,6 +5855,7 @@ union wpa_event_data {
* @cf2: Center frequency 2
*/
struct ch_switch {
@@ -348,3 +374,187 @@
switch (event) {
case EVENT_AUTH:
#ifdef CONFIG_FST
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -367,6 +367,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
@@ -1222,7 +1222,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);
@@ -1258,7 +1258,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);
@@ -7609,6 +7609,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,
@@ -7668,21 +7669,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) {
@@ -8041,6 +8038,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)
{
@@ -9385,6 +9426,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,
@@ -11967,6 +12039,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,

View File

@@ -10,7 +10,7 @@
--- a/src/ap/x_snoop.c
+++ b/src/ap/x_snoop.c
@@ -31,14 +31,16 @@ int x_snoop_init(struct hostapd_data *ha
@@ -31,28 +31,31 @@ int x_snoop_init(struct hostapd_data *ha
return -1;
}
@@ -29,13 +29,20 @@
wpa_printf(MSG_DEBUG,
"x_snoop: Failed to enable proxyarp on the bridge port");
return -1;
@@ -52,7 +54,8 @@ int x_snoop_init(struct hostapd_data *ha
}
if (hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT,
- 1)) {
+ conf->snoop_iface[0] ? conf->snoop_iface : NULL, 1)) {
wpa_printf(MSG_DEBUG,
"x_snoop: Failed to enable accepting gratuitous ARP on the bridge");
return -1;
}
#ifdef CONFIG_IPV6
- if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) {
+ if (!conf->snoop_iface[0] &&
+ hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) {
+ hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, NULL, 1)) {
wpa_printf(MSG_DEBUG,
"x_snoop: Failed to enable multicast snooping on the bridge");
return -1;
@@ -44,15 +51,27 @@
struct hostapd_bss_config *conf = hapd->conf;
struct l2_packet_data *l2;
+ const char *ifname = conf->bridge;
- l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1);
+
+ if (conf->snoop_iface[0])
+ ifname = conf->snoop_iface;
+
- l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1);
+ l2 = l2_packet_init(ifname, NULL, ETH_P_ALL, handler, hapd, 1);
if (l2 == NULL) {
wpa_printf(MSG_DEBUG,
"x_snoop: Failed to initialize L2 packet processing %s",
@@ -125,7 +132,10 @@ void x_snoop_mcast_to_ucast_convert_send
void x_snoop_deinit(struct hostapd_data *hapd)
{
- hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0);
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT,
+ conf->snoop_iface[0] ? conf->snoop_iface : NULL, 0);
hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0);
hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0);
}
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2343,6 +2343,8 @@ static int hostapd_config_fill(struct ho
@@ -64,3 +83,55 @@
} else if (os_strcmp(buf, "vlan_bridge") == 0) {
os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge));
} else if (os_strcmp(buf, "wds_bridge") == 0) {
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -340,12 +340,12 @@ static inline int hostapd_drv_br_port_se
static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd,
enum drv_br_net_param param,
- unsigned int val)
+ const char *ifname, unsigned int val)
{
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
hapd->driver->br_set_net_param == NULL)
return -1;
- return hapd->driver->br_set_net_param(hapd->drv_priv, param, val);
+ return hapd->driver->br_set_net_param(hapd->drv_priv, param, ifname, val);
}
static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -3756,7 +3756,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,
- unsigned int val);
+ const char *ifname, unsigned int val);
/**
* get_wowlan - Get wake-on-wireless status
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -10825,7 +10825,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,
- unsigned int val)
+ const char *ifname, unsigned int val)
{
struct i802_bss *bss = priv;
char path[128];
@@ -10851,8 +10851,11 @@ static int wpa_driver_br_set_net_param(v
return -EINVAL;
}
+ if (!ifname)
+ ifname = bss->brname;
+
os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
- ip_version, bss->brname, param_txt);
+ ip_version, ifname, param_txt);
set_val:
if (linux_write_system_file(path, val))

View File

@@ -19,18 +19,6 @@
enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
--- a/src/ap/ubus.c
+++ b/src/ap/ubus.c
@@ -424,6 +424,9 @@ hostapd_bss_get_status(struct ubus_conte
hapd->iface->cac_started ? hapd->iface->dfs_cac_ms / 1000 - now.sec : 0);
blobmsg_close_table(&b, dfs_table);
+ if (hapd->conf->uci_section)
+ blobmsg_add_string(&b, "uci_section", hapd->conf->uci_section);
+
ubus_send_reply(ctx, req, b.head);
return 0;
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -785,6 +785,7 @@ void hostapd_config_free_bss(struct host

View File

@@ -50,42 +50,4 @@
return NL_SKIP;
}
--- a/src/ap/ubus.c
+++ b/src/ap/ubus.c
@@ -306,6 +306,36 @@ hostapd_bss_get_clients(struct ubus_cont
blobmsg_add_u32(&b, "tx", sta_driver_data.current_tx_rate * 100);
blobmsg_close_table(&b, r);
blobmsg_add_u32(&b, "signal", sta_driver_data.signal);
+
+ r = blobmsg_open_table(&b, "mcs");
+ if (sta_driver_data.rx_hemcs) {
+ blobmsg_add_u32(&b, "he", 1);
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_hemcs);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_hemcs);
+ } else if (sta_driver_data.rx_vhtmcs) {
+ blobmsg_add_u32(&b, "vht", 1);
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_vhtmcs);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_vhtmcs);
+ } else {
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_mcs);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_mcs);
+ }
+ blobmsg_close_table(&b, r);
+
+ r = blobmsg_open_table(&b, "nss");
+ if (sta_driver_data.rx_he_nss) {
+ blobmsg_add_u32(&b, "he", 1);
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_he_nss);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_he_nss);
+ } else if (sta_driver_data.rx_vht_nss) {
+ blobmsg_add_u32(&b, "vht", 1);
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_vht_nss);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_vht_nss);
+ } else {
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_mcs);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_mcs);
+ }
+ blobmsg_close_table(&b, r);
}
hostapd_parse_capab_blobmsg(sta);

View File

@@ -0,0 +1,48 @@
Index: hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_ft.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/wpa_auth_ft.c
+++ hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_ft.c
@@ -3067,6 +3067,7 @@ static int wpa_ft_process_auth_req(struc
size_t identity_len = 0, radius_cui_len = 0;
int use_sha384;
size_t pmk_r1_len, kdk_len;
+ struct os_reltime now;
*resp_ies = NULL;
*resp_ies_len = 0;
@@ -3185,10 +3186,19 @@ pmk_r1_derived:
os_memcpy(sm->pmk_r1, pmk_r1, pmk_r1_len);
sm->pmk_r1_len = pmk_r1_len;
- if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
- wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
- "ANonce");
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ if (os_get_reltime(&now) < 0 ||
+ os_reltime_expired(&now, &sm->ANonce_time, 1)) {
+ if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
+ "ANonce");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ sm->ANonce_time.sec = now.sec;
+ sm->ANonce_time.usec = now.usec;
+ wpa_printf(MSG_INFO, "FT: ANonce was randomized");
+ } else {
+ wpa_printf(MSG_INFO, "FT: ANonce has not expired");
+
}
wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
Index: hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_i.h
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/wpa_auth_i.h
+++ hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_i.h
@@ -54,6 +54,7 @@ struct wpa_state_machine {
bool MICVerified;
bool GUpdateStationKeys;
u8 ANonce[WPA_NONCE_LEN];
+ struct os_reltime ANonce_time;
u8 SNonce[WPA_NONCE_LEN];
u8 alt_SNonce[WPA_NONCE_LEN];
u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];

View File

@@ -61,28 +61,6 @@
};
--- a/src/ap/ubus.c
+++ b/src/ap/ubus.c
@@ -336,6 +336,9 @@ hostapd_bss_get_clients(struct ubus_cont
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_mcs);
}
blobmsg_close_table(&b, r);
+
+ if (sta->signal_mgmt)
+ blobmsg_add_u32(&b, "signal_mgmt", sta->signal_mgmt);
}
hostapd_parse_capab_blobmsg(sta);
@@ -457,6 +460,9 @@ hostapd_bss_get_status(struct ubus_conte
if (hapd->conf->uci_section)
blobmsg_add_string(&b, "uci_section", hapd->conf->uci_section);
+ if (hapd->signal_mgmt)
+ blobmsg_add_u32(&b, "signal_mgmt", hapd->signal_mgmt);
+
ubus_send_reply(ctx, req, b.head);
return 0;
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -451,6 +451,7 @@ struct hostapd_data {

View File

@@ -306,6 +306,39 @@ hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj,
blobmsg_add_u32(&b, "tx", sta_driver_data.current_tx_rate * 100);
blobmsg_close_table(&b, r);
blobmsg_add_u32(&b, "signal", sta_driver_data.signal);
r = blobmsg_open_table(&b, "mcs");
if (sta_driver_data.rx_hemcs) {
blobmsg_add_u32(&b, "he", 1);
blobmsg_add_u32(&b, "rx", sta_driver_data.rx_hemcs);
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_hemcs);
} else if (sta_driver_data.rx_vhtmcs) {
blobmsg_add_u32(&b, "vht", 1);
blobmsg_add_u32(&b, "rx", sta_driver_data.rx_vhtmcs);
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_vhtmcs);
} else {
blobmsg_add_u32(&b, "rx", sta_driver_data.rx_mcs);
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_mcs);
}
blobmsg_close_table(&b, r);
r = blobmsg_open_table(&b, "nss");
if (sta_driver_data.rx_he_nss) {
blobmsg_add_u32(&b, "he", 1);
blobmsg_add_u32(&b, "rx", sta_driver_data.rx_he_nss);
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_he_nss);
} else if (sta_driver_data.rx_vht_nss) {
blobmsg_add_u32(&b, "vht", 1);
blobmsg_add_u32(&b, "rx", sta_driver_data.rx_vht_nss);
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_vht_nss);
} else {
blobmsg_add_u32(&b, "rx", sta_driver_data.rx_mcs);
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_mcs);
}
blobmsg_close_table(&b, r);
if (sta->signal_mgmt)
blobmsg_add_u32(&b, "signal_mgmt", sta->signal_mgmt);
}
hostapd_parse_capab_blobmsg(sta);
@@ -424,6 +457,12 @@ hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
hapd->iface->cac_started ? hapd->iface->dfs_cac_ms / 1000 - now.sec : 0);
blobmsg_close_table(&b, dfs_table);
if (hapd->conf->uci_section)
blobmsg_add_string(&b, "uci_section", hapd->conf->uci_section);
if (hapd->signal_mgmt)
blobmsg_add_u32(&b, "signal_mgmt", hapd->signal_mgmt);
ubus_send_reply(ctx, req, b.head);
return 0;
@@ -1698,6 +1737,19 @@ void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *
ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
}
void hostapd_ubus_notify_csa(struct hostapd_data *hapd, int freq)
{
if (!hapd->ubus.obj.has_subscribers)
return;
blob_buf_init(&b, 0);
blobmsg_add_string(&b, "ifname", hapd->conf->iface);
blobmsg_add_u32(&b, "freq", freq);
blobmsg_printf(&b, "bssid", MACSTR, MAC2STR(hapd->conf->bssid));
ubus_notify(ctx, &hapd->ubus.obj, "channel-switch", b.head, -1);
}
void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta)
{

File diff suppressed because it is too large Load Diff

View File

@@ -65,6 +65,7 @@ void hostapd_ubus_free(struct hapd_interfaces *interfaces);
int hostapd_ubus_notify_bss_transition_query(
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
const u8 *candidate_list, u16 candidate_list_len);
void hostapd_ubus_notify_csa(struct hostapd_data *hapd, int freq);
#else

View File

@@ -7,6 +7,8 @@
#include "beacon.h"
#include "hw_features.h"
#include "ap_drv_ops.h"
#include "dfs.h"
#include "acs.h"
#include <libubox/uloop.h>
static uc_resource_type_t *global_type, *bss_type, *iface_type;
@@ -109,6 +111,94 @@ uc_hostapd_remove_iface(uc_vm_t *vm, size_t nargs)
return NULL;
}
static struct hostapd_vlan *
bss_conf_find_vlan(struct hostapd_bss_config *bss, int id)
{
struct hostapd_vlan *vlan;
for (vlan = bss->vlan; vlan; vlan = vlan->next)
if (vlan->vlan_id == id)
return vlan;
return NULL;
}
static int
bss_conf_rename_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
const char *ifname)
{
if (!strcmp(ifname, vlan->ifname))
return 0;
hostapd_drv_if_rename(hapd, WPA_IF_AP_VLAN, vlan->ifname, ifname);
os_strlcpy(vlan->ifname, ifname, sizeof(vlan->ifname));
return 0;
}
static int
bss_reload_vlans(struct hostapd_data *hapd, struct hostapd_bss_config *bss)
{
struct hostapd_bss_config *old_bss = hapd->conf;
struct hostapd_vlan *vlan, *vlan_new, *wildcard;
char ifname[IFNAMSIZ + 1], vlan_ifname[IFNAMSIZ + 1], *pos;
int ret;
vlan = bss_conf_find_vlan(old_bss, VLAN_ID_WILDCARD);
wildcard = bss_conf_find_vlan(bss, VLAN_ID_WILDCARD);
if (!!vlan != !!wildcard)
return -1;
if (vlan && wildcard && strcmp(vlan->ifname, wildcard->ifname) != 0)
strcpy(vlan->ifname, wildcard->ifname);
else
wildcard = NULL;
for (vlan = bss->vlan; vlan; vlan = vlan->next) {
if (vlan->vlan_id == VLAN_ID_WILDCARD ||
vlan->dynamic_vlan > 0)
continue;
if (!bss_conf_find_vlan(old_bss, vlan->vlan_id))
return -1;
}
for (vlan = old_bss->vlan; vlan; vlan = vlan->next) {
if (vlan->vlan_id == VLAN_ID_WILDCARD)
continue;
if (vlan->dynamic_vlan == 0) {
vlan_new = bss_conf_find_vlan(bss, vlan->vlan_id);
if (!vlan_new)
return -1;
if (bss_conf_rename_vlan(hapd, vlan, vlan_new->ifname))
return -1;
continue;
}
if (!wildcard)
continue;
os_strlcpy(ifname, wildcard->ifname, sizeof(ifname));
pos = os_strchr(ifname, '#');
if (!pos)
return -1;
*pos++ = '\0';
ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s%d%s",
ifname, vlan->vlan_id, pos);
if (os_snprintf_error(sizeof(vlan_ifname), ret))
return -1;
if (bss_conf_rename_vlan(hapd, vlan, vlan_ifname))
return -1;
}
return 0;
}
static uc_value_t *
uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
{
@@ -118,6 +208,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;
@@ -129,9 +220,28 @@ 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);
ret = bss_reload_vlans(hapd, bss);
goto done;
}
hostapd_bss_deinit_no_free(hapd);
hostapd_drv_stop_ap(hapd);
hostapd_free_hapd_data(hapd);
@@ -142,12 +252,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->multiple_bssid);
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);
}
@@ -178,10 +290,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;
@@ -191,8 +308,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);
@@ -266,6 +388,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)
{
@@ -297,12 +471,32 @@ uc_hostapd_iface_stop(uc_vm_t *vm, size_t nargs)
struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
int i;
switch (iface->state) {
case HAPD_IFACE_ENABLED:
case HAPD_IFACE_DISABLED:
break;
#ifdef CONFIG_ACS
case HAPD_IFACE_ACS:
acs_cleanup(iface);
iface->scan_cb = NULL;
/* fallthrough */
#endif
default:
hostapd_disable_iface(iface);
break;
}
if (iface->state != HAPD_IFACE_ENABLED)
hostapd_disable_iface(iface);
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *hapd = iface->bss[i];
hostapd_drv_stop_ap(hapd);
hapd->started = 0;
hapd->beacon_set_done = 0;
}
return NULL;
}
static uc_value_t *
@@ -311,67 +505,85 @@ uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs)
struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
uc_value_t *info = uc_fn_arg(0);
struct hostapd_config *conf;
bool changed = false;
uint64_t intval;
int i;
if (!iface)
return NULL;
if (!info)
if (!info) {
iface->freq = 0;
goto out;
}
if (ucv_type(info) != UC_OBJECT)
return NULL;
#define UPDATE_VAL(field, name) \
if ((intval = ucv_int64_get(ucv_object_get(info, name, NULL))) && \
!errno && intval != conf->field) do { \
conf->field = intval; \
changed = true; \
} while(0)
conf = iface->conf;
if ((intval = ucv_int64_get(ucv_object_get(info, "op_class", NULL))) && !errno)
conf->op_class = intval;
if ((intval = ucv_int64_get(ucv_object_get(info, "hw_mode", NULL))) && !errno)
conf->hw_mode = intval;
if ((intval = ucv_int64_get(ucv_object_get(info, "channel", NULL))) && !errno)
conf->channel = intval;
if ((intval = ucv_int64_get(ucv_object_get(info, "sec_channel", NULL))) && !errno)
conf->secondary_channel = intval;
#ifdef CONFIG_IEEE80211AC
if ((intval = ucv_int64_get(ucv_object_get(info, "center_seg0_idx", NULL))) && !errno) {
conf->vht_oper_centr_freq_seg0_idx = intval;
#ifdef CONFIG_IEEE80211AX
conf->he_oper_centr_freq_seg0_idx = intval;
#endif
#ifdef CONFIG_IEEE80211BE
conf->eht_oper_centr_freq_seg0_idx = intval;
#endif
}
if ((intval = ucv_int64_get(ucv_object_get(info, "center_seg1_idx", NULL))) && !errno) {
conf->vht_oper_centr_freq_seg1_idx = intval;
#ifdef CONFIG_IEEE80211AX
conf->he_oper_centr_freq_seg1_idx = intval;
#endif
#ifdef CONFIG_IEEE80211BE
conf->eht_oper_centr_freq_seg1_idx = intval;
#endif
}
UPDATE_VAL(op_class, "op_class");
UPDATE_VAL(hw_mode, "hw_mode");
UPDATE_VAL(channel, "channel");
UPDATE_VAL(secondary_channel, "sec_channel");
if (!changed &&
(iface->bss[0]->beacon_set_done ||
iface->state == HAPD_IFACE_DFS))
return ucv_boolean_new(true);
intval = ucv_int64_get(ucv_object_get(info, "center_seg0_idx", NULL));
if (!errno)
hostapd_set_oper_centr_freq_seg0_idx(conf, intval);
intval = ucv_int64_get(ucv_object_get(info, "center_seg1_idx", NULL));
if (!errno)
hostapd_set_oper_centr_freq_seg1_idx(conf, intval);
intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL));
if (!errno) {
conf->vht_oper_chwidth = intval;
#ifdef CONFIG_IEEE80211AX
conf->he_oper_chwidth = intval;
#endif
#ifdef CONFIG_IEEE80211BE
conf->eht_oper_chwidth = intval;
#endif
}
#endif
if (!errno)
hostapd_set_oper_chwidth(conf, intval);
intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL));
if (!errno)
iface->freq = intval;
else
iface->freq = 0;
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 (iface->state != HAPD_IFACE_ENABLED) {
hostapd_enable_iface(iface);
return ucv_boolean_new(true);
}
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *hapd = iface->bss[i];
int ret;
hapd->started = 1;
hapd->conf->start_disabled = 0;
hostapd_set_freq(hapd, conf->hw_mode, iface->freq,
conf->channel,
conf->enable_edmg,
@@ -436,6 +648,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[] = {
@@ -449,9 +710,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 },

View File

@@ -129,7 +129,10 @@ uc_value_t *uc_wpa_freq_info(uc_vm_t *vm, size_t nargs)
tmp_channel &= ~((8 << width) - 1);
center_idx = tmp_channel + center_ofs + (4 << width) - 1;
ucv_object_add(ret, "center_seg0_idx", ucv_int64_new(center_idx));
if (freq_val < 3000)
ucv_object_add(ret, "center_seg0_idx", ucv_int64_new(0));
else
ucv_object_add(ret, "center_seg0_idx", ucv_int64_new(center_idx));
center_idx = (center_idx - channel) * 5 + freq_val;
ucv_object_add(ret, "center_freq1", ucv_int64_new(center_idx));
@@ -295,9 +298,15 @@ uc_value_t *wpa_ucode_registry_get(uc_value_t *reg, int idx)
uc_value_t *wpa_ucode_registry_remove(uc_value_t *reg, int idx)
{
uc_value_t *val = wpa_ucode_registry_get(reg, idx);
void **dataptr;
if (val)
ucv_array_set(reg, idx - 1, NULL);
if (!val)
return NULL;
ucv_array_set(reg, idx - 1, NULL);
dataptr = ucv_resource_dataptr(val, NULL);
if (dataptr)
*dataptr = NULL;
return val;
}

View File

@@ -2,6 +2,7 @@
#include "utils/common.h"
#include "utils/ucode.h"
#include "drivers/driver.h"
#include "ap/hostapd.h"
#include "wpa_supplicant_i.h"
#include "wps_supplicant.h"
#include "bss.h"
@@ -211,12 +212,13 @@ uc_wpas_iface_status(uc_vm_t *vm, size_t nargs)
ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
if (ie && ie[1] >= 2) {
const struct ieee80211_ht_operation *ht_oper;
int sec;
ht_oper = (const void *) (ie + 2);
if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
sec = ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
sec_chan = 1;
else if (ht_oper->ht_param &
HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
sec_chan = -1;
}
@@ -224,6 +226,15 @@ uc_wpas_iface_status(uc_vm_t *vm, size_t nargs)
ucv_object_add(ret, "frequency", ucv_int64_new(bss->freq));
}
#ifdef CONFIG_MESH
if (wpa_s->ifmsh) {
struct hostapd_iface *ifmsh = wpa_s->ifmsh;
ucv_object_add(ret, "sec_chan_offset", ucv_int64_new(ifmsh->conf->secondary_channel));
ucv_object_add(ret, "frequency", ucv_int64_new(ifmsh->freq));
}
#endif
return ret;
}

View File

@@ -20,7 +20,7 @@ DEFAULT_PACKAGES += kmod-qca-nss-dp kmod-qca-ssdk swconfig \
kmod-usb-phy-ipq5018 kmod-usb-dwc3-qcom-internal \
kmod-ath11k-ahb ath11k-firmware-ipq5018 \
kmod-gpio-button-hotplug iwinfo \
qca-ssdk-shell kmod-qca-nss-drv-bridge-mgr \
qca-ssdk-shell \
uboot-envtools
$(eval $(call BuildTarget))

View File

@@ -0,0 +1,60 @@
From: Andy Ren <andy.ren@getcruise.com>
Date: Mon, 7 Nov 2022 09:42:42 -0800
Subject: [PATCH] net/core: Allow live renaming when an interface is up
Allow a network interface to be renamed when the interface
is up.
As described in the netconsole documentation [1], when netconsole is
used as a built-in, it will bring up the specified interface as soon as
possible. As a result, user space will not be able to rename the
interface since the kernel disallows renaming of interfaces that are
administratively up unless the 'IFF_LIVE_RENAME_OK' private flag was set
by the kernel.
The original solution [2] to this problem was to add a new parameter to
the netconsole configuration parameters that allows renaming of
the interface used by netconsole while it is administratively up.
However, during the discussion that followed, it became apparent that we
have no reason to keep the current restriction and instead we should
allow user space to rename interfaces regardless of their administrative
state:
1. The restriction was put in place over 20 years ago when renaming was
only possible via IOCTL and before rtnetlink started notifying user
space about such changes like it does today.
2. The 'IFF_LIVE_RENAME_OK' flag was added over 3 years ago in version
5.2 and no regressions were reported.
3. In-kernel listeners to 'NETDEV_CHANGENAME' do not seem to care about
the administrative state of interface.
Therefore, allow user space to rename running interfaces by removing the
restriction and the associated 'IFF_LIVE_RENAME_OK' flag. Help in
possible triage by emitting a message to the kernel log that an
interface was renamed while UP.
[1] https://www.kernel.org/doc/Documentation/networking/netconsole.rst
[2] https://lore.kernel.org/netdev/20221102002420.2613004-1-andy.ren@getcruise.com/
Signed-off-by: Andy Ren <andy.ren@getcruise.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
Index: linux-5.4.164-qsdk-26349818b464f8c7b52d59ce73579d9f3dd6bd5d/net/core/dev.c
===================================================================
--- linux-5.4.164-qsdk-26349818b464f8c7b52d59ce73579d9f3dd6bd5d.orig/net/core/dev.c
+++ linux-5.4.164-qsdk-26349818b464f8c7b52d59ce73579d9f3dd6bd5d/net/core/dev.c
@@ -1125,7 +1125,8 @@ int dev_change_name(struct net_device *d
}
if (oldname[0] && !strchr(oldname, '%'))
- netdev_info(dev, "renamed from %s\n", oldname);
+ netdev_info(dev, "renamed from %s%s\n", oldname,
+ dev->flags & IFF_UP ? " (while UP)" : "");
old_assign_type = dev->name_assign_type;
dev->name_assign_type = NET_NAME_RENAMED;

View File

@@ -20,7 +20,7 @@ DEFAULT_PACKAGES += kmod-qca-nss-dp kmod-qca-ssdk swconfig \
kmod-usb-phy-ipq807x kmod-usb-dwc3-qcom-internal \
kmod-ath11k-ahb ath11k-firmware-ipq60xx \
kmod-gpio-button-hotplug iwinfo \
qca-ssdk-shell kmod-qca-nss-drv-bridge-mgr \
qca-ssdk-shell \
uboot-envtools
$(eval $(call BuildTarget))

View File

@@ -0,0 +1,60 @@
From: Andy Ren <andy.ren@getcruise.com>
Date: Mon, 7 Nov 2022 09:42:42 -0800
Subject: [PATCH] net/core: Allow live renaming when an interface is up
Allow a network interface to be renamed when the interface
is up.
As described in the netconsole documentation [1], when netconsole is
used as a built-in, it will bring up the specified interface as soon as
possible. As a result, user space will not be able to rename the
interface since the kernel disallows renaming of interfaces that are
administratively up unless the 'IFF_LIVE_RENAME_OK' private flag was set
by the kernel.
The original solution [2] to this problem was to add a new parameter to
the netconsole configuration parameters that allows renaming of
the interface used by netconsole while it is administratively up.
However, during the discussion that followed, it became apparent that we
have no reason to keep the current restriction and instead we should
allow user space to rename interfaces regardless of their administrative
state:
1. The restriction was put in place over 20 years ago when renaming was
only possible via IOCTL and before rtnetlink started notifying user
space about such changes like it does today.
2. The 'IFF_LIVE_RENAME_OK' flag was added over 3 years ago in version
5.2 and no regressions were reported.
3. In-kernel listeners to 'NETDEV_CHANGENAME' do not seem to care about
the administrative state of interface.
Therefore, allow user space to rename running interfaces by removing the
restriction and the associated 'IFF_LIVE_RENAME_OK' flag. Help in
possible triage by emitting a message to the kernel log that an
interface was renamed while UP.
[1] https://www.kernel.org/doc/Documentation/networking/netconsole.rst
[2] https://lore.kernel.org/netdev/20221102002420.2613004-1-andy.ren@getcruise.com/
Signed-off-by: Andy Ren <andy.ren@getcruise.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
Index: linux-5.4.164-qsdk-26349818b464f8c7b52d59ce73579d9f3dd6bd5d/net/core/dev.c
===================================================================
--- linux-5.4.164-qsdk-26349818b464f8c7b52d59ce73579d9f3dd6bd5d.orig/net/core/dev.c
+++ linux-5.4.164-qsdk-26349818b464f8c7b52d59ce73579d9f3dd6bd5d/net/core/dev.c
@@ -1125,7 +1125,8 @@ int dev_change_name(struct net_device *d
}
if (oldname[0] && !strchr(oldname, '%'))
- netdev_info(dev, "renamed from %s\n", oldname);
+ netdev_info(dev, "renamed from %s%s\n", oldname,
+ dev->flags & IFF_UP ? " (while UP)" : "");
old_assign_type = dev->name_assign_type;
dev->name_assign_type = NET_NAME_RENAMED;

View File

@@ -20,7 +20,7 @@ DEFAULT_PACKAGES += kmod-qca-nss-dp kmod-qca-ssdk swconfig \
kmod-usb-phy-ipq807x kmod-usb-dwc3-qcom-internal \
kmod-ath11k-ahb ath11k-firmware-ipq807x \
kmod-gpio-button-hotplug iwinfo \
qca-ssdk-shell kmod-qca-nss-drv-bridge-mgr \
qca-ssdk-shell \
uboot-envtools
$(eval $(call BuildTarget))

View File

@@ -0,0 +1,67 @@
From: Andy Ren <andy.ren@getcruise.com>
Date: Mon, 7 Nov 2022 09:42:42 -0800
Subject: [PATCH] net/core: Allow live renaming when an interface is up
Allow a network interface to be renamed when the interface
is up.
As described in the netconsole documentation [1], when netconsole is
used as a built-in, it will bring up the specified interface as soon as
possible. As a result, user space will not be able to rename the
interface since the kernel disallows renaming of interfaces that are
administratively up unless the 'IFF_LIVE_RENAME_OK' private flag was set
by the kernel.
The original solution [2] to this problem was to add a new parameter to
the netconsole configuration parameters that allows renaming of
the interface used by netconsole while it is administratively up.
However, during the discussion that followed, it became apparent that we
have no reason to keep the current restriction and instead we should
allow user space to rename interfaces regardless of their administrative
state:
1. The restriction was put in place over 20 years ago when renaming was
only possible via IOCTL and before rtnetlink started notifying user
space about such changes like it does today.
2. The 'IFF_LIVE_RENAME_OK' flag was added over 3 years ago in version
5.2 and no regressions were reported.
3. In-kernel listeners to 'NETDEV_CHANGENAME' do not seem to care about
the administrative state of interface.
Therefore, allow user space to rename running interfaces by removing the
restriction and the associated 'IFF_LIVE_RENAME_OK' flag. Help in
possible triage by emitting a message to the kernel log that an
interface was renamed while UP.
[1] https://www.kernel.org/doc/Documentation/networking/netconsole.rst
[2] https://lore.kernel.org/netdev/20221102002420.2613004-1-andy.ren@getcruise.com/
Signed-off-by: Andy Ren <andy.ren@getcruise.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1152,8 +1152,6 @@ int dev_change_name(struct net_device *d
BUG_ON(!dev_net(dev));
net = dev_net(dev);
- if (dev->flags & IFF_UP)
- return -EBUSY;
write_seqcount_begin(&devnet_rename_seq);
@@ -1171,7 +1169,8 @@ int dev_change_name(struct net_device *d
}
if (oldname[0] && !strchr(oldname, '%'))
- netdev_info(dev, "renamed from %s\n", oldname);
+ netdev_info(dev, "renamed from %s%s\n", oldname,
+ dev->flags & IFF_UP ? " (while UP)" : "");
old_assign_type = dev->name_assign_type;
dev->name_assign_type = NET_NAME_RENAMED;

View File

@@ -0,0 +1,60 @@
From: Andy Ren <andy.ren@getcruise.com>
Date: Mon, 7 Nov 2022 09:42:42 -0800
Subject: [PATCH] net/core: Allow live renaming when an interface is up
Allow a network interface to be renamed when the interface
is up.
As described in the netconsole documentation [1], when netconsole is
used as a built-in, it will bring up the specified interface as soon as
possible. As a result, user space will not be able to rename the
interface since the kernel disallows renaming of interfaces that are
administratively up unless the 'IFF_LIVE_RENAME_OK' private flag was set
by the kernel.
The original solution [2] to this problem was to add a new parameter to
the netconsole configuration parameters that allows renaming of
the interface used by netconsole while it is administratively up.
However, during the discussion that followed, it became apparent that we
have no reason to keep the current restriction and instead we should
allow user space to rename interfaces regardless of their administrative
state:
1. The restriction was put in place over 20 years ago when renaming was
only possible via IOCTL and before rtnetlink started notifying user
space about such changes like it does today.
2. The 'IFF_LIVE_RENAME_OK' flag was added over 3 years ago in version
5.2 and no regressions were reported.
3. In-kernel listeners to 'NETDEV_CHANGENAME' do not seem to care about
the administrative state of interface.
Therefore, allow user space to rename running interfaces by removing the
restriction and the associated 'IFF_LIVE_RENAME_OK' flag. Help in
possible triage by emitting a message to the kernel log that an
interface was renamed while UP.
[1] https://www.kernel.org/doc/Documentation/networking/netconsole.rst
[2] https://lore.kernel.org/netdev/20221102002420.2613004-1-andy.ren@getcruise.com/
Signed-off-by: Andy Ren <andy.ren@getcruise.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
Index: linux-5.4.164-qsdk-26349818b464f8c7b52d59ce73579d9f3dd6bd5d/net/core/dev.c
===================================================================
--- linux-5.4.164-qsdk-26349818b464f8c7b52d59ce73579d9f3dd6bd5d.orig/net/core/dev.c
+++ linux-5.4.164-qsdk-26349818b464f8c7b52d59ce73579d9f3dd6bd5d/net/core/dev.c
@@ -1125,7 +1125,8 @@ int dev_change_name(struct net_device *d
}
if (oldname[0] && !strchr(oldname, '%'))
- netdev_info(dev, "renamed from %s\n", oldname);
+ netdev_info(dev, "renamed from %s%s\n", oldname,
+ dev->flags & IFF_UP ? " (while UP)" : "");
old_assign_type = dev->name_assign_type;
dev->name_assign_type = NET_NAME_RENAMED;

View File

@@ -488,6 +488,7 @@ ${channel:+channel=$channel}
${channel_list:+chanlist=$channel_list}
${hostapd_noscan:+noscan=1}
${tx_burst:+tx_queue_data2_burst=$tx_burst}
#num_global_macaddr=$num_global_macaddr
$base_cfg
EOF
@@ -528,6 +529,7 @@ mac80211_hostapd_setup_bss() {
cat >> /var/run/hostapd-$phy.conf <<EOF
$hostapd_cfg
bssid=$macaddr
${default_macaddr:+#default_macaddr}
${dtim_period:+dtim_period=$dtim_period}
${max_listen_int:+max_listen_interval=$max_listen_int}
EOF
@@ -542,57 +544,9 @@ mac80211_get_addr() {
mac80211_generate_mac() {
local phy="$1"
local multiple_bssid="$2"
local id="${macidx:-0}"
local ref="$(cat /sys/class/ieee80211/${phy}/macaddress)"
local mask="$(cat /sys/class/ieee80211/${phy}/address_mask)"
[ "$mask" = "00:00:00:00:00:00" -a "$multiple_bssid" != 1 ] && {
mask="ff:ff:ff:ff:ff:ff";
[ "$(wc -l < /sys/class/ieee80211/${phy}/addresses)" -gt $id ] && {
addr="$(mac80211_get_addr "$phy" "$id")"
[ -n "$addr" ] && {
echo "$addr"
return
}
}
}
local oIFS="$IFS"; IFS=":"; set -- $mask; IFS="$oIFS"
local mask1=$1
local mask6=$6
local oIFS="$IFS"; IFS=":"; set -- $ref; IFS="$oIFS"
[ "$multiple_bssid" -eq 1 ] && {
printf "02:%s:%s:%s:%s:%02x" $b1 $2 $3 $4 $5 $macidx
return
}
macidx=$(($id + 1))
local use_global=0
[ "$id" -gt 0 -a "$macidx" -le "$num_global_macaddr" ] && use_global=1
[ "$((0x$mask1))" -gt 0 -a "$use_global" -lt 1 ] && {
b1="0x$1"
[ "$id" -gt 0 ] && \
b1=$(($b1 ^ ((($id - !($b1 & 2)) << 2)) | 0x2))
printf "%02x:%s:%s:%s:%s:%s" $b1 $2 $3 $4 $5 $6
return
}
[ "$((0x$mask6))" -lt 255 -a "$use_global" -gt 0 ] && {
printf "%s:%s:%s:%s:%s:%02x" $1 $2 $3 $4 $5 $(( 0x$6 ^ $id ))
return
}
off2=$(( (0x$6 + $id) / 0x100 ))
printf "%s:%s:%s:%s:%02x:%02x" \
$1 $2 $3 $4 \
$(( (0x$5 + $off2) % 0x100 )) \
$(( (0x$6 + $id) % 0x100 ))
wdev_tool "$phy" get_macaddr id=$id num_global=$num_global_macaddr mbssid=$multiple_bssid
}
find_phy() {
@@ -626,11 +580,14 @@ mac80211_prepare_vif() {
set_default powersave 0
json_add_string _ifname "$ifname"
default_macaddr=
[ -n "$macaddr" ] || {
macaddr="$(mac80211_generate_mac $phy $multiple_bssid)"
macaddr="$(mac80211_generate_mac $phy)"
macidx="$(($macidx + 1))"
default_macaddr=1
}
json_add_string _macaddr "$macaddr"
json_add_string _default_macaddr "$default_macaddr"
json_select ..
@@ -754,7 +711,7 @@ mac80211_setup_adhoc() {
json_add_object "$ifname"
json_add_string mode adhoc
json_add_string macaddr "$macaddr"
[ -n "$default_macaddr" ] || json_add_string macaddr "$macaddr"
json_add_string ssid "$ssid"
json_add_string freq "$freq"
json_add_string htmode "$iw_htmode"
@@ -780,7 +737,7 @@ mac80211_setup_mesh() {
json_add_object "$ifname"
json_add_string mode mesh
json_add_string macaddr "$macaddr"
[ -n "$default_macaddr" ] || json_add_string macaddr "$macaddr"
json_add_string ssid "$ssid"
json_add_string freq "$freq"
json_add_string htmode "$iw_htmode"
@@ -831,7 +788,6 @@ wpa_supplicant_init_config() {
wpa_supplicant_add_interface() {
local ifname="$1"
local mode="$2"
local hostapd_ctrl="$3"
local prev
_wpa_supplicant_common "$ifname"
@@ -843,9 +799,8 @@ wpa_supplicant_add_interface() {
json_add_string iface "$ifname"
json_add_string mode "$mode"
json_add_string config "$_config"
json_add_string macaddr "$macaddr"
[ -n "$default_macaddr" ] || json_add_string macaddr "$macaddr"
[ -n "$network_bridge" ] && json_add_string bridge "$network_bridge"
[ -n "$hostapd_ctrl" ] && json_add_string hostapd_ctrl "$hostapd_ctrl"
[ -n "$wds" ] && json_add_boolean 4addr "$wds"
json_add_boolean powersave "$powersave"
[ "$mode" = "mesh" ] && mac80211_add_mesh_params
@@ -920,7 +875,7 @@ mac80211_setup_supplicant() {
wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan"
fi
wpa_supplicant_add_interface "$ifname" "$mode" "$hostapd_ctrl"
wpa_supplicant_add_interface "$ifname" "$mode"
return 0
}
@@ -932,6 +887,7 @@ mac80211_setup_vif() {
json_select config
json_get_var ifname _ifname
json_get_var macaddr _macaddr
json_get_var default_macaddr _default_macaddr
json_get_vars mode wds powersave
set_default powersave 0
@@ -1014,7 +970,7 @@ mac80211_reset_config() {
hostapd_conf_file="/var/run/hostapd-$phy.conf"
ubus call hostapd config_set '{ "phy": "'"$phy"'", "config": "", "prev_config": "'"$hostapd_conf_file"'" }' > /dev/null
ubus call wpa_supplicant config_set '{ "phy": "'"$phy"'", "config": [] }' > /dev/null
wdev_tool "$phy" '{}'
wdev_tool "$phy" set_config '{}'
}
drv_mac80211_setup() {
@@ -1116,7 +1072,7 @@ drv_mac80211_setup() {
mac80211_prepare_iw_htmode
active_ifnames=
for_each_interface "ap sta adhoc mesh monitor" mac80211_prepare_vif ${multiple_bssid}
for_each_interface "ap sta adhoc mesh monitor" mac80211_prepare_vif
for_each_interface "ap sta adhoc mesh monitor" mac80211_setup_vif
[ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_set_config "$phy"
@@ -1125,7 +1081,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

View File

@@ -0,0 +1,148 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 14 Sep 2023 13:17:16 +0200
Subject: [PATCH] cfg80211: allow grace period for DFS available after beacon
shutdown
Fixes reconfiguring an AP on a DFS channel in non-ETSI regdomain
Fixes: b35a51c7dd25 ("cfg80211: Make pre-CAC results valid only for ETSI domain")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -162,6 +162,8 @@ enum ieee80211_channel_flags {
* @dfs_state: current state of this channel. Only relevant if radar is required
* on this channel.
* @dfs_state_entered: timestamp (jiffies) when the dfs state was entered.
+ * @dfs_state_last_available: timestamp (jiffies) of the last time when the
+ * channel was available.
* @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels.
*/
struct ieee80211_channel {
@@ -178,6 +180,7 @@ struct ieee80211_channel {
int orig_mag, orig_mpwr;
enum nl80211_dfs_state dfs_state;
unsigned long dfs_state_entered;
+ unsigned long dfs_state_last_available;
unsigned int dfs_cac_ms;
};
--- a/net/wireless/ap.c
+++ b/net/wireless/ap.c
@@ -25,6 +25,8 @@ int __cfg80211_stop_ap(struct cfg80211_r
if (!wdev->beacon_interval)
return -ENOENT;
+ cfg80211_update_last_available(wdev->wiphy, &wdev->chandef);
+
err = rdev_stop_ap(rdev, dev);
if (!err) {
wdev->conn_owner_nlportid = 0;
@@ -35,9 +37,6 @@ int __cfg80211_stop_ap(struct cfg80211_r
if (notify)
nl80211_send_ap_stopped(wdev);
- /* Should we apply the grace period during beaconing interface
- * shutdown also?
- */
cfg80211_sched_dfs_chan_update(rdev);
}
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -411,6 +411,8 @@ static void cfg80211_set_chans_dfs_state
c->dfs_state = dfs_state;
c->dfs_state_entered = jiffies;
+ if (dfs_state == NL80211_DFS_AVAILABLE)
+ c->dfs_state_last_available = jiffies;
}
}
@@ -769,6 +771,49 @@ static bool cfg80211_get_chans_dfs_avail
return true;
}
+static void
+__cfg80211_update_last_available(struct wiphy *wiphy,
+ u32 center_freq,
+ u32 bandwidth)
+{
+ struct ieee80211_channel *c;
+ u32 freq, start_freq, end_freq;
+
+ start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
+ end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
+
+ /*
+ * Check entire range of channels for the bandwidth.
+ * If any channel in between is disabled or has not
+ * had gone through CAC return false
+ */
+ for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
+ c = ieee80211_get_channel_khz(wiphy, freq);
+ if (!c)
+ return;
+
+ c->dfs_state_last_available = jiffies;
+ }
+}
+
+void cfg80211_update_last_available(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef)
+{
+ int width;
+
+ width = cfg80211_chandef_get_width(chandef);
+ if (width < 0)
+ return;
+
+ __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq1),
+ width);
+ if (chandef->width != NL80211_CHAN_WIDTH_80P80)
+ return;
+
+ __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq2),
+ width);
+}
+
static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef)
{
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -483,6 +483,8 @@ void cfg80211_set_dfs_state(struct wiphy
enum nl80211_dfs_state dfs_state);
void cfg80211_dfs_channels_update_work(struct work_struct *work);
+void cfg80211_update_last_available(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef);
unsigned int
cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -858,6 +858,8 @@ void cfg80211_dfs_channels_update_work(s
if (c->dfs_state == NL80211_DFS_UNAVAILABLE) {
time_dfs_update = IEEE80211_DFS_MIN_NOP_TIME_MS;
radar_event = NL80211_RADAR_NOP_FINISHED;
+ timeout = c->dfs_state_entered +
+ msecs_to_jiffies(time_dfs_update);
} else {
if (regulatory_pre_cac_allowed(wiphy) ||
cfg80211_any_wiphy_oper_chan(wiphy, c))
@@ -865,11 +867,10 @@ void cfg80211_dfs_channels_update_work(s
time_dfs_update = REG_PRE_CAC_EXPIRY_GRACE_MS;
radar_event = NL80211_RADAR_PRE_CAC_EXPIRED;
+ timeout = c->dfs_state_last_available +
+ msecs_to_jiffies(time_dfs_update);
}
- timeout = c->dfs_state_entered +
- msecs_to_jiffies(time_dfs_update);
-
if (time_after_eq(jiffies, timeout)) {
c->dfs_state = NL80211_DFS_USABLE;
c->dfs_state_entered = jiffies;

View File

@@ -771,10 +771,10 @@ hostapd_set_bss_options() {
wps_possible=1
# Here we make the assumption that if we're in open mode
# with WPS enabled, we got to be in unconfigured state.
vlan_possible=1
wps_not_configured=1
[ "$macfilter" = radius ] && {
append_radius_server
vlan_possible=1
}
;;
psk|sae|psk-sae)

View File

@@ -34,7 +34,7 @@ boot() {
case "$(board_name)" in
cig,wf660a)
mmc_dev=$(echo $(find_mmc_part "0:ETHPHYFW") | sed 's/^.\{5\}//')
[ -n $mmc_dev ] && mount -t ext4 /dev/$mmc_dev /certificates
[ -n "$mmc_dev" ] && mount -t ext4 /dev/$mmc_dev /certificates
;;
esac
@@ -75,7 +75,10 @@ boot() {
PART_NAME=rootfs_1
fi
;;
yuncore,ax840)
cig,wf186w|\
cig,wf186h|\
yuncore,ax840|\
yuncore,fap655)
PART_NAME=rootfs_1
;;
*)

View File

@@ -4,10 +4,10 @@ PKG_NAME:=ucentral-client
PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-client.git
PKG_MIRROR_HASH:=208bc53ea0194a59ff4dc78c32033a393017b0b883aa4d7741595b61ad3a4fd3
PKG_MIRROR_HASH:=49d19d1cddb538f233a7c1d588b5c765929a8fe28a1524d0455c4b516dcd0310
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2022-06-22
PKG_SOURCE_VERSION:=d898a7afb595d6c2350d38d027bf142e72060662
PKG_SOURCE_VERSION:=3bbcd36c6111e08df6c8f13e0079826ec417cc85
PKG_LICENSE:=BSD-3-Clause
PKG_MAINTAINER:=John Crispin <john@phrozen.org>

View File

@@ -231,14 +231,27 @@ function dhcp_subscriber_remove_cb(remove) {
printf('dhcp remove: %.J\n', remove);
}
function match_dhcp_relay_option82(format, hapd) {
switch(format) {
case 'ap-mac':
uci.load('ucentral');
let ucentral = uci.get_all('ucentral', 'config');
return ucentral.serial;
case 'ssid':
return hapd.config.ssid;
case 'vlan-id':
return hapd.config.vlan_id;
}
}
function dhcp_relay_subscriber_notify_cb(notify) {
let ifname = split(notify.data.info.device, '-v');
let hapd = hostapd[ifname[0]];
let vlan = ifname[1];
if (hapd) {
vlan ??= hapd.config.vlan_id;
let circuit_id = `${vlan}`;
let remote_id = hapd.bssid;
let circuit_id = match_dhcp_relay_option82(relay['vlan' + vlan]?.circuit_id, hapd);
let remote_id = match_dhcp_relay_option82(relay['vlan' + vlan]?.remote_id, hapd);
return {
address: relay['vlan' + vlan]?.server,
options: [

View File

@@ -4,10 +4,10 @@ PKG_NAME:=ucentral-schema
PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-schema.git
PKG_MIRROR_HASH:=6da4c8a82c5393d54bfe1a91479730cc126e7de1cf1565a0274d600759e668e0
PKG_MIRROR_HASH:=62571bb529e8b350bafdc63db3d7e02effa3edf5e5f19bfe8ced96c7cfb08b0e
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2022-05-29
PKG_SOURCE_VERSION:=708b1de986b63c35e4f5e79a3183ffb4a36f40a1
PKG_SOURCE_VERSION:=e99eaf9bdbbe68639b4632d7fec171d89c379dc5
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=BSD-3-Clause

View File

@@ -8,6 +8,7 @@ board=$(board_name)
case "$board" in
cig,wf186w|\
cig,wf186h|\
cig,wf194c4|\
cig,wf194c|\
cig,wf610d|\

View File

@@ -1,5 +1,15 @@
#!/bin/sh
. /lib/functions.sh
case "$(board_name)" in
"cig,wf186w")
uci del event.config.wan_port
uci add_list event.config.wan_port=eth0
exit 0
;;
esac
wan=$(cat /etc/board.json | jsonfilter -e '@.network.wan.device')
[ -z "$wan" ] && eval $(jsonfilter -i /etc/board.json -e 'wan=@.network.wan.ports.*')
for w in $wan; do

View File

@@ -68,7 +68,7 @@ global.start = function() {
global.uci = require('uci').cursor();
global.ubus.conn = require('ubus').connect();
for (let module in [ 'config', 'event', 'phy', 'local', 'station', 'command', 'policy' ]) {
for (let module in [ 'config', 'event', 'phy', 'neighbor', 'local', 'station', 'command', 'policy' ]) {
printf('loading ' + module + '\n');
global[module] = require(module);
if (exists(global[module], 'init'))

View File

@@ -1,64 +1,75 @@
function result(error, text, data) {
function result(error, event, text, data) {
let res = {
error: error,
text: text || 'unknown',
...(data ? { data } : {}),
...(data ? data : {}),
};
if (event)
global.event.send('rrm.bss.command', res);
return res;
}
const actions = {
// ubus call usteer2 command '{"action": "kick", "addr": "1c:57:dc:37:3c:b1", "params": {"reason": 5, "ban_time": 30}}'
// ubus call usteer2 command '{"action": "kick", "addr": "1c:57:dc:37:3c:b1", "reason": 5, "ban_time": 30 }'
kick: function(msg) {
if (global.station.kick(msg))
return result(1, 'station ' + msg.mac + ' is unknown');
if (!global.station.kick(msg))
return result(1, msg.event, 'station ' + msg.addr + ' is unknown', { action: 'kick', addr: msg.addr });
return result(0, 'station ' + msg.mac + ' was kicked');
return result(0, 0, 'station ' + msg.addr + ' was kicked', { action: 'kick', addr: msg.addr });
},
// ubus call usteer2 command '{"action": "beacon_request", "addr": "4e:7f:3e:2c:8a:68", "params": {"channel": 36}}'
// ubus call usteer2 command '{"action": "beacon_request", "addr": "4e:7f:3e:2c:8a:68", "params": {"ssid": "Cockney"}}'
// ubus call usteer2 command '{"action": "beacon_request", "addr": "4e:7f:3e:2c:8a:68", "params": "channel": 1}'
// ubus call usteer2 command '{"action": "beacon_request", "addr": "4e:7f:3e:2c:8a:68", "params": "ssid": "Pluto" }'
// ubus call usteer2 get_beacon_request '{"addr": "4e:7f:3e:2c:8a:68"}'
beacon_request: function(msg) {
if (!global.station.beacon_request(msg))
return result(1, 'station ' + msg.addr + ' is unknown');
return result(1, msg.event, 'station ' + msg.addr + ' is unknown', { action: 'beacon_request', addr: msg.addr });
return result(0, 'station ' + msg.addr + ' beacon-request sent');
return result(0, 0, 'station ' + msg.addr + ' beacon-request sent', { action: 'beacon_request', addr: msg.addr });
},
// ubus call usteer2 command '{"action": "channel_switch", "addr": "34:eF:b6:aF:48:b1", "params": {"channel": 4, "band": "2G"}}'
// ubus call usteer2 command '{"action": "channel_switch", "bssid": "34:eF:b6:aF:48:b1", "channel": 4 }'
channel_switch: function(msg) {
if (!global.local.switch_chan(msg))
return result(1, 'BSS ' + msg.bssid + ' failed to trigger channel switch');
return result(1, msg.event, 'BSS ' + msg.bssid + ' failed to trigger channel switch', { action: 'channel_switch', bssid: msg.bssid });
return result(0, 'BSS ' + msg.bssid + ' triggered channel switch');
return result(0, msg.event, 'BSS ' + msg.bssid + ' triggered channel switch', { action: 'channel_switch', bssid: msg.bssid });
},
// ubus call usteer2 command '{"action": "tx_power", "phy": "platform/soc/c000000.wifi+1", "params": {"level": 20}}'
// ubus call usteer2 command '{"action": "tx_power", "bssid": "34:eF:b6:aF:48:b1", "level": 20}'
tx_power: function(msg) {
if (!global.phy.txpower(msg))
return result(1, 'PHY ' + msg,phy + ' failed to set TX power');
return result(0, 'PHY ' + msg.phy + ' changed TX power');
return result(1, msg.event, 'BSS ' + msg.bssid + ' failed to set TX power', { action: 'tx_power', bssid: msg.bssid });
let level = global.local.txpower(msg.bssid) / 100;
return result(0, msg.event, 'BSS ' + msg.bssid + ' changed TX power', { action: 'tx_power', bssid: msg.bssid, level });
},
// ubus call usteer2 command '{"action": "bss_transition", "addr": "4e:7f:3e:2c:8a:68", "params": { "neighbors": ["34:ef:b6:af:48:b1"]}}'
// ubus call usteer2 command '{"action": "bss_transition", "addr": "4e:7f:3e:2c:8a:68", "neighbors": ["34:ef:b6:af:48:b1"] }'
bss_transition: function(msg) {
if (!global.station.bss_transition(msg))
return result(1, 'BSS transition ' + msg.addr + ' failed to trigger');
return result(1, msg.event, 'BSS transition ' + msg.addr + ' failed to trigger', { action: 'bss_transition', addr: msg.addr });
return result(0, 'BSS transition ' + msg.addr + ' triggered');
return result(0, 0, 'BSS transition ' + msg.addr + ' triggered');
},
// ubus call usteer2 command '{"action": "neighbors", "neighbors": [ [ "00:11:22:33:44:55", "OpenWifi", "34efb6af48b1af4900005301070603010300" ], [ "aa:bb:cc:dd:ee:ff", "OpenWifi2", "34efb6af48b1af4900005301070603010300" ] ] }'
neighbors: function(msg) {
if (!global.neighbor.remote(msg))
return result(1, msg.event, 'Failed to set neighbors', { action: 'neighbors' });
return result(0, 0, 'applied neighbor reports');
},
};
return {
handle: function(msg) {
if (!actions[msg.action])
return result(1, 'unknown action ' + msg.action);
return result(1, msg.event, 'unknown action ' + msg.action);
try {
return actions[msg.action](msg);
} catch(e) {
return result(1, 'action ' + msg.action + ' failed to execute');
printf('%.J\n', e.stacktrace[0].context);
return result(1, msg.event, 'action ' + msg.action + ' failed to execute');
}
},
};

View File

@@ -6,7 +6,16 @@ let state = {};
let hapd = {};
let handlers = {};
function channel_to_freq(band, channel) {
function channel_to_freq(cur_freq, channel) {
let band;
if (cur_freq <= 2484)
band = '2G';
else if (cur_freq <= 5885)
band = '5G';
else
band = '6G';
if (band == '2G' && channel >= 1 && channel <= 13)
return 2407 + channel * 5;
else if (band == '2G' && channel == 14)
@@ -58,23 +67,6 @@ function hapd_update() {
return 5000;
}
function hapd_nr_set(iface) {
let list = [];
for (let k, v in hapd) {
if (k == iface || v.ssid != hapd[iface].ssid)
continue;
push(list, v.rrm_nr);
global.ubus.conn.call('hostapd.' + iface, 'rrm_nr_set', { list });
}
}
function hapd_nr_update(ssid) {
for (let k, v in hapd)
if (v.ssid == ssid)
hapd_nr_set(k);
}
function hapd_subunsub(path, sub) {
/* check if this is a hostapd instance */
let name = split(path, '.');
@@ -88,6 +80,7 @@ function hapd_subunsub(path, sub) {
/* the hostapd instance disappeared */
if (!sub) {
global.event.send('rrm.bss.del', { bssid: hapd[name] });
global.neighbor.local_del(name);
delete hapd[name];
delete state[name];
return;
@@ -122,14 +115,15 @@ function hapd_subunsub(path, sub) {
/* ask hostapd for the local neighbourhood report data */
let rrm = global.ubus.conn.call(path, 'rrm_nr_get_own');
if (rrm && rrm.value)
if (rrm && rrm.value) {
hapd[name].rrm_nr = rrm.value;
global.neighbor.local_add(name, rrm.value);
}
global.neighbor.update();
/* trigger an initial channel survey */
channel_survey(name);
/* update the neighborhood reports */
hapd_nr_update(hapd[name].ssid);
//channel_survey(name);
/* send an event */
global.event.send('rrm.bss.add', {
@@ -137,7 +131,8 @@ function hapd_subunsub(path, sub) {
ssid: hapd[name].ssid,
freq: hapd[name].freq,
channel: hapd[name].channel,
op_class: hapd[name].op_class
op_class: hapd[name].op_class,
rrm_nr: hapd[name].rrm_nr,
});
}
@@ -169,6 +164,10 @@ function ucentral_handle_event(req) {
printf('%.J\n', req);
}
function channel_switch_handler(type, data) {
global.event.send('rrm.bss.channel-switch', { bssid: data.bssid, freq: data.freq });
}
return {
status: function() {
return hapd;
@@ -193,7 +192,8 @@ return {
ucentral_subunsub(true);
}
uloop_timeout(hapd_update, 5000);
// uloop_timeout(hapd_update, 5000);
global.local.register_handler('channel-switch', channel_switch_handler);
},
register_handler: function(event, handler) {
@@ -203,16 +203,36 @@ return {
},
switch_chan: function(msg) {
if (!msg.addr || !msg.params?.band || !msg.params?.channel)
if (!msg.bssid || !msg.channel)
return false;
for (let bss, v in hapd) {
if (v.bssid != lc(msg.addr))
if (v.bssid != lc(msg.bssid))
continue;
return global.ubus.conn.call('hostapd.' + bss, 'switch_chan', {
freq: channel_to_freq(msg.param.band, mag.param.channel),
freq: channel_to_freq(v.freq, msg.channel),
bcn_count: 10
}) == null;
}
return false;
},
bssid_to_phy: function(bssid) {
for (let bss, v in hapd) {
if (v.bssid != lc(bssid))
continue;
let iface = global.nl80211.request(global.nl80211.const.NL80211_CMD_GET_INTERFACE, 0, { dev: bss });
return iface.wiphy;
}
return -1;
},
txpower: function(bssid) {
for (let bss, v in hapd) {
if (v.bssid != lc(bssid))
continue;
let iface = global.nl80211.request(global.nl80211.const.NL80211_CMD_GET_INTERFACE, 0, { dev: bss });
return iface.wiphy_tx_power_level;
}
return 0;
},
};

View File

@@ -0,0 +1,53 @@
let local = { };
let remote = [ ];
return {
init: function() {
},
local_add: function(dev, data) {
local[dev] = data;
},
local_del: function(dev) {
delete local[dev];
},
get: function(dev) {
let result = [];
for (let k, v in remote) {
if (local[dev][1] != v[1])
continue;
push(result, v);
}
for (let k, v in local) {
if (k == dev || local[dev][1] != v[1])
continue;
push(result, v);
}
return result;
},
update: function() {
for (let dev in local) {
let list = this.get(dev);
global.ubus.conn.call('hostapd.' + dev, 'rrm_nr_set', { list });
}
},
remote: function(msg) {
for (let neighbor in msg.neighbors) {
if (type(neighbor) != 'array' || length(neighbor) != 3)
return false;
for (let i = 0; i < 3; i++)
if (type(neighbor[i]) != 'string')
return false;
}
remote = msg.neighbors;
this.update();
return true;
}
};

View File

@@ -147,12 +147,12 @@ return {
},
txpower: function(msg) {
if (!msg.phy || !msg.params?.level)
if (!msg.bssid || !msg.level)
return false;
if (!this.phys[msg.phy])
return false;
global.nl80211.request(global.nl80211.const.NL80211_CMD_SET_WIPHY, 0, { wiphy: this.phys[msg.phy].index, wiphy_tx_power_setting: 2, wiphy_tx_power_level: msg.params.level * 100});
let wiphy = global.local.bssid_to_phy(msg.bssid);
if (wiphy < 0)
return false;
global.nl80211.request(global.nl80211.const.NL80211_CMD_SET_WIPHY, 0, { wiphy, wiphy_tx_power_setting: 2, wiphy_tx_power_level: msg.level * 100});
return true;
},
};

View File

@@ -164,7 +164,7 @@ return {
},
beacon_request: function(msg) {
if (!msg.addr || (!msg.params?.channel && !msg.params?.ssid))
if (!msg.addr || (!msg.channel && !msg.ssid))
return false;
let station = stations[msg.addr];
@@ -185,20 +185,20 @@ return {
let payload = {
addr: msg.addr,
mode: msg.params?.mode || 1,
op_class: msg.params?.op_class || 128,
duration: msg.params?.duration || 100,
op_class: msg.op_class || 128,
duration: msg.duration || 100,
};
if (msg.params.channel)
payload.channel = msg.params.channel;
if (msg.channel)
payload.channel = msg.channel;
else
payload.ssid = msg.params.ssid;
payload.ssid = msg.ssid;
global.ubus.conn.call(`hostapd.${station.device}`, 'rrm_beacon_req', payload);
return true;
},
kick: function(msg) {
if (!msg.addr || !msg.params?.ban_time || !msg.params?.reason)
if (!msg.addr || !msg.ban_time || !msg.reason)
return false;
if (!exists(stations, msg.addr))
@@ -206,9 +206,9 @@ return {
let payload = {
addr: msg.addr,
reason: msg.params.reason,
reason: msg.reason,
deauth: 1,
ban_time: msg.params.ban_time
ban_time: msg.ban_time
};
/* tell hostapd to kick a station via ubus */
@@ -223,17 +223,16 @@ return {
return stations;
},
// ubus call usteer2 command '{"action": "bss_transition", "addr": "4e:7f:3e:2c:8a:68", "params": { "neighbors": ["36:ef:b6:af:48:b1"]}}'
bss_transition: function(msg) {
if (!msg.addr || !msg.params?.neighbors)
if (!msg.addr || !msg.neighbors)
return false;
if (!stations[msg.addr])
return false;
let neighbors = [];
for (let i = 0; i < 5; i++)
if (msg.params?.neighbors[i])
push(neighbors, replace(msg.params?.neighbors[i], ':', ''));
if (msg.neighbors[i])
push(neighbors, replace(msg.neighbors[i], ':', ''));
let ret = global.ubus.conn.call(`hostapd.${stations[msg.addr].device}`, 'wnm_disassoc_imminent', {
addr: msg.addr, duration: 20, abridged: 1, neighbors }) == null;

View File

@@ -26,6 +26,7 @@ endef
ALLWIFIBOARDS:= \
cig-wf188 \
cig-wf186w \
cig-wf186h \
cig-wf660a \
cig-wf194c \
cig-wf194c4 \
@@ -348,6 +349,7 @@ endef
$(eval $(call generate-ath11k-wifi-package,cig-wf188,Cigtech WF188))
$(eval $(call generate-ath11k-wifi-package,cig-wf186w,Cigtech WF186w))
$(eval $(call generate-ath11k-wifi-package,cig-wf186h,Cigtech WF186h))
$(eval $(call generate-ath11k-wifi-package,cig-wf660a,Cigtech WF660a))
$(eval $(call generate-ath11k-wifi-package,cig-wf194c,Cigtech WF194c))
$(eval $(call generate-ath11k-wifi-package,cig-wf194c4,Cigtech WF194c4))

Binary file not shown.

Binary file not shown.

View File

@@ -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;
@@ -150,7 +300,7 @@ function is_equal(val1, val2) {
if (!is_equal(val1[key], val2[key]))
return false;
for (let key in val2)
if (!val1[key])
if (val1[key] == null)
return false;
return true;
} else {
@@ -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 };

View File

@@ -725,8 +725,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_server" ] && {
append bss_conf "acct_server_addr=$acct_server" "$N"
@@ -772,6 +771,7 @@ hostapd_set_bss_options() {
# Here we make the assumption that if we're in open mode
# with WPS enabled, we got to be in unconfigured state.
wps_not_configured=1
vlan_possible=1
[ "$macfilter" = radius ] && {
append_radius_server
vlan_possible=1

View File

@@ -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();
@@ -31,7 +31,7 @@ function iface_remove(cfg)
wdev_remove(bss.ifname);
}
function iface_gen_config(phy, config)
function iface_gen_config(phy, config, start_disabled)
{
let str = `data:
${join("\n", config.radio.data)}
@@ -41,18 +41,92 @@ 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 += `
start_disabled=1
`;
}
return str;
}
function iface_restart(phy, config, old_config)
function iface_freq_info(iface, config, params)
{
let freq = params.frequency;
if (!freq)
return null;
let sec_offset = params.sec_chan_offset;
if (sec_offset != -1 && sec_offset != 1)
sec_offset = 0;
let width = 0;
for (let line in config.radio.data) {
if (!sec_offset && match(line, /^ht_capab=.*HT40/)) {
sec_offset = null; // auto-detect
continue;
}
let val = match(line, /^(vht_oper_chwidth|he_oper_chwidth)=(\d+)/);
if (!val)
continue;
val = int(val[2]);
if (val > width)
width = val;
}
if (freq < 4000)
width = 0;
return hostapd.freq_info(freq, sec_offset, width);
}
function iface_add(phy, config, phy_status)
{
let config_inline = iface_gen_config(phy, config, !!phy_status);
let bss = config.bss[0];
let ret = hostapd.add_iface(`bss_config=${bss.ifname}:${config_inline}`);
if (ret < 0)
return false;
if (!phy_status)
return true;
let iface = hostapd.interfaces[bss.ifname];
if (!iface)
return false;
let freq_info = iface_freq_info(iface, config, phy_status);
return iface.start(freq_info) >= 0;
}
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);
@@ -61,15 +135,29 @@ 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)
hostapd.printf(`Failed to create ${bss.ifname} on phy ${phy}: ${err}`);
let config_inline = iface_gen_config(phy, config);
let ubus = hostapd.data.ubus;
let phy_status = ubus.call("wpa_supplicant", "phy_status", { phy: phy });
if (phy_status && phy_status.state == "COMPLETED") {
if (iface_add(phy, config, phy_status))
return;
hostapd.printf(`Failed to bring up phy ${phy} ifname=${bss.ifname} with supplicant provided frequency`);
}
ubus.call("wpa_supplicant", "phy_set_state", { phy: phy, stop: true });
if (hostapd.add_iface(`bss_config=${bss.ifname}:${config_inline}`) < 0)
if (!iface_add(phy, config))
hostapd.printf(`hostapd.add_iface failed for phy ${phy} ifname=${bss.ifname}`);
ubus.call("wpa_supplicant", "phy_set_state", { phy: phy, stop: false });
}
@@ -111,8 +199,65 @@ 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;
delete new_cfg.hash.vlan_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;
@@ -122,82 +267,230 @@ 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(`Could not update config data files for bss ${ifname}`);
return false;
} else {
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`);
if (bss.set_config(config_inline, i) < 0) {
hostapd.printf(`Failed to set config for bss ${ifname}`);
return false;
}
}
@@ -205,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];
@@ -214,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)
@@ -268,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]);
@@ -294,28 +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: {
@@ -326,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;
@@ -344,34 +676,10 @@ let main_obj = {
return 0;
}
let freq = req.args.frequency;
if (!freq)
if (!req.args.frequency)
return libubus.STATUS_INVALID_ARGUMENT;
let sec_offset = req.args.sec_chan_offset;
if (sec_offset != -1 && sec_offset != 1)
sec_offset = 0;
let width = 0;
for (let line in config.radio.data) {
if (!sec_offset && match(line, /^ht_capab=.*HT40/)) {
sec_offset = null; // auto-detect
continue;
}
let val = match(line, /^(vht_oper_chwidth|he_oper_chwidth)=(\d+)/);
if (!val)
continue;
val = int(val[2]);
if (val > width)
width = val;
}
if (freq < 4000)
width = 0;
let freq_info = hostapd.freq_info(freq, sec_offset, width);
let freq_info = iface_freq_info(iface, config, req.args);
if (!freq_info)
return libubus.STATUS_UNKNOWN_ERROR;
@@ -380,14 +688,34 @@ let main_obj = {
freq_info.csa_count = req.args.csa_count ?? 10;
ret = iface.switch_channel(freq_info);
} else {
iface.stop();
ret = iface.start(freq_info);
}
if (!ret)
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: {
@@ -395,7 +723,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;
@@ -403,34 +731,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;
@@ -440,19 +763,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;
}
})
},
};

View File

@@ -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)
@@ -47,7 +55,7 @@ function iface_start(wdev)
system(cmd);
} else if (wdev.mode == "mesh") {
let cmd = [ "iw", "dev", ifname, "mesh", "join", wdev.ssid, "freq", wdev.freq, wdev.htmode ];
for (let key in [ "beacon-interval", "mcast-rate" ])
for (let key in [ "mcast-rate", "beacon-interval" ])
if (wdev[key])
push(cmd, key, wdev[key]);
system(cmd);
@@ -114,43 +122,86 @@ function add_existing(phy, config)
}
}
function usage()
{
warn(`Usage: ${basename(sourcepath())} <phy> <command> [<arguments>]
let statefile = `/var/run/wdev-${phy}.json`;
for (let dev in ARGV)
keep_devices[dev] = true;
if (!phy || !new_config) {
warn(`Usage: ${basename(sourcepath())} <phy> <config> [<device]...]\n`);
Commands:
set_config <config> [<device]...] - set phy configuration
get_macaddr <id> - get phy MAC address for vif index <id>
`);
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);

View File

@@ -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);
@@ -43,6 +51,11 @@ function iface_cb(new_if, old_if)
return;
}
if (new_if && old_if)
wpas.printf(`Update configuration for interface ${old_if.config.iface}`);
else if (old_if)
wpas.printf(`Remove interface ${old_if.config.iface}`);
if (old_if)
iface_stop(old_if);
}
@@ -73,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 = {
@@ -106,6 +132,55 @@ 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: ""
},
call: function(req) {
if (!req.args.phy)
return libubus.STATUS_INVALID_ARGUMENT;
let phy = wpas.data.config[req.args.phy];
if (!phy)
return libubus.STATUS_NOT_FOUND;
for (let ifname in phy.data) {
try {
let iface = wpas.interfaces[ifname];
if (!iface)
continue;
let status = iface.status();
if (!status)
continue;
if (status.state == "INTERFACE_DISABLED")
continue;
status.ifname = ifname;
return status;
} catch (e) {
continue;
}
}
return libubus.STATUS_NOT_FOUND;
}
},
config_set: {
args: {
phy: "",
@@ -116,6 +191,7 @@ let main_obj = {
if (!req.args.phy)
return libubus.STATUS_INVALID_ARGUMENT;
wpas.printf(`Set new config for phy ${req.args.phy}`);
try {
if (req.args.config)
set_config(req.args.phy, req.args.config);
@@ -188,6 +264,7 @@ function iface_hostapd_notify(phy, ifname, iface, state)
switch (state) {
case "DISCONNECTED":
case "AUTHENTICATING":
case "SCANNING":
msg.up = false;
break;
case "INTERFACE_DISABLED":

View File

@@ -0,0 +1,43 @@
From: Harshitha Prem <quic_hprem@quicinc.com>
Date: Wed, 22 Feb 2023 09:29:01 +0530
Subject: [PATCH] nl80211: Add frequency info in start AP command
When ACS is configured in multiple BSS case, sometimes a virtual AP
interface does not come up as the channel context information between
different BSSs of the same band does not match.
Same behavior is observed in case of multiple band/hardware under a
single wiphy, when we bring up multiple virtual interface in various
bands simultaneously and the kernel maps a random channel as it has more
than one channel context, e.g., say a 2.4 GHz channel to a 5 GHz virtual
AP interface when the start AP command is sent. This is because the
frequency information is not present in the command.
Add the frequency information into the start AP netlink command so that
the kernel maps the appropriate channel context by parsing it instead of
using a previous set channel information.
Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
---
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -167,6 +167,8 @@ static int nl80211_send_frame_cmd(struct
const u16 *csa_offs, size_t csa_offs_len);
static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
int report);
+static int nl80211_put_freq_params(struct nl_msg *msg,
+ const struct hostapd_freq_params *freq);
#define IFIDX_ANY -1
@@ -4717,6 +4719,9 @@ static int wpa_driver_nl80211_set_ap(voi
nla_nest_end(msg, spr);
}
+ if (params->freq && nl80211_put_freq_params(msg, params->freq) < 0)
+ goto fail;
+
if (params->freq && params->freq->he_enabled) {
struct nlattr *bss_color;

View File

@@ -0,0 +1,20 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 14 Sep 2023 10:53:50 +0200
Subject: [PATCH] driver_nl80211: fix setting QoS map on secondary BSSs
The setting is per-BSS, not per PHY
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -10045,7 +10045,7 @@ static int nl80211_set_qos_map(void *pri
wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
qos_map_set, qos_map_set_len);
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) ||
+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_QOS_MAP)) ||
nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) {
nlmsg_free(msg);
return -ENOBUFS;

View File

@@ -0,0 +1,18 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 14 Sep 2023 11:28:03 +0200
Subject: [PATCH] driver_nl80211: update drv->ifindex on removing the first
BSS
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -8003,6 +8003,7 @@ static int wpa_driver_nl80211_if_remove(
if (drv->first_bss->next) {
drv->first_bss = drv->first_bss->next;
drv->ctx = drv->first_bss->ctx;
+ drv->ifindex = drv->first_bss->ifindex;
os_free(bss);
} else {
wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");

View File

@@ -1,5 +1,7 @@
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
Index: hostapd-2021-02-20-59e9794c/hostapd/Makefile
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/hostapd/Makefile
+++ hostapd-2021-02-20-59e9794c/hostapd/Makefile
@@ -166,6 +166,12 @@ OBJS += ../src/common/hw_features_common
OBJS += ../src/eapol_auth/eapol_auth_sm.o
@@ -13,8 +15,10 @@
ifdef CONFIG_CODE_COVERAGE
CFLAGS += -O0 -fprofile-arcs -ftest-coverage
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
Index: hostapd-2021-02-20-59e9794c/src/ap/hostapd.h
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/hostapd.h
+++ hostapd-2021-02-20-59e9794c/src/ap/hostapd.h
@@ -17,6 +17,7 @@
#include "utils/list.h"
#include "ap_config.h"
@@ -39,8 +43,10 @@
void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
struct hostapd_iface * hostapd_alloc_iface(void);
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
Index: hostapd-2021-02-20-59e9794c/src/ap/hostapd.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/hostapd.c
+++ hostapd-2021-02-20-59e9794c/src/ap/hostapd.c
@@ -376,6 +376,7 @@ void hostapd_free_hapd_data(struct hosta
hapd->beacon_set_done = 0;
@@ -82,8 +88,10 @@
hostapd_interface_deinit(iface);
wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit",
__func__, driver, drv_priv);
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
Index: hostapd-2021-02-20-59e9794c/src/ap/ieee802_11.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/ieee802_11.c
+++ hostapd-2021-02-20-59e9794c/src/ap/ieee802_11.c
@@ -3421,13 +3421,18 @@ static void handle_auth(struct hostapd_d
u16 auth_alg, auth_transaction, status_code;
u16 resp = WLAN_STATUS_SUCCESS;
@@ -170,8 +178,10 @@
sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL) {
wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
Index: hostapd-2021-02-20-59e9794c/src/ap/beacon.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/beacon.c
+++ hostapd-2021-02-20-59e9794c/src/ap/beacon.c
@@ -823,6 +823,12 @@ void handle_probe_req(struct hostapd_dat
u16 csa_offs[2];
size_t csa_offs_len;
@@ -198,8 +208,10 @@
/* TODO: verify that supp_rates contains at least one matching rate
* with AP configuration */
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
Index: hostapd-2021-02-20-59e9794c/src/ap/drv_callbacks.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/drv_callbacks.c
+++ hostapd-2021-02-20-59e9794c/src/ap/drv_callbacks.c
@@ -145,6 +145,10 @@ int hostapd_notif_assoc(struct hostapd_d
u16 reason = WLAN_REASON_UNSPECIFIED;
int status = WLAN_STATUS_SUCCESS;
@@ -224,8 +236,22 @@
#ifdef CONFIG_P2P
if (elems.p2p) {
wpabuf_free(sta->p2p_ie);
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -981,9 +991,11 @@ void hostapd_event_ch_switch(struct host
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs);
+ hostapd_ubus_notify_csa(hapd, freq);
} else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
"freq=%d dfs=%d", freq, is_dfs);
+ hostapd_ubus_notify_csa(hapd, freq);
} else if (is_dfs &&
hostapd_is_dfs_required(hapd->iface) &&
!hostapd_is_dfs_chan_available(hapd->iface) &&
Index: hostapd-2021-02-20-59e9794c/src/ap/sta_info.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/sta_info.c
+++ hostapd-2021-02-20-59e9794c/src/ap/sta_info.c
@@ -458,6 +458,7 @@ void ap_handle_timer(void *eloop_ctx, vo
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
@@ -304,8 +330,10 @@
if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx)
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
Index: hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_glue.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/wpa_auth_glue.c
+++ hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_glue.c
@@ -265,6 +265,7 @@ static void hostapd_wpa_auth_psk_failure
struct hostapd_data *hapd = ctx;
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR,
@@ -314,8 +342,10 @@
}
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/Makefile
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/wpa_supplicant/Makefile
+++ hostapd-2021-02-20-59e9794c/wpa_supplicant/Makefile
@@ -169,6 +169,13 @@ ifdef CONFIG_EAPOL_TEST
CFLAGS += -Werror -DEAPOL_TEST
endif
@@ -340,8 +370,10 @@
endif
CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/wpa_supplicant.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/wpa_supplicant/wpa_supplicant.c
+++ hostapd-2021-02-20-59e9794c/wpa_supplicant/wpa_supplicant.c
@@ -6943,6 +6943,8 @@ struct wpa_supplicant * wpa_supplicant_a
}
#endif /* CONFIG_P2P */
@@ -373,8 +405,10 @@
return 0;
}
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/wpa_supplicant_i.h
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/wpa_supplicant/wpa_supplicant_i.h
+++ hostapd-2021-02-20-59e9794c/wpa_supplicant/wpa_supplicant_i.h
@@ -19,6 +19,7 @@
#include "wps/wps_defs.h"
#include "config_ssid.h"
@@ -400,8 +434,10 @@
#ifdef CONFIG_MATCH_IFACE
int matched;
#endif /* CONFIG_MATCH_IFACE */
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/wps_supplicant.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/wpa_supplicant/wps_supplicant.c
+++ hostapd-2021-02-20-59e9794c/wpa_supplicant/wps_supplicant.c
@@ -33,6 +33,7 @@
#include "p2p/p2p.h"
#include "p2p_supplicant.h"
@@ -419,8 +455,10 @@
if (wpa_s->conf->wps_cred_processing == 1)
return 0;
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/main.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/wpa_supplicant/main.c
+++ hostapd-2021-02-20-59e9794c/wpa_supplicant/main.c
@@ -202,7 +202,7 @@ int main(int argc, char *argv[])
for (;;) {
@@ -440,8 +478,10 @@
case 'o':
params.override_driver = optarg;
break;
--- a/src/ap/rrm.c
+++ b/src/ap/rrm.c
Index: hostapd-2021-02-20-59e9794c/src/ap/rrm.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/rrm.c
+++ hostapd-2021-02-20-59e9794c/src/ap/rrm.c
@@ -89,6 +89,9 @@ static void hostapd_handle_beacon_report
return;
wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s",
@@ -452,8 +492,10 @@
}
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
Index: hostapd-2021-02-20-59e9794c/src/ap/vlan_init.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/vlan_init.c
+++ hostapd-2021-02-20-59e9794c/src/ap/vlan_init.c
@@ -22,6 +22,7 @@
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
int existsok)
@@ -490,8 +532,10 @@
return hostapd_vlan_if_remove(hapd, vlan->ifname);
}
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
Index: hostapd-2021-02-20-59e9794c/src/ap/dfs.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/dfs.c
+++ hostapd-2021-02-20-59e9794c/src/ap/dfs.c
@@ -1226,6 +1226,8 @@ int hostapd_dfs_nop_finished(struct host
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
@@ -501,8 +545,10 @@
/* Proceed only if DFS is not offloaded to the driver */
if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
return 0;
--- a/src/ap/airtime_policy.c
+++ b/src/ap/airtime_policy.c
Index: hostapd-2021-02-20-59e9794c/src/ap/airtime_policy.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/airtime_policy.c
+++ hostapd-2021-02-20-59e9794c/src/ap/airtime_policy.c
@@ -108,8 +108,14 @@ static void set_sta_weights(struct hosta
{
struct sta_info *sta;
@@ -532,8 +578,10 @@
if (weight)
return sta_set_airtime_weight(hapd, sta, weight);
}
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
Index: hostapd-2021-02-20-59e9794c/src/ap/sta_info.h
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/sta_info.h
+++ hostapd-2021-02-20-59e9794c/src/ap/sta_info.h
@@ -323,6 +323,7 @@ struct sta_info {
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_AIRTIME_POLICY
@@ -542,8 +590,10 @@
struct os_reltime backlogged_until;
#endif /* CONFIG_AIRTIME_POLICY */
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
Index: hostapd-2021-02-20-59e9794c/src/ap/wnm_ap.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/wnm_ap.c
+++ hostapd-2021-02-20-59e9794c/src/ap/wnm_ap.c
@@ -442,7 +442,8 @@ static void ieee802_11_rx_bss_trans_mgmt
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
@@ -582,8 +632,10 @@
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
}
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
Index: hostapd-2021-02-20-59e9794c/src/utils/eloop.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/utils/eloop.c
+++ hostapd-2021-02-20-59e9794c/src/utils/eloop.c
@@ -77,6 +77,9 @@ struct eloop_sock_table {
struct eloop_data {
int max_sock;
@@ -632,8 +684,10 @@
void eloop_terminate(void)
{
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
Index: hostapd-2021-02-20-59e9794c/src/utils/eloop.h
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/utils/eloop.h
+++ hostapd-2021-02-20-59e9794c/src/utils/eloop.h
@@ -65,6 +65,9 @@ typedef void (*eloop_timeout_handler)(vo
*/
typedef void (*eloop_signal_handler)(int sig, void *signal_ctx);
@@ -663,8 +717,10 @@
/**
* eloop_run - Start the event loop
*
Index: hostapd-2021-02-20-59e9794c/src/utils/uloop.c
===================================================================
--- /dev/null
+++ b/src/utils/uloop.c
+++ hostapd-2021-02-20-59e9794c/src/utils/uloop.c
@@ -0,0 +1,64 @@
+#include <libubox/uloop.h>
+#include "includes.h"

View File

@@ -287,7 +287,33 @@
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -5827,6 +5827,7 @@ union wpa_event_data {
@@ -3357,6 +3357,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)
@@ -5827,6 +5846,7 @@ union wpa_event_data {
/**
* struct ch_switch
@@ -295,7 +321,7 @@
* @freq: Frequency of new channel in MHz
* @ht_enabled: Whether this is an HT channel
* @ch_offset: Secondary channel offset
@@ -5835,6 +5836,7 @@ union wpa_event_data {
@@ -5835,6 +5855,7 @@ union wpa_event_data {
* @cf2: Center frequency 2
*/
struct ch_switch {
@@ -348,3 +374,187 @@
switch (event) {
case EVENT_AUTH:
#ifdef CONFIG_FST
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -367,6 +367,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
@@ -1222,7 +1222,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);
@@ -1258,7 +1258,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);
@@ -7609,6 +7609,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,
@@ -7668,21 +7669,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) {
@@ -8041,6 +8038,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)
{
@@ -9385,6 +9426,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,
@@ -11967,6 +12039,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,

View File

@@ -10,7 +10,7 @@
--- a/src/ap/x_snoop.c
+++ b/src/ap/x_snoop.c
@@ -31,14 +31,16 @@ int x_snoop_init(struct hostapd_data *ha
@@ -31,28 +31,31 @@ int x_snoop_init(struct hostapd_data *ha
return -1;
}
@@ -29,13 +29,20 @@
wpa_printf(MSG_DEBUG,
"x_snoop: Failed to enable proxyarp on the bridge port");
return -1;
@@ -52,7 +54,8 @@ int x_snoop_init(struct hostapd_data *ha
}
if (hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT,
- 1)) {
+ conf->snoop_iface[0] ? conf->snoop_iface : NULL, 1)) {
wpa_printf(MSG_DEBUG,
"x_snoop: Failed to enable accepting gratuitous ARP on the bridge");
return -1;
}
#ifdef CONFIG_IPV6
- if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) {
+ if (!conf->snoop_iface[0] &&
+ hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) {
+ hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, NULL, 1)) {
wpa_printf(MSG_DEBUG,
"x_snoop: Failed to enable multicast snooping on the bridge");
return -1;
@@ -44,15 +51,27 @@
struct hostapd_bss_config *conf = hapd->conf;
struct l2_packet_data *l2;
+ const char *ifname = conf->bridge;
- l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1);
+
+ if (conf->snoop_iface[0])
+ ifname = conf->snoop_iface;
+
- l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1);
+ l2 = l2_packet_init(ifname, NULL, ETH_P_ALL, handler, hapd, 1);
if (l2 == NULL) {
wpa_printf(MSG_DEBUG,
"x_snoop: Failed to initialize L2 packet processing %s",
@@ -125,7 +132,10 @@ void x_snoop_mcast_to_ucast_convert_send
void x_snoop_deinit(struct hostapd_data *hapd)
{
- hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0);
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT,
+ conf->snoop_iface[0] ? conf->snoop_iface : NULL, 0);
hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0);
hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0);
}
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2343,6 +2343,8 @@ static int hostapd_config_fill(struct ho
@@ -64,3 +83,55 @@
} else if (os_strcmp(buf, "vlan_bridge") == 0) {
os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge));
} else if (os_strcmp(buf, "wds_bridge") == 0) {
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -340,12 +340,12 @@ static inline int hostapd_drv_br_port_se
static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd,
enum drv_br_net_param param,
- unsigned int val)
+ const char *ifname, unsigned int val)
{
if (hapd->driver == NULL || hapd->drv_priv == NULL ||
hapd->driver->br_set_net_param == NULL)
return -1;
- return hapd->driver->br_set_net_param(hapd->drv_priv, param, val);
+ return hapd->driver->br_set_net_param(hapd->drv_priv, param, ifname, val);
}
static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -3756,7 +3756,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,
- unsigned int val);
+ const char *ifname, unsigned int val);
/**
* get_wowlan - Get wake-on-wireless status
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -10825,7 +10825,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,
- unsigned int val)
+ const char *ifname, unsigned int val)
{
struct i802_bss *bss = priv;
char path[128];
@@ -10851,8 +10851,11 @@ static int wpa_driver_br_set_net_param(v
return -EINVAL;
}
+ if (!ifname)
+ ifname = bss->brname;
+
os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
- ip_version, bss->brname, param_txt);
+ ip_version, ifname, param_txt);
set_val:
if (linux_write_system_file(path, val))

View File

@@ -19,18 +19,6 @@
enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
--- a/src/ap/ubus.c
+++ b/src/ap/ubus.c
@@ -424,6 +424,9 @@ hostapd_bss_get_status(struct ubus_conte
hapd->iface->cac_started ? hapd->iface->dfs_cac_ms / 1000 - now.sec : 0);
blobmsg_close_table(&b, dfs_table);
+ if (hapd->conf->uci_section)
+ blobmsg_add_string(&b, "uci_section", hapd->conf->uci_section);
+
ubus_send_reply(ctx, req, b.head);
return 0;
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -785,6 +785,7 @@ void hostapd_config_free_bss(struct host

View File

@@ -50,42 +50,4 @@
return NL_SKIP;
}
--- a/src/ap/ubus.c
+++ b/src/ap/ubus.c
@@ -306,6 +306,36 @@ hostapd_bss_get_clients(struct ubus_cont
blobmsg_add_u32(&b, "tx", sta_driver_data.current_tx_rate * 100);
blobmsg_close_table(&b, r);
blobmsg_add_u32(&b, "signal", sta_driver_data.signal);
+
+ r = blobmsg_open_table(&b, "mcs");
+ if (sta_driver_data.rx_hemcs) {
+ blobmsg_add_u32(&b, "he", 1);
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_hemcs);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_hemcs);
+ } else if (sta_driver_data.rx_vhtmcs) {
+ blobmsg_add_u32(&b, "vht", 1);
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_vhtmcs);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_vhtmcs);
+ } else {
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_mcs);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_mcs);
+ }
+ blobmsg_close_table(&b, r);
+
+ r = blobmsg_open_table(&b, "nss");
+ if (sta_driver_data.rx_he_nss) {
+ blobmsg_add_u32(&b, "he", 1);
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_he_nss);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_he_nss);
+ } else if (sta_driver_data.rx_vht_nss) {
+ blobmsg_add_u32(&b, "vht", 1);
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_vht_nss);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_vht_nss);
+ } else {
+ blobmsg_add_u32(&b, "rx", sta_driver_data.rx_mcs);
+ blobmsg_add_u32(&b, "tx", sta_driver_data.tx_mcs);
+ }
+ blobmsg_close_table(&b, r);
}
hostapd_parse_capab_blobmsg(sta);

View File

@@ -0,0 +1,48 @@
Index: hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_ft.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/wpa_auth_ft.c
+++ hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_ft.c
@@ -3067,6 +3067,7 @@ static int wpa_ft_process_auth_req(struc
size_t identity_len = 0, radius_cui_len = 0;
int use_sha384;
size_t pmk_r1_len, kdk_len;
+ struct os_reltime now;
*resp_ies = NULL;
*resp_ies_len = 0;
@@ -3185,10 +3186,19 @@ pmk_r1_derived:
os_memcpy(sm->pmk_r1, pmk_r1, pmk_r1_len);
sm->pmk_r1_len = pmk_r1_len;
- if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
- wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
- "ANonce");
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ if (os_get_reltime(&now) < 0 ||
+ os_reltime_expired(&now, &sm->ANonce_time, 1)) {
+ if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
+ "ANonce");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+ sm->ANonce_time.sec = now.sec;
+ sm->ANonce_time.usec = now.usec;
+ wpa_printf(MSG_INFO, "FT: ANonce was randomized");
+ } else {
+ wpa_printf(MSG_INFO, "FT: ANonce has not expired");
+
}
wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
Index: hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_i.h
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/wpa_auth_i.h
+++ hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_i.h
@@ -54,6 +54,7 @@ struct wpa_state_machine {
bool MICVerified;
bool GUpdateStationKeys;
u8 ANonce[WPA_NONCE_LEN];
+ struct os_reltime ANonce_time;
u8 SNonce[WPA_NONCE_LEN];
u8 alt_SNonce[WPA_NONCE_LEN];
u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];

View File

@@ -61,28 +61,6 @@
};
--- a/src/ap/ubus.c
+++ b/src/ap/ubus.c
@@ -336,6 +336,9 @@ hostapd_bss_get_clients(struct ubus_cont
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_mcs);
}
blobmsg_close_table(&b, r);
+
+ if (sta->signal_mgmt)
+ blobmsg_add_u32(&b, "signal_mgmt", sta->signal_mgmt);
}
hostapd_parse_capab_blobmsg(sta);
@@ -457,6 +460,9 @@ hostapd_bss_get_status(struct ubus_conte
if (hapd->conf->uci_section)
blobmsg_add_string(&b, "uci_section", hapd->conf->uci_section);
+ if (hapd->signal_mgmt)
+ blobmsg_add_u32(&b, "signal_mgmt", hapd->signal_mgmt);
+
ubus_send_reply(ctx, req, b.head);
return 0;
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -451,6 +451,7 @@ struct hostapd_data {

View File

@@ -306,6 +306,39 @@ hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj,
blobmsg_add_u32(&b, "tx", sta_driver_data.current_tx_rate * 100);
blobmsg_close_table(&b, r);
blobmsg_add_u32(&b, "signal", sta_driver_data.signal);
r = blobmsg_open_table(&b, "mcs");
if (sta_driver_data.rx_hemcs) {
blobmsg_add_u32(&b, "he", 1);
blobmsg_add_u32(&b, "rx", sta_driver_data.rx_hemcs);
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_hemcs);
} else if (sta_driver_data.rx_vhtmcs) {
blobmsg_add_u32(&b, "vht", 1);
blobmsg_add_u32(&b, "rx", sta_driver_data.rx_vhtmcs);
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_vhtmcs);
} else {
blobmsg_add_u32(&b, "rx", sta_driver_data.rx_mcs);
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_mcs);
}
blobmsg_close_table(&b, r);
r = blobmsg_open_table(&b, "nss");
if (sta_driver_data.rx_he_nss) {
blobmsg_add_u32(&b, "he", 1);
blobmsg_add_u32(&b, "rx", sta_driver_data.rx_he_nss);
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_he_nss);
} else if (sta_driver_data.rx_vht_nss) {
blobmsg_add_u32(&b, "vht", 1);
blobmsg_add_u32(&b, "rx", sta_driver_data.rx_vht_nss);
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_vht_nss);
} else {
blobmsg_add_u32(&b, "rx", sta_driver_data.rx_mcs);
blobmsg_add_u32(&b, "tx", sta_driver_data.tx_mcs);
}
blobmsg_close_table(&b, r);
if (sta->signal_mgmt)
blobmsg_add_u32(&b, "signal_mgmt", sta->signal_mgmt);
}
hostapd_parse_capab_blobmsg(sta);
@@ -424,6 +457,12 @@ hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj,
hapd->iface->cac_started ? hapd->iface->dfs_cac_ms / 1000 - now.sec : 0);
blobmsg_close_table(&b, dfs_table);
if (hapd->conf->uci_section)
blobmsg_add_string(&b, "uci_section", hapd->conf->uci_section);
if (hapd->signal_mgmt)
blobmsg_add_u32(&b, "signal_mgmt", hapd->signal_mgmt);
ubus_send_reply(ctx, req, b.head);
return 0;
@@ -1698,6 +1737,19 @@ void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *
ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1);
}
void hostapd_ubus_notify_csa(struct hostapd_data *hapd, int freq)
{
if (!hapd->ubus.obj.has_subscribers)
return;
blob_buf_init(&b, 0);
blobmsg_add_string(&b, "ifname", hapd->conf->iface);
blobmsg_add_u32(&b, "freq", freq);
blobmsg_printf(&b, "bssid", MACSTR, MAC2STR(hapd->conf->bssid));
ubus_notify(ctx, &hapd->ubus.obj, "channel-switch", b.head, -1);
}
void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta)
{

File diff suppressed because it is too large Load Diff

View File

@@ -65,6 +65,7 @@ void hostapd_ubus_free(struct hapd_interfaces *interfaces);
int hostapd_ubus_notify_bss_transition_query(
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
const u8 *candidate_list, u16 candidate_list_len);
void hostapd_ubus_notify_csa(struct hostapd_data *hapd, int freq);
#else

View File

@@ -7,6 +7,8 @@
#include "beacon.h"
#include "hw_features.h"
#include "ap_drv_ops.h"
#include "dfs.h"
#include "acs.h"
#include <libubox/uloop.h>
static uc_resource_type_t *global_type, *bss_type, *iface_type;
@@ -109,6 +111,94 @@ uc_hostapd_remove_iface(uc_vm_t *vm, size_t nargs)
return NULL;
}
static struct hostapd_vlan *
bss_conf_find_vlan(struct hostapd_bss_config *bss, int id)
{
struct hostapd_vlan *vlan;
for (vlan = bss->vlan; vlan; vlan = vlan->next)
if (vlan->vlan_id == id)
return vlan;
return NULL;
}
static int
bss_conf_rename_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
const char *ifname)
{
if (!strcmp(ifname, vlan->ifname))
return 0;
hostapd_drv_if_rename(hapd, WPA_IF_AP_VLAN, vlan->ifname, ifname);
os_strlcpy(vlan->ifname, ifname, sizeof(vlan->ifname));
return 0;
}
static int
bss_reload_vlans(struct hostapd_data *hapd, struct hostapd_bss_config *bss)
{
struct hostapd_bss_config *old_bss = hapd->conf;
struct hostapd_vlan *vlan, *vlan_new, *wildcard;
char ifname[IFNAMSIZ + 1], vlan_ifname[IFNAMSIZ + 1], *pos;
int ret;
vlan = bss_conf_find_vlan(old_bss, VLAN_ID_WILDCARD);
wildcard = bss_conf_find_vlan(bss, VLAN_ID_WILDCARD);
if (!!vlan != !!wildcard)
return -1;
if (vlan && wildcard && strcmp(vlan->ifname, wildcard->ifname) != 0)
strcpy(vlan->ifname, wildcard->ifname);
else
wildcard = NULL;
for (vlan = bss->vlan; vlan; vlan = vlan->next) {
if (vlan->vlan_id == VLAN_ID_WILDCARD ||
vlan->dynamic_vlan > 0)
continue;
if (!bss_conf_find_vlan(old_bss, vlan->vlan_id))
return -1;
}
for (vlan = old_bss->vlan; vlan; vlan = vlan->next) {
if (vlan->vlan_id == VLAN_ID_WILDCARD)
continue;
if (vlan->dynamic_vlan == 0) {
vlan_new = bss_conf_find_vlan(bss, vlan->vlan_id);
if (!vlan_new)
return -1;
if (bss_conf_rename_vlan(hapd, vlan, vlan_new->ifname))
return -1;
continue;
}
if (!wildcard)
continue;
os_strlcpy(ifname, wildcard->ifname, sizeof(ifname));
pos = os_strchr(ifname, '#');
if (!pos)
return -1;
*pos++ = '\0';
ret = os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s%d%s",
ifname, vlan->vlan_id, pos);
if (os_snprintf_error(sizeof(vlan_ifname), ret))
return -1;
if (bss_conf_rename_vlan(hapd, vlan, vlan_ifname))
return -1;
}
return 0;
}
static uc_value_t *
uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs)
{
@@ -118,6 +208,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;
@@ -129,9 +220,28 @@ 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);
ret = bss_reload_vlans(hapd, bss);
goto done;
}
hostapd_bss_deinit_no_free(hapd);
hostapd_drv_stop_ap(hapd);
hostapd_free_hapd_data(hapd);
@@ -142,12 +252,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->multiple_bssid);
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);
}
@@ -178,10 +290,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;
@@ -191,8 +308,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);
@@ -266,6 +388,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)
{
@@ -297,12 +471,32 @@ uc_hostapd_iface_stop(uc_vm_t *vm, size_t nargs)
struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
int i;
switch (iface->state) {
case HAPD_IFACE_ENABLED:
case HAPD_IFACE_DISABLED:
break;
#ifdef CONFIG_ACS
case HAPD_IFACE_ACS:
acs_cleanup(iface);
iface->scan_cb = NULL;
/* fallthrough */
#endif
default:
hostapd_disable_iface(iface);
break;
}
if (iface->state != HAPD_IFACE_ENABLED)
hostapd_disable_iface(iface);
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *hapd = iface->bss[i];
hostapd_drv_stop_ap(hapd);
hapd->started = 0;
hapd->beacon_set_done = 0;
}
return NULL;
}
static uc_value_t *
@@ -311,67 +505,85 @@ uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs)
struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface");
uc_value_t *info = uc_fn_arg(0);
struct hostapd_config *conf;
bool changed = false;
uint64_t intval;
int i;
if (!iface)
return NULL;
if (!info)
if (!info) {
iface->freq = 0;
goto out;
}
if (ucv_type(info) != UC_OBJECT)
return NULL;
#define UPDATE_VAL(field, name) \
if ((intval = ucv_int64_get(ucv_object_get(info, name, NULL))) && \
!errno && intval != conf->field) do { \
conf->field = intval; \
changed = true; \
} while(0)
conf = iface->conf;
if ((intval = ucv_int64_get(ucv_object_get(info, "op_class", NULL))) && !errno)
conf->op_class = intval;
if ((intval = ucv_int64_get(ucv_object_get(info, "hw_mode", NULL))) && !errno)
conf->hw_mode = intval;
if ((intval = ucv_int64_get(ucv_object_get(info, "channel", NULL))) && !errno)
conf->channel = intval;
if ((intval = ucv_int64_get(ucv_object_get(info, "sec_channel", NULL))) && !errno)
conf->secondary_channel = intval;
#ifdef CONFIG_IEEE80211AC
if ((intval = ucv_int64_get(ucv_object_get(info, "center_seg0_idx", NULL))) && !errno) {
conf->vht_oper_centr_freq_seg0_idx = intval;
#ifdef CONFIG_IEEE80211AX
conf->he_oper_centr_freq_seg0_idx = intval;
#endif
#ifdef CONFIG_IEEE80211BE
conf->eht_oper_centr_freq_seg0_idx = intval;
#endif
}
if ((intval = ucv_int64_get(ucv_object_get(info, "center_seg1_idx", NULL))) && !errno) {
conf->vht_oper_centr_freq_seg1_idx = intval;
#ifdef CONFIG_IEEE80211AX
conf->he_oper_centr_freq_seg1_idx = intval;
#endif
#ifdef CONFIG_IEEE80211BE
conf->eht_oper_centr_freq_seg1_idx = intval;
#endif
}
UPDATE_VAL(op_class, "op_class");
UPDATE_VAL(hw_mode, "hw_mode");
UPDATE_VAL(channel, "channel");
UPDATE_VAL(secondary_channel, "sec_channel");
if (!changed &&
(iface->bss[0]->beacon_set_done ||
iface->state == HAPD_IFACE_DFS))
return ucv_boolean_new(true);
intval = ucv_int64_get(ucv_object_get(info, "center_seg0_idx", NULL));
if (!errno)
hostapd_set_oper_centr_freq_seg0_idx(conf, intval);
intval = ucv_int64_get(ucv_object_get(info, "center_seg1_idx", NULL));
if (!errno)
hostapd_set_oper_centr_freq_seg1_idx(conf, intval);
intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL));
if (!errno) {
conf->vht_oper_chwidth = intval;
#ifdef CONFIG_IEEE80211AX
conf->he_oper_chwidth = intval;
#endif
#ifdef CONFIG_IEEE80211BE
conf->eht_oper_chwidth = intval;
#endif
}
#endif
if (!errno)
hostapd_set_oper_chwidth(conf, intval);
intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL));
if (!errno)
iface->freq = intval;
else
iface->freq = 0;
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 (iface->state != HAPD_IFACE_ENABLED) {
hostapd_enable_iface(iface);
return ucv_boolean_new(true);
}
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *hapd = iface->bss[i];
int ret;
hapd->started = 1;
hapd->conf->start_disabled = 0;
hostapd_set_freq(hapd, conf->hw_mode, iface->freq,
conf->channel,
conf->enable_edmg,
@@ -436,6 +648,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[] = {
@@ -449,9 +710,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 },

View File

@@ -129,7 +129,10 @@ uc_value_t *uc_wpa_freq_info(uc_vm_t *vm, size_t nargs)
tmp_channel &= ~((8 << width) - 1);
center_idx = tmp_channel + center_ofs + (4 << width) - 1;
ucv_object_add(ret, "center_seg0_idx", ucv_int64_new(center_idx));
if (freq_val < 3000)
ucv_object_add(ret, "center_seg0_idx", ucv_int64_new(0));
else
ucv_object_add(ret, "center_seg0_idx", ucv_int64_new(center_idx));
center_idx = (center_idx - channel) * 5 + freq_val;
ucv_object_add(ret, "center_freq1", ucv_int64_new(center_idx));
@@ -295,9 +298,15 @@ uc_value_t *wpa_ucode_registry_get(uc_value_t *reg, int idx)
uc_value_t *wpa_ucode_registry_remove(uc_value_t *reg, int idx)
{
uc_value_t *val = wpa_ucode_registry_get(reg, idx);
void **dataptr;
if (val)
ucv_array_set(reg, idx - 1, NULL);
if (!val)
return NULL;
ucv_array_set(reg, idx - 1, NULL);
dataptr = ucv_resource_dataptr(val, NULL);
if (dataptr)
*dataptr = NULL;
return val;
}

View File

@@ -2,6 +2,7 @@
#include "utils/common.h"
#include "utils/ucode.h"
#include "drivers/driver.h"
#include "ap/hostapd.h"
#include "wpa_supplicant_i.h"
#include "wps_supplicant.h"
#include "bss.h"
@@ -211,12 +212,13 @@ uc_wpas_iface_status(uc_vm_t *vm, size_t nargs)
ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION);
if (ie && ie[1] >= 2) {
const struct ieee80211_ht_operation *ht_oper;
int sec;
ht_oper = (const void *) (ie + 2);
if (ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
sec = ht_oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
sec_chan = 1;
else if (ht_oper->ht_param &
HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
sec_chan = -1;
}
@@ -224,6 +226,15 @@ uc_wpas_iface_status(uc_vm_t *vm, size_t nargs)
ucv_object_add(ret, "frequency", ucv_int64_new(bss->freq));
}
#ifdef CONFIG_MESH
if (wpa_s->ifmsh) {
struct hostapd_iface *ifmsh = wpa_s->ifmsh;
ucv_object_add(ret, "sec_chan_offset", ucv_int64_new(ifmsh->conf->secondary_channel));
ucv_object_add(ret, "frequency", ucv_int64_new(ifmsh->freq));
}
#endif
return ret;
}

View File

@@ -488,6 +488,7 @@ ${channel:+channel=$channel}
${channel_list:+chanlist=$channel_list}
${hostapd_noscan:+noscan=1}
${tx_burst:+tx_queue_data2_burst=$tx_burst}
#num_global_macaddr=$num_global_macaddr
$base_cfg
EOF
@@ -528,6 +529,7 @@ mac80211_hostapd_setup_bss() {
cat >> /var/run/hostapd-$phy.conf <<EOF
$hostapd_cfg
bssid=$macaddr
${default_macaddr:+#default_macaddr}
${dtim_period:+dtim_period=$dtim_period}
${max_listen_int:+max_listen_interval=$max_listen_int}
EOF
@@ -542,57 +544,9 @@ mac80211_get_addr() {
mac80211_generate_mac() {
local phy="$1"
local multiple_bssid="$2"
local id="${macidx:-0}"
local ref="$(cat /sys/class/ieee80211/${phy}/macaddress)"
local mask="$(cat /sys/class/ieee80211/${phy}/address_mask)"
[ "$mask" = "00:00:00:00:00:00" -a "$multiple_bssid" != 1 ] && {
mask="ff:ff:ff:ff:ff:ff";
[ "$(wc -l < /sys/class/ieee80211/${phy}/addresses)" -gt $id ] && {
addr="$(mac80211_get_addr "$phy" "$id")"
[ -n "$addr" ] && {
echo "$addr"
return
}
}
}
local oIFS="$IFS"; IFS=":"; set -- $mask; IFS="$oIFS"
local mask1=$1
local mask6=$6
local oIFS="$IFS"; IFS=":"; set -- $ref; IFS="$oIFS"
[ "$multiple_bssid" -eq 1 ] && {
printf "02:%s:%s:%s:%s:%02x" $b1 $2 $3 $4 $5 $macidx
return
}
macidx=$(($id + 1))
local use_global=0
[ "$id" -gt 0 -a "$macidx" -le "$num_global_macaddr" ] && use_global=1
[ "$((0x$mask1))" -gt 0 -a "$use_global" -lt 1 ] && {
b1="0x$1"
[ "$id" -gt 0 ] && \
b1=$(($b1 ^ ((($id - !($b1 & 2)) << 2)) | 0x2))
printf "%02x:%s:%s:%s:%s:%s" $b1 $2 $3 $4 $5 $6
return
}
[ "$((0x$mask6))" -lt 255 -a "$use_global" -gt 0 ] && {
printf "%s:%s:%s:%s:%s:%02x" $1 $2 $3 $4 $5 $(( 0x$6 ^ $id ))
return
}
off2=$(( (0x$6 + $id) / 0x100 ))
printf "%s:%s:%s:%s:%02x:%02x" \
$1 $2 $3 $4 \
$(( (0x$5 + $off2) % 0x100 )) \
$(( (0x$6 + $id) % 0x100 ))
wdev_tool "$phy" get_macaddr id=$id num_global=$num_global_macaddr mbssid=$multiple_bssid
}
find_phy() {
@@ -626,11 +580,14 @@ mac80211_prepare_vif() {
set_default powersave 0
json_add_string _ifname "$ifname"
default_macaddr=
[ -n "$macaddr" ] || {
macaddr="$(mac80211_generate_mac $phy $multiple_bssid)"
macaddr="$(mac80211_generate_mac $phy)"
macidx="$(($macidx + 1))"
default_macaddr=1
}
json_add_string _macaddr "$macaddr"
json_add_string _default_macaddr "$default_macaddr"
json_select ..
@@ -754,7 +711,7 @@ mac80211_setup_adhoc() {
json_add_object "$ifname"
json_add_string mode adhoc
json_add_string macaddr "$macaddr"
[ -n "$default_macaddr" ] || json_add_string macaddr "$macaddr"
json_add_string ssid "$ssid"
json_add_string freq "$freq"
json_add_string htmode "$iw_htmode"
@@ -780,7 +737,7 @@ mac80211_setup_mesh() {
json_add_object "$ifname"
json_add_string mode mesh
json_add_string macaddr "$macaddr"
[ -n "$default_macaddr" ] || json_add_string macaddr "$macaddr"
json_add_string ssid "$ssid"
json_add_string freq "$freq"
json_add_string htmode "$iw_htmode"
@@ -831,7 +788,6 @@ wpa_supplicant_init_config() {
wpa_supplicant_add_interface() {
local ifname="$1"
local mode="$2"
local hostapd_ctrl="$3"
local prev
_wpa_supplicant_common "$ifname"
@@ -843,9 +799,8 @@ wpa_supplicant_add_interface() {
json_add_string iface "$ifname"
json_add_string mode "$mode"
json_add_string config "$_config"
json_add_string macaddr "$macaddr"
[ -n "$default_macaddr" ] || json_add_string macaddr "$macaddr"
[ -n "$network_bridge" ] && json_add_string bridge "$network_bridge"
[ -n "$hostapd_ctrl" ] && json_add_string hostapd_ctrl "$hostapd_ctrl"
[ -n "$wds" ] && json_add_boolean 4addr "$wds"
json_add_boolean powersave "$powersave"
[ "$mode" = "mesh" ] && mac80211_add_mesh_params
@@ -920,7 +875,7 @@ mac80211_setup_supplicant() {
wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan"
fi
wpa_supplicant_add_interface "$ifname" "$mode" "$hostapd_ctrl"
wpa_supplicant_add_interface "$ifname" "$mode"
return 0
}
@@ -932,6 +887,7 @@ mac80211_setup_vif() {
json_select config
json_get_var ifname _ifname
json_get_var macaddr _macaddr
json_get_var default_macaddr _default_macaddr
json_get_vars mode wds powersave
set_default powersave 0
@@ -1014,7 +970,7 @@ mac80211_reset_config() {
hostapd_conf_file="/var/run/hostapd-$phy.conf"
ubus call hostapd config_set '{ "phy": "'"$phy"'", "config": "", "prev_config": "'"$hostapd_conf_file"'" }' > /dev/null
ubus call wpa_supplicant config_set '{ "phy": "'"$phy"'", "config": [] }' > /dev/null
wdev_tool "$phy" '{}'
wdev_tool "$phy" set_config '{}'
}
drv_mac80211_setup() {
@@ -1116,7 +1072,7 @@ drv_mac80211_setup() {
mac80211_prepare_iw_htmode
active_ifnames=
for_each_interface "ap sta adhoc mesh monitor" mac80211_prepare_vif ${multiple_bssid}
for_each_interface "ap sta adhoc mesh monitor" mac80211_prepare_vif
for_each_interface "ap sta adhoc mesh monitor" mac80211_setup_vif
[ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_set_config "$phy"
@@ -1125,7 +1081,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

View File

@@ -0,0 +1,148 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 14 Sep 2023 13:17:16 +0200
Subject: [PATCH] cfg80211: allow grace period for DFS available after beacon
shutdown
Fixes reconfiguring an AP on a DFS channel in non-ETSI regdomain
Fixes: b35a51c7dd25 ("cfg80211: Make pre-CAC results valid only for ETSI domain")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -162,6 +162,8 @@ enum ieee80211_channel_flags {
* @dfs_state: current state of this channel. Only relevant if radar is required
* on this channel.
* @dfs_state_entered: timestamp (jiffies) when the dfs state was entered.
+ * @dfs_state_last_available: timestamp (jiffies) of the last time when the
+ * channel was available.
* @dfs_cac_ms: DFS CAC time in milliseconds, this is valid for DFS channels.
*/
struct ieee80211_channel {
@@ -178,6 +180,7 @@ struct ieee80211_channel {
int orig_mag, orig_mpwr;
enum nl80211_dfs_state dfs_state;
unsigned long dfs_state_entered;
+ unsigned long dfs_state_last_available;
unsigned int dfs_cac_ms;
};
--- a/net/wireless/ap.c
+++ b/net/wireless/ap.c
@@ -25,6 +25,8 @@ int __cfg80211_stop_ap(struct cfg80211_r
if (!wdev->beacon_interval)
return -ENOENT;
+ cfg80211_update_last_available(wdev->wiphy, &wdev->chandef);
+
err = rdev_stop_ap(rdev, dev);
if (!err) {
wdev->conn_owner_nlportid = 0;
@@ -35,9 +37,6 @@ int __cfg80211_stop_ap(struct cfg80211_r
if (notify)
nl80211_send_ap_stopped(wdev);
- /* Should we apply the grace period during beaconing interface
- * shutdown also?
- */
cfg80211_sched_dfs_chan_update(rdev);
}
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -411,6 +411,8 @@ static void cfg80211_set_chans_dfs_state
c->dfs_state = dfs_state;
c->dfs_state_entered = jiffies;
+ if (dfs_state == NL80211_DFS_AVAILABLE)
+ c->dfs_state_last_available = jiffies;
}
}
@@ -769,6 +771,49 @@ static bool cfg80211_get_chans_dfs_avail
return true;
}
+static void
+__cfg80211_update_last_available(struct wiphy *wiphy,
+ u32 center_freq,
+ u32 bandwidth)
+{
+ struct ieee80211_channel *c;
+ u32 freq, start_freq, end_freq;
+
+ start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
+ end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
+
+ /*
+ * Check entire range of channels for the bandwidth.
+ * If any channel in between is disabled or has not
+ * had gone through CAC return false
+ */
+ for (freq = start_freq; freq <= end_freq; freq += MHZ_TO_KHZ(20)) {
+ c = ieee80211_get_channel_khz(wiphy, freq);
+ if (!c)
+ return;
+
+ c->dfs_state_last_available = jiffies;
+ }
+}
+
+void cfg80211_update_last_available(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef)
+{
+ int width;
+
+ width = cfg80211_chandef_get_width(chandef);
+ if (width < 0)
+ return;
+
+ __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq1),
+ width);
+ if (chandef->width != NL80211_CHAN_WIDTH_80P80)
+ return;
+
+ __cfg80211_update_last_available(wiphy, MHZ_TO_KHZ(chandef->center_freq2),
+ width);
+}
+
static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef)
{
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -483,6 +483,8 @@ void cfg80211_set_dfs_state(struct wiphy
enum nl80211_dfs_state dfs_state);
void cfg80211_dfs_channels_update_work(struct work_struct *work);
+void cfg80211_update_last_available(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef);
unsigned int
cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -858,6 +858,8 @@ void cfg80211_dfs_channels_update_work(s
if (c->dfs_state == NL80211_DFS_UNAVAILABLE) {
time_dfs_update = IEEE80211_DFS_MIN_NOP_TIME_MS;
radar_event = NL80211_RADAR_NOP_FINISHED;
+ timeout = c->dfs_state_entered +
+ msecs_to_jiffies(time_dfs_update);
} else {
if (regulatory_pre_cac_allowed(wiphy) ||
cfg80211_any_wiphy_oper_chan(wiphy, c))
@@ -865,11 +867,10 @@ void cfg80211_dfs_channels_update_work(s
time_dfs_update = REG_PRE_CAC_EXPIRY_GRACE_MS;
radar_event = NL80211_RADAR_PRE_CAC_EXPIRED;
+ timeout = c->dfs_state_last_available +
+ msecs_to_jiffies(time_dfs_update);
}
- timeout = c->dfs_state_entered +
- msecs_to_jiffies(time_dfs_update);
-
if (time_after_eq(jiffies, timeout)) {
c->dfs_state = NL80211_DFS_USABLE;
c->dfs_state_entered = jiffies;

View File

@@ -0,0 +1,587 @@
--- a/config.c
+++ b/config.c
@@ -557,8 +557,8 @@ config_parse_wireless_device(struct uci_
wireless_device_create(drv, s->e.name, b.head);
}
-static struct wireless_interface*
-config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section *s)
+static void
+config_parse_wireless_vlan(struct wireless_interface *vif, struct uci_section *s)
{
char *name;
@@ -566,12 +566,12 @@ config_parse_wireless_interface(struct w
sprintf(name, "@%s[%d]", s->type, config_section_idx(s));
blob_buf_init(&b, 0);
- uci_to_blob(&b, s, wdev->drv->interface.config);
- return wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name);
+ uci_to_blob(&b, s, vif->wdev->drv->vlan.config);
+ wireless_vlan_create(vif, b.head, s->anonymous ? name : s->e.name);
}
static void
-config_parse_wireless_vlan(struct wireless_device *wdev, char *vif, struct uci_section *s)
+config_parse_wireless_station(struct wireless_interface *vif, struct uci_section *s)
{
char *name;
@@ -579,21 +579,62 @@ config_parse_wireless_vlan(struct wirele
sprintf(name, "@%s[%d]", s->type, config_section_idx(s));
blob_buf_init(&b, 0);
- uci_to_blob(&b, s, wdev->drv->vlan.config);
- wireless_vlan_create(wdev, vif, b.head, s->anonymous ? name : s->e.name);
+ uci_to_blob(&b, s, vif->wdev->drv->station.config);
+ wireless_station_create(vif, b.head, s->anonymous ? name : s->e.name);
}
static void
-config_parse_wireless_station(struct wireless_device *wdev, char *vif, struct uci_section *s)
+config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section *s)
{
+ struct wireless_interface *vif;
+ struct uci_element *f;
char *name;
name = alloca(strlen(s->type) + 16);
sprintf(name, "@%s[%d]", s->type, config_section_idx(s));
blob_buf_init(&b, 0);
- uci_to_blob(&b, s, wdev->drv->station.config);
- wireless_station_create(wdev, vif, b.head, s->anonymous ? name : s->e.name);
+ uci_to_blob(&b, s, wdev->drv->interface.config);
+ vif = wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name);
+ if (!vif)
+ return;
+
+ vif->vlan_idx = vif->sta_idx = 0;
+ vlist_update(&vif->vlans);
+ vlist_update(&vif->stations);
+
+ if (s->anonymous)
+ goto out;
+
+ uci_foreach_element(&uci_wireless->sections, f) {
+ struct uci_section *cur = uci_to_section(f);
+ const char *vif_name;
+
+ if (strcmp(cur->type, "wifi-vlan") != 0)
+ continue;
+
+ vif_name = uci_lookup_option_string(uci_ctx, cur, "iface");
+ if (vif_name && strcmp(s->e.name, vif_name))
+ continue;
+ config_parse_wireless_vlan(vif, cur);
+ }
+
+ uci_foreach_element(&uci_wireless->sections, f) {
+ struct uci_section *cur = uci_to_section(f);
+ const char *vif_name;
+
+ if (strcmp(cur->type, "wifi-station") != 0)
+ continue;
+
+ vif_name = uci_lookup_option_string(uci_ctx, cur, "iface");
+ if (vif_name && strcmp(s->e.name, vif_name))
+ continue;
+ config_parse_wireless_station(vif, cur);
+ }
+
+out:
+ vlist_flush(&vif->vlans);
+ vlist_flush(&vif->stations);
}
static void
@@ -623,16 +664,10 @@ config_init_wireless(void)
vlist_for_each_element(&wireless_devices, wdev, node) {
wdev->vif_idx = 0;
vlist_update(&wdev->interfaces);
- wdev->vlan_idx = 0;
- vlist_update(&wdev->vlans);
- wdev->sta_idx = 0;
- vlist_update(&wdev->stations);
}
uci_foreach_element(&uci_wireless->sections, e) {
struct uci_section *s = uci_to_section(e);
- struct wireless_interface *vif;
- struct uci_element *f;
if (strcmp(s->type, "wifi-iface") != 0)
continue;
@@ -647,42 +682,11 @@ config_init_wireless(void)
continue;
}
- vif = config_parse_wireless_interface(wdev, s);
-
- if (!vif || s->anonymous)
- continue;
- uci_foreach_element(&uci_wireless->sections, f) {
- struct uci_section *s = uci_to_section(f);
- const char *vif_name;
-
- if (strcmp(s->type, "wifi-vlan") != 0)
- continue;
-
- vif_name = uci_lookup_option_string(uci_ctx, s, "iface");
- if (vif_name && strcmp(e->name, vif_name))
- continue;
- config_parse_wireless_vlan(wdev, vif->name, s);
- }
-
- uci_foreach_element(&uci_wireless->sections, f) {
- struct uci_section *s = uci_to_section(f);
- const char *vif_name;
-
- if (strcmp(s->type, "wifi-station") != 0)
- continue;
-
- vif_name = uci_lookup_option_string(uci_ctx, s, "iface");
- if (vif_name && strcmp(e->name, vif_name))
- continue;
- config_parse_wireless_station(wdev, vif->name, s);
- }
+ config_parse_wireless_interface(wdev, s);
}
- vlist_for_each_element(&wireless_devices, wdev, node) {
+ vlist_for_each_element(&wireless_devices, wdev, node)
vlist_flush(&wdev->interfaces);
- vlist_flush(&wdev->vlans);
- vlist_flush(&wdev->stations);
- }
}
--- a/scripts/netifd-wireless.sh
+++ b/scripts/netifd-wireless.sh
@@ -108,14 +108,16 @@ _wdev_wrapper() {
}
_wdev_notify_init() {
- local command="$1"
- local name="$2"
- local value="$3"
+ local command="$1"; shift;
json_init
json_add_int "command" "$command"
json_add_string "device" "$__netifd_device"
- [ -n "$name" -a -n "$value" ] && json_add_string "$name" "$value"
+ while [ -n "$1" ]; do
+ local name="$1"; shift
+ local value="$1"; shift
+ json_add_string "$name" "$value"
+ done
json_add_object "data"
}
@@ -151,7 +153,7 @@ _wireless_add_vlan() {
local name="$1"; shift
local ifname="$1"; shift
- _wdev_notify_init $CMD_SET_DATA "vlan" "$name"
+ _wdev_notify_init $CMD_SET_DATA interface "$__cur_interface" "vlan" "$name"
json_add_string "ifname" "$ifname"
_wdev_add_variables "$@"
_wdev_notify
@@ -333,6 +335,7 @@ for_each_interface() {
continue
}
fi
+ __cur_interface="$_w_iface"
"$@" "$_w_iface"
json_select ..
done
--- a/wireless.c
+++ b/wireless.c
@@ -205,9 +205,7 @@ prepare_config(struct wireless_device *w
blobmsg_add_blob(&b, vif->data);
j = blobmsg_open_table(&b, "vlans");
- vlist_for_each_element(&wdev->vlans, vlan, node) {
- if (strcmp(vlan->vif, vif->name))
- continue;
+ vlist_for_each_element(&vif->vlans, vlan, node) {
k = blobmsg_open_table(&b, vlan->name);
vif_config_add_bridge(&b, vlan->network, up);
put_container(&b, vlan->config, "config");
@@ -218,9 +216,7 @@ prepare_config(struct wireless_device *w
blobmsg_close_table(&b, j);
j = blobmsg_open_table(&b, "stas");
- vlist_for_each_element(&wdev->stations, sta, node) {
- if (strcmp(sta->vif, vif->name))
- continue;
+ vlist_for_each_element(&vif->stations, sta, node) {
k = blobmsg_open_table(&b, sta->name);
put_container(&b, sta->config, "config");
if (sta->data)
@@ -311,15 +307,15 @@ wireless_device_free_state(struct wirele
free(vif->data);
vif->data = NULL;
vif->ifname = NULL;
- }
- vlist_for_each_element(&wdev->vlans, vlan, node) {
- free(vlan->data);
- vlan->data = NULL;
- vlan->ifname = NULL;
- }
- vlist_for_each_element(&wdev->stations, sta, node) {
- free(sta->data);
- sta->data = NULL;
+ vlist_for_each_element(&vif->vlans, vlan, node) {
+ free(vlan->data);
+ vlan->data = NULL;
+ vlan->ifname = NULL;
+ }
+ vlist_for_each_element(&vif->stations, sta, node) {
+ free(sta->data);
+ sta->data = NULL;
+ }
}
}
@@ -510,8 +506,6 @@ wireless_device_free(struct wireless_dev
{
wireless_handler_stop(wdev);
vlist_flush_all(&wdev->interfaces);
- vlist_flush_all(&wdev->vlans);
- vlist_flush_all(&wdev->stations);
avl_delete(&wireless_devices.avl, &wdev->node.avl);
free(wdev->config);
free(wdev->prev_config);
@@ -547,11 +541,12 @@ wireless_device_mark_down(struct wireles
netifd_log_message(L_NOTICE, "Wireless device '%s' is now down\n", wdev->name);
- vlist_for_each_element(&wdev->vlans, vlan, node)
- wireless_vlan_handle_link(vlan, false);
- vlist_for_each_element(&wdev->interfaces, vif, node)
+ vlist_for_each_element(&wdev->interfaces, vif, node) {
wireless_interface_handle_link(vif, NULL, false);
+ vlist_for_each_element(&vif->vlans, vlan, node)
+ wireless_vlan_handle_link(vlan, false);
+ }
wireless_process_kill_all(wdev, SIGTERM, true);
@@ -623,10 +618,11 @@ wireless_device_mark_up(struct wireless_
netifd_log_message(L_NOTICE, "Wireless device '%s' is now up\n", wdev->name);
wdev->retry = WIRELESS_SETUP_RETRY;
wdev->state = IFS_UP;
- vlist_for_each_element(&wdev->interfaces, vif, node)
+ vlist_for_each_element(&wdev->interfaces, vif, node) {
wireless_interface_handle_link(vif, NULL, true);
- vlist_for_each_element(&wdev->vlans, vlan, node)
- wireless_vlan_handle_link(vlan, true);
+ vlist_for_each_element(&vif->vlans, vlan, node)
+ wireless_vlan_handle_link(vlan, true);
+ }
}
static void
@@ -848,6 +844,16 @@ wireless_interface_init_config(struct wi
vif->multicast_to_unicast = cur ? blobmsg_get_bool(cur) : -1;
}
+static void
+vif_free(struct wireless_interface *vif)
+{
+ vlist_flush_all(&vif->vlans);
+ vlist_flush_all(&vif->stations);
+ free((void *) vif->section);
+ free(vif->config);
+ free(vif);
+}
+
/* vlist update call for wireless interface list */
static void
vif_update(struct vlist_tree *tree, struct vlist_node *node_new,
@@ -884,9 +890,7 @@ vif_update(struct vlist_tree *tree, stru
} else if (vif_old) {
D(WIRELESS, "Delete wireless interface %s on device %s\n", vif_old->name, wdev->name);
wireless_interface_handle_link(vif_old, NULL, false);
- free((void *) vif_old->section);
- free(vif_old->config);
- free(vif_old);
+ vif_free(vif_old);
}
wdev->config_update = true;
@@ -921,14 +925,10 @@ static void
vlan_update(struct vlist_tree *tree, struct vlist_node *node_new,
struct vlist_node *node_old)
{
- struct wireless_vlan *vlan_old = container_of(node_old, struct wireless_vlan, node);
- struct wireless_vlan *vlan_new = container_of(node_new, struct wireless_vlan, node);
- struct wireless_device *wdev;
-
- if (vlan_old)
- wdev = vlan_old->wdev;
- else
- wdev = vlan_new->wdev;
+ struct wireless_vlan *vlan_old = container_of_safe(node_old, struct wireless_vlan, node);
+ struct wireless_vlan *vlan_new = container_of_safe(node_new, struct wireless_vlan, node);
+ struct wireless_interface *vif = container_of(tree, struct wireless_interface, vlans);
+ struct wireless_device *wdev = vif->wdev;
if (vlan_old && vlan_new) {
free((void *) vlan_old->section);
@@ -951,7 +951,7 @@ vlan_update(struct vlist_tree *tree, str
vlan_new->config = blob_memdup(vlan_new->config);
wireless_vlan_init_config(vlan_new);
} else if (vlan_old) {
- D(WIRELESS, "Delete wireless interface %s on device %s\n", vlan_old->name, wdev->name);
+ D(WIRELESS, "Delete wireless vlan %s on device %s\n", vlan_old->name, wdev->name);
wireless_vlan_handle_link(vlan_old, false);
free((void *) vlan_old->section);
free(vlan_old->config);
@@ -966,14 +966,10 @@ static void
station_update(struct vlist_tree *tree, struct vlist_node *node_new,
struct vlist_node *node_old)
{
- struct wireless_station *sta_old = container_of(node_old, struct wireless_station, node);
- struct wireless_station *sta_new = container_of(node_new, struct wireless_station, node);
- struct wireless_device *wdev;
-
- if (sta_old)
- wdev = sta_old->wdev;
- else
- wdev = sta_new->wdev;
+ struct wireless_station *sta_old = container_of_safe(node_old, struct wireless_station, node);
+ struct wireless_station *sta_new = container_of_safe(node_new, struct wireless_station, node);
+ struct wireless_interface *vif = container_of(tree, struct wireless_interface, stations);
+ struct wireless_device *wdev = vif->wdev;
if (sta_old && sta_new) {
free((void *) sta_old->section);
@@ -1088,10 +1084,6 @@ wireless_device_create(struct wireless_d
INIT_LIST_HEAD(&wdev->script_proc);
vlist_init(&wdev->interfaces, avl_strcmp, vif_update);
wdev->interfaces.keep_old = true;
- vlist_init(&wdev->vlans, avl_strcmp, vlan_update);
- wdev->vlans.keep_old = true;
- vlist_init(&wdev->stations, avl_strcmp, station_update);
- wdev->stations.keep_old = true;
wdev->timeout.cb = wireless_device_setup_timeout;
wdev->script_task.cb = wireless_device_script_task_cb;
@@ -1108,12 +1100,12 @@ wireless_device_create(struct wireless_d
/* creates a wireless station object. Called by config */
void
-wireless_station_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section)
+wireless_station_create(struct wireless_interface *vif, struct blob_attr *data, const char *section)
{
struct wireless_station *sta;
struct blob_attr *tb[__STA_ATTR_MAX];
struct blob_attr *cur;
- char *name_buf, *vif_buf;
+ char *name_buf;
char name[8];
blobmsg_parse(sta_policy, __STA_ATTR_MAX, tb, blob_data(data), blob_len(data));
@@ -1122,18 +1114,15 @@ wireless_station_create(struct wireless_
if (cur && blobmsg_get_bool(cur))
return;
- sprintf(name, "%d", wdev->sta_idx++);
+ sprintf(name, "%d", vif->sta_idx++);
sta = calloc_a(sizeof(*sta),
- &name_buf, strlen(name) + 1,
- &vif_buf, strlen(vif) + 1);
+ &name_buf, strlen(name) + 1);
sta->name = strcpy(name_buf, name);
- sta->vif = strcpy(vif_buf, vif);
- sta->wdev = wdev;
sta->config = data;
sta->section = section;
- vlist_add(&wdev->stations, &sta->node, sta->name);
+ vlist_add(&vif->stations, &sta->node, sta->name);
}
/* ubus callback network.wireless.status, runs for every interface, encode the station */
@@ -1151,12 +1140,12 @@ wireless_station_status(struct wireless_
/* create a vlan object. Called by config */
void
-wireless_vlan_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section)
+wireless_vlan_create(struct wireless_interface *vif, struct blob_attr *data, const char *section)
{
struct wireless_vlan *vlan;
struct blob_attr *tb[__VLAN_ATTR_MAX];
struct blob_attr *cur;
- char *name_buf, *vif_buf;
+ char *name_buf;
char name[8];
blobmsg_parse(vlan_policy, __VLAN_ATTR_MAX, tb, blob_data(data), blob_len(data));
@@ -1165,19 +1154,14 @@ wireless_vlan_create(struct wireless_dev
if (cur && blobmsg_get_bool(cur))
return;
- sprintf(name, "%d", wdev->vlan_idx++);
+ sprintf(name, "%d", vif->vlan_idx++);
- vlan = calloc_a(sizeof(*vlan),
- &name_buf, strlen(name) + 1,
- &vif_buf, strlen(vif) + 1);
+ vlan = calloc_a(sizeof(*vlan), &name_buf, strlen(name) + 1);
vlan->name = strcpy(name_buf, name);
- vlan->vif = strcpy(vif_buf, vif);
- vlan->wdev = wdev;
vlan->config = data;
vlan->section = section;
- vlan->isolate = false;
- vlist_add(&wdev->vlans, &vlan->node, vlan->name);
+ vlist_add(&vif->vlans, &vlan->node, vlan->name);
}
/* ubus callback network.wireless.status, runs for every interface, encode the vlan informations */
@@ -1220,6 +1204,12 @@ struct wireless_interface* wireless_inte
vif->section = section;
vif->isolate = false;
+ vlist_init(&vif->vlans, avl_strcmp, vlan_update);
+ vif->vlans.keep_old = true;
+
+ vlist_init(&vif->stations, avl_strcmp, station_update);
+ vif->stations.keep_old = true;
+
vlist_add(&wdev->interfaces, &vif->node, vif->name);
return vlist_find(&wdev->interfaces, name, vif, node);
@@ -1240,14 +1230,12 @@ wireless_interface_status(struct wireles
blobmsg_add_string(b, "ifname", iface->ifname);
put_container(b, iface->config, "config");
j = blobmsg_open_array(b, "vlans");
- vlist_for_each_element(&iface->wdev->vlans, vlan, node)
- if (!strcmp(iface->name, vlan->vif))
- wireless_vlan_status(vlan, b);
+ vlist_for_each_element(&iface->vlans, vlan, node)
+ wireless_vlan_status(vlan, b);
blobmsg_close_array(b, j);
j = blobmsg_open_array(b, "stations");
- vlist_for_each_element(&iface->wdev->stations, sta, node)
- if (!strcmp(iface->name, sta->vif))
- wireless_station_status(sta, b);
+ vlist_for_each_element(&iface->stations, sta, node)
+ wireless_station_status(sta, b);
blobmsg_close_array(b, j);
blobmsg_close_table(b, i);
}
@@ -1496,7 +1484,9 @@ wireless_device_notify(struct wireless_d
}
if ((cur = tb[NOTIFY_ATTR_VLAN]) != NULL) {
- vlan = vlist_find(&wdev->vlans, blobmsg_data(cur), vlan, node);
+ if (!vif)
+ return UBUS_STATUS_NOT_FOUND;
+ vlan = vlist_find(&vif->vlans, blobmsg_data(cur), vlan, node);
if (!vlan)
return UBUS_STATUS_NOT_FOUND;
}
@@ -1516,19 +1506,19 @@ wireless_device_notify(struct wireless_d
wireless_device_mark_up(wdev);
break;
case NOTIFY_CMD_SET_DATA:
- if (vif)
- pdata = &vif->data;
- else if (vlan)
+ if (vlan)
pdata = &vlan->data;
+ else if (vif)
+ pdata = &vif->data;
else
pdata = &wdev->data;
free(*pdata);
*pdata = blob_memdup(cur);
- if (vif)
- wireless_interface_set_data(vif);
- else if (vlan)
+ if (vlan)
wireless_vlan_set_data(vlan);
+ else if (vif)
+ wireless_interface_set_data(vif);
break;
case NOTIFY_CMD_PROCESS_ADD:
return wireless_device_add_process(wdev, cur);
--- a/wireless.h
+++ b/wireless.h
@@ -44,8 +44,6 @@ struct wireless_device {
struct wireless_driver *drv;
struct vlist_tree interfaces;
- struct vlist_tree vlans;
- struct vlist_tree stations;
char *name;
struct netifd_process script_task;
@@ -73,8 +71,6 @@ struct wireless_device {
int retry;
int vif_idx;
- int vlan_idx;
- int sta_idx;
};
struct wireless_interface {
@@ -82,6 +78,8 @@ struct wireless_interface {
const char *section;
char *name;
+ struct vlist_tree vlans;
+ struct vlist_tree stations;
struct wireless_device *wdev;
struct blob_attr *config;
@@ -94,6 +92,8 @@ struct wireless_interface {
bool isolate;
bool ap_mode;
int multicast_to_unicast;
+ int vlan_idx;
+ int sta_idx;
};
struct wireless_vlan {
@@ -101,9 +101,6 @@ struct wireless_vlan {
const char *section;
char *name;
- struct wireless_device *wdev;
- char *vif;
-
struct blob_attr *config;
struct blob_attr *data;
@@ -119,9 +116,6 @@ struct wireless_station {
const char *section;
char *name;
- struct wireless_device *wdev;
- char *vif;
-
struct blob_attr *config;
struct blob_attr *data;
};
@@ -143,8 +137,8 @@ void wireless_device_reconf(struct wirel
void wireless_device_status(struct wireless_device *wdev, struct blob_buf *b);
void wireless_device_get_validate(struct wireless_device *wdev, struct blob_buf *b);
struct wireless_interface* wireless_interface_create(struct wireless_device *wdev, struct blob_attr *data, const char *section);
-void wireless_vlan_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section);
-void wireless_station_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section);
+void wireless_vlan_create(struct wireless_interface *vif, struct blob_attr *data, const char *section);
+void wireless_station_create(struct wireless_interface *vif, struct blob_attr *data, const char *section);
int wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data,
struct ubus_request_data *req);

View File

@@ -0,0 +1,285 @@
From 4e4128e44fcb6c0f444e4aa481eb8941f47a801a Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Fri, 15 Sep 2023 20:47:10 +0200
Subject: [PATCH] netifd: add support for enabling/disabling wifi interfaces
via ifup/ifdown
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
package/network/config/netifd/files/sbin/ifup | 33 ---
.../patches/410-wireless_network_state.patch | 194 ++++++++++++++++++
2 files changed, 194 insertions(+), 33 deletions(-)
create mode 100644 package/network/config/netifd/patches/410-wireless_network_state.patch
diff --git a/package/network/config/netifd/files/sbin/ifup b/package/network/config/netifd/files/sbin/ifup
index 15be535bbfc9..fbf2fd80c7ea 100755
--- a/package/network/config/netifd/files/sbin/ifup
+++ b/package/network/config/netifd/files/sbin/ifup
@@ -1,7 +1,6 @@
#!/bin/sh
ifup_all=
-setup_wifi=
if_call() {
local interface="$1"
@@ -14,7 +13,6 @@ case "$0" in
*ifdown) modes=down;;
*ifup)
modes="down up"
- setup_wifi=1
;;
*) echo "Invalid command: $0";;
esac
@@ -25,10 +23,6 @@ while :; do
ifup_all=1
shift
;;
- -w)
- setup_wifi=
- shift
- ;;
*)
break
;;
@@ -40,7 +34,6 @@ if [ -n "$ifup_all" ]; then
for interface in $(ubus -S list 'network.interface.*'); do
if_call "${interface##network.interface.}"
done
- [ -n "$setup_wifi" ] && /sbin/wifi up
exit
else
ubus -S list "network.interface.$1" > /dev/null || {
@@ -49,29 +42,3 @@ else
}
if_call "$1"
fi
-
-if [ -n "$setup_wifi" ] && grep -sq config /etc/config/wireless; then
- . /lib/functions.sh
-
- find_related_radios() {
- local wdev wnet
- config_get wdev "$1" device
- config_get wnet "$1" network
-
- if [ -n "$wdev" ]; then
- for wnet in $wnet; do
- if [ "$wnet" = "$network" ]; then
- append radio_devs "$wdev" "$N"
- fi
- done
- fi
- }
-
- network="$1"
- config_load wireless
- config_foreach find_related_radios wifi-iface
-
- for dev in $(echo "$radio_devs" | sort -u); do
- /sbin/wifi up "$dev"
- done
-fi
diff --git a/package/network/config/netifd/patches/410-wireless_network_state.patch b/package/network/config/netifd/patches/410-wireless_network_state.patch
new file mode 100644
index 000000000000..4e9b905190b6
--- /dev/null
+++ b/package/network/config/netifd/patches/410-wireless_network_state.patch
@@ -0,0 +1,194 @@
+--- a/config.c
++++ b/config.c
+@@ -784,7 +784,7 @@ config_init_all(void)
+ vlist_flush(&interfaces);
+ interface_refresh_assignments(false);
+ interface_start_pending();
+- wireless_start_pending();
++ wireless_start_pending(0);
+
+ return ret;
+ }
+--- a/interface.c
++++ b/interface.c
+@@ -25,6 +25,7 @@
+ #include "ubus.h"
+ #include "config.h"
+ #include "system.h"
++#include "wireless.h"
+
+ struct vlist_tree interfaces;
+ static LIST_HEAD(iface_all_users);
+@@ -1125,6 +1126,7 @@ interface_set_up(struct interface *iface
+ const char *error = NULL;
+
+ iface->autostart = true;
++ wireless_check_network_enabled();
+
+ if (iface->state != IFS_DOWN)
+ return;
+@@ -1157,6 +1159,7 @@ interface_set_down(struct interface *ifa
+ __interface_set_down(iface, false);
+ } else {
+ iface->autostart = false;
++ wireless_check_network_enabled();
+ __interface_set_down(iface, false);
+ }
+ }
+--- a/wireless.c
++++ b/wireless.c
+@@ -198,6 +198,9 @@ prepare_config(struct wireless_device *w
+
+ l = blobmsg_open_table(&b, "interfaces");
+ vlist_for_each_element(&wdev->interfaces, vif, node) {
++ if (vif->disabled)
++ continue;
++
+ i = blobmsg_open_table(&b, vif->name);
+ vif_config_add_bridge(&b, vif->network, up);
+ put_container(&b, vif->config, "config");
+@@ -438,6 +441,8 @@ wireless_device_run_handler(struct wirel
+ wdev->prev_config = NULL;
+ } else {
+ prepare_config(wdev, &b, up);
++ free(wdev->prev_config);
++ wdev->prev_config = up ? blob_memdup(b.head) : NULL;
+ config = blobmsg_format_json(b.head, true);
+ }
+
+@@ -495,8 +500,6 @@ __wireless_device_set_up(struct wireless
+ if ((!force && wdev->state != IFS_DOWN) || config_init)
+ return;
+
+- free(wdev->prev_config);
+- wdev->prev_config = NULL;
+ wdev->state = IFS_SETUP;
+ wireless_device_run_handler(wdev, true);
+ }
+@@ -690,16 +693,6 @@ wdev_set_config_state(struct wireless_de
+ }
+
+ static void
+-wdev_prepare_prev_config(struct wireless_device *wdev)
+-{
+- if (wdev->prev_config)
+- return;
+-
+- prepare_config(wdev, &b, false);
+- wdev->prev_config = blob_memdup(b.head);
+-}
+-
+-static void
+ wdev_change_config(struct wireless_device *wdev, struct wireless_device *wd_new)
+ {
+ struct blob_attr *new_config = wd_new->config;
+@@ -709,7 +702,6 @@ wdev_change_config(struct wireless_devic
+ wdev->serialize = wd_new->serialize;
+ free(wd_new);
+
+- wdev_prepare_prev_config(wdev);
+ if (blob_attr_equal(wdev->config, new_config) && wdev->disabled == disabled)
+ return;
+
+@@ -1533,19 +1525,78 @@ wireless_device_notify(struct wireless_d
+ return 0;
+ }
+
+-/* called on startup and by netifd reload() */
+-void
+-wireless_start_pending(void)
++static void
++wdev_check_network_enabled(struct wireless_device *wdev)
++{
++ struct wireless_interface *vif;
++ struct interface *iface;
++ struct blob_attr *cur;
++ int rem;
++
++ vlist_for_each_element(&wdev->interfaces, vif, node) {
++ int enabled = -1;
++
++ blobmsg_for_each_attr(cur, vif->network, rem) {
++ iface = vlist_find(&interfaces, blobmsg_get_string(cur), iface, node);
++ if (!iface)
++ continue;
++
++ if (iface->autostart) {
++ enabled = 1;
++ break;
++ }
++ if (enabled != 1)
++ enabled = 0;
++ }
++
++ if (vif->disabled == !enabled)
++ continue;
++
++ vif->disabled = !enabled;
++ wdev->config_update = true;
++ }
++}
++
++static void
++__wireless_start_pending(struct uloop_timeout *t)
+ {
+ struct wireless_device *wdev;
+
+ vlist_for_each_element(&wireless_devices, wdev, node) {
++ wdev_check_network_enabled(wdev);
+ if (wdev->config_update)
+ wdev_set_config_state(wdev, IFC_RELOAD);
+ __wireless_device_set_up(wdev, 0);
+ }
+ }
+
++void wireless_start_pending(int timeout)
++{
++ static struct uloop_timeout timer = {
++ .cb = __wireless_start_pending
++ };
++
++ if (timeout) {
++ uloop_timeout_set(&timer, timeout);
++ return;
++ }
++
++ uloop_timeout_cancel(&timer);
++ timer.cb(&timer);
++}
++
++void wireless_check_network_enabled(void)
++{
++ struct wireless_device *wdev;
++
++ vlist_for_each_element(&wireless_devices, wdev, node) {
++ wdev_check_network_enabled(wdev);
++
++ if (wdev->config_update)
++ wireless_start_pending(1000);
++ }
++}
++
+ void wireless_device_hotplug_event(const char *name, bool add)
+ {
+ struct wireless_interface *vif;
+--- a/wireless.h
++++ b/wireless.h
+@@ -94,6 +94,7 @@ struct wireless_interface {
+ int multicast_to_unicast;
+ int vlan_idx;
+ int sta_idx;
++ bool disabled;
+ };
+
+ struct wireless_vlan {
+@@ -142,7 +143,8 @@ void wireless_station_create(struct wire
+ int wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data,
+ struct ubus_request_data *req);
+
+-void wireless_start_pending(void);
++void wireless_check_network_enabled(void);
++void wireless_start_pending(int timeout);
+ void wireless_init(void);
+ void wireless_device_hotplug_event(const char *name, bool add);
+
--
2.39.2

View File

@@ -0,0 +1,607 @@
From f7feafa6a88a70f96ac4bf556ff5b0665eb9735a Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Fri, 15 Sep 2023 15:01:44 +0200
Subject: [PATCH] netifd: add wireless vlan/sta fix
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
.../patches/400-wireless_vlan_fix.patch | 587 ++++++++++++++++++
1 file changed, 587 insertions(+)
create mode 100644 package/network/config/netifd/patches/400-wireless_vlan_fix.patch
diff --git a/package/network/config/netifd/patches/400-wireless_vlan_fix.patch b/package/network/config/netifd/patches/400-wireless_vlan_fix.patch
new file mode 100644
index 000000000000..449121dd3d9e
--- /dev/null
+++ b/package/network/config/netifd/patches/400-wireless_vlan_fix.patch
@@ -0,0 +1,587 @@
+--- a/config.c
++++ b/config.c
+@@ -557,8 +557,8 @@ config_parse_wireless_device(struct uci_
+ wireless_device_create(drv, s->e.name, b.head);
+ }
+
+-static struct wireless_interface*
+-config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section *s)
++static void
++config_parse_wireless_vlan(struct wireless_interface *vif, struct uci_section *s)
+ {
+ char *name;
+
+@@ -566,12 +566,12 @@ config_parse_wireless_interface(struct w
+ sprintf(name, "@%s[%d]", s->type, config_section_idx(s));
+
+ blob_buf_init(&b, 0);
+- uci_to_blob(&b, s, wdev->drv->interface.config);
+- return wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name);
++ uci_to_blob(&b, s, vif->wdev->drv->vlan.config);
++ wireless_vlan_create(vif, b.head, s->anonymous ? name : s->e.name);
+ }
+
+ static void
+-config_parse_wireless_vlan(struct wireless_device *wdev, char *vif, struct uci_section *s)
++config_parse_wireless_station(struct wireless_interface *vif, struct uci_section *s)
+ {
+ char *name;
+
+@@ -579,21 +579,62 @@ config_parse_wireless_vlan(struct wirele
+ sprintf(name, "@%s[%d]", s->type, config_section_idx(s));
+
+ blob_buf_init(&b, 0);
+- uci_to_blob(&b, s, wdev->drv->vlan.config);
+- wireless_vlan_create(wdev, vif, b.head, s->anonymous ? name : s->e.name);
++ uci_to_blob(&b, s, vif->wdev->drv->station.config);
++ wireless_station_create(vif, b.head, s->anonymous ? name : s->e.name);
+ }
+
+ static void
+-config_parse_wireless_station(struct wireless_device *wdev, char *vif, struct uci_section *s)
++config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section *s)
+ {
++ struct wireless_interface *vif;
++ struct uci_element *f;
+ char *name;
+
+ name = alloca(strlen(s->type) + 16);
+ sprintf(name, "@%s[%d]", s->type, config_section_idx(s));
+
+ blob_buf_init(&b, 0);
+- uci_to_blob(&b, s, wdev->drv->station.config);
+- wireless_station_create(wdev, vif, b.head, s->anonymous ? name : s->e.name);
++ uci_to_blob(&b, s, wdev->drv->interface.config);
++ vif = wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name);
++ if (!vif)
++ return;
++
++ vif->vlan_idx = vif->sta_idx = 0;
++ vlist_update(&vif->vlans);
++ vlist_update(&vif->stations);
++
++ if (s->anonymous)
++ goto out;
++
++ uci_foreach_element(&uci_wireless->sections, f) {
++ struct uci_section *cur = uci_to_section(f);
++ const char *vif_name;
++
++ if (strcmp(cur->type, "wifi-vlan") != 0)
++ continue;
++
++ vif_name = uci_lookup_option_string(uci_ctx, cur, "iface");
++ if (vif_name && strcmp(s->e.name, vif_name))
++ continue;
++ config_parse_wireless_vlan(vif, cur);
++ }
++
++ uci_foreach_element(&uci_wireless->sections, f) {
++ struct uci_section *cur = uci_to_section(f);
++ const char *vif_name;
++
++ if (strcmp(cur->type, "wifi-station") != 0)
++ continue;
++
++ vif_name = uci_lookup_option_string(uci_ctx, cur, "iface");
++ if (vif_name && strcmp(s->e.name, vif_name))
++ continue;
++ config_parse_wireless_station(vif, cur);
++ }
++
++out:
++ vlist_flush(&vif->vlans);
++ vlist_flush(&vif->stations);
+ }
+
+ static void
+@@ -623,16 +664,10 @@ config_init_wireless(void)
+ vlist_for_each_element(&wireless_devices, wdev, node) {
+ wdev->vif_idx = 0;
+ vlist_update(&wdev->interfaces);
+- wdev->vlan_idx = 0;
+- vlist_update(&wdev->vlans);
+- wdev->sta_idx = 0;
+- vlist_update(&wdev->stations);
+ }
+
+ uci_foreach_element(&uci_wireless->sections, e) {
+ struct uci_section *s = uci_to_section(e);
+- struct wireless_interface *vif;
+- struct uci_element *f;
+
+ if (strcmp(s->type, "wifi-iface") != 0)
+ continue;
+@@ -647,42 +682,11 @@ config_init_wireless(void)
+ continue;
+ }
+
+- vif = config_parse_wireless_interface(wdev, s);
+-
+- if (!vif || s->anonymous)
+- continue;
+- uci_foreach_element(&uci_wireless->sections, f) {
+- struct uci_section *s = uci_to_section(f);
+- const char *vif_name;
+-
+- if (strcmp(s->type, "wifi-vlan") != 0)
+- continue;
+-
+- vif_name = uci_lookup_option_string(uci_ctx, s, "iface");
+- if (vif_name && strcmp(e->name, vif_name))
+- continue;
+- config_parse_wireless_vlan(wdev, vif->name, s);
+- }
+-
+- uci_foreach_element(&uci_wireless->sections, f) {
+- struct uci_section *s = uci_to_section(f);
+- const char *vif_name;
+-
+- if (strcmp(s->type, "wifi-station") != 0)
+- continue;
+-
+- vif_name = uci_lookup_option_string(uci_ctx, s, "iface");
+- if (vif_name && strcmp(e->name, vif_name))
+- continue;
+- config_parse_wireless_station(wdev, vif->name, s);
+- }
++ config_parse_wireless_interface(wdev, s);
+ }
+
+- vlist_for_each_element(&wireless_devices, wdev, node) {
++ vlist_for_each_element(&wireless_devices, wdev, node)
+ vlist_flush(&wdev->interfaces);
+- vlist_flush(&wdev->vlans);
+- vlist_flush(&wdev->stations);
+- }
+ }
+
+
+--- a/scripts/netifd-wireless.sh
++++ b/scripts/netifd-wireless.sh
+@@ -108,14 +108,16 @@ _wdev_wrapper() {
+ }
+
+ _wdev_notify_init() {
+- local command="$1"
+- local name="$2"
+- local value="$3"
++ local command="$1"; shift;
+
+ json_init
+ json_add_int "command" "$command"
+ json_add_string "device" "$__netifd_device"
+- [ -n "$name" -a -n "$value" ] && json_add_string "$name" "$value"
++ while [ -n "$1" ]; do
++ local name="$1"; shift
++ local value="$1"; shift
++ json_add_string "$name" "$value"
++ done
+ json_add_object "data"
+ }
+
+@@ -151,7 +153,7 @@ _wireless_add_vlan() {
+ local name="$1"; shift
+ local ifname="$1"; shift
+
+- _wdev_notify_init $CMD_SET_DATA "vlan" "$name"
++ _wdev_notify_init $CMD_SET_DATA interface "$__cur_interface" "vlan" "$name"
+ json_add_string "ifname" "$ifname"
+ _wdev_add_variables "$@"
+ _wdev_notify
+@@ -333,6 +335,7 @@ for_each_interface() {
+ continue
+ }
+ fi
++ __cur_interface="$_w_iface"
+ "$@" "$_w_iface"
+ json_select ..
+ done
+--- a/wireless.c
++++ b/wireless.c
+@@ -205,9 +205,7 @@ prepare_config(struct wireless_device *w
+ blobmsg_add_blob(&b, vif->data);
+
+ j = blobmsg_open_table(&b, "vlans");
+- vlist_for_each_element(&wdev->vlans, vlan, node) {
+- if (strcmp(vlan->vif, vif->name))
+- continue;
++ vlist_for_each_element(&vif->vlans, vlan, node) {
+ k = blobmsg_open_table(&b, vlan->name);
+ vif_config_add_bridge(&b, vlan->network, up);
+ put_container(&b, vlan->config, "config");
+@@ -218,9 +216,7 @@ prepare_config(struct wireless_device *w
+ blobmsg_close_table(&b, j);
+
+ j = blobmsg_open_table(&b, "stas");
+- vlist_for_each_element(&wdev->stations, sta, node) {
+- if (strcmp(sta->vif, vif->name))
+- continue;
++ vlist_for_each_element(&vif->stations, sta, node) {
+ k = blobmsg_open_table(&b, sta->name);
+ put_container(&b, sta->config, "config");
+ if (sta->data)
+@@ -311,15 +307,15 @@ wireless_device_free_state(struct wirele
+ free(vif->data);
+ vif->data = NULL;
+ vif->ifname = NULL;
+- }
+- vlist_for_each_element(&wdev->vlans, vlan, node) {
+- free(vlan->data);
+- vlan->data = NULL;
+- vlan->ifname = NULL;
+- }
+- vlist_for_each_element(&wdev->stations, sta, node) {
+- free(sta->data);
+- sta->data = NULL;
++ vlist_for_each_element(&vif->vlans, vlan, node) {
++ free(vlan->data);
++ vlan->data = NULL;
++ vlan->ifname = NULL;
++ }
++ vlist_for_each_element(&vif->stations, sta, node) {
++ free(sta->data);
++ sta->data = NULL;
++ }
+ }
+ }
+
+@@ -510,8 +506,6 @@ wireless_device_free(struct wireless_dev
+ {
+ wireless_handler_stop(wdev);
+ vlist_flush_all(&wdev->interfaces);
+- vlist_flush_all(&wdev->vlans);
+- vlist_flush_all(&wdev->stations);
+ avl_delete(&wireless_devices.avl, &wdev->node.avl);
+ free(wdev->config);
+ free(wdev->prev_config);
+@@ -547,11 +541,12 @@ wireless_device_mark_down(struct wireles
+
+ netifd_log_message(L_NOTICE, "Wireless device '%s' is now down\n", wdev->name);
+
+- vlist_for_each_element(&wdev->vlans, vlan, node)
+- wireless_vlan_handle_link(vlan, false);
+
+- vlist_for_each_element(&wdev->interfaces, vif, node)
++ vlist_for_each_element(&wdev->interfaces, vif, node) {
+ wireless_interface_handle_link(vif, NULL, false);
++ vlist_for_each_element(&vif->vlans, vlan, node)
++ wireless_vlan_handle_link(vlan, false);
++ }
+
+ wireless_process_kill_all(wdev, SIGTERM, true);
+
+@@ -623,10 +618,11 @@ wireless_device_mark_up(struct wireless_
+ netifd_log_message(L_NOTICE, "Wireless device '%s' is now up\n", wdev->name);
+ wdev->retry = WIRELESS_SETUP_RETRY;
+ wdev->state = IFS_UP;
+- vlist_for_each_element(&wdev->interfaces, vif, node)
++ vlist_for_each_element(&wdev->interfaces, vif, node) {
+ wireless_interface_handle_link(vif, NULL, true);
+- vlist_for_each_element(&wdev->vlans, vlan, node)
+- wireless_vlan_handle_link(vlan, true);
++ vlist_for_each_element(&vif->vlans, vlan, node)
++ wireless_vlan_handle_link(vlan, true);
++ }
+ }
+
+ static void
+@@ -848,6 +844,16 @@ wireless_interface_init_config(struct wi
+ vif->multicast_to_unicast = cur ? blobmsg_get_bool(cur) : -1;
+ }
+
++static void
++vif_free(struct wireless_interface *vif)
++{
++ vlist_flush_all(&vif->vlans);
++ vlist_flush_all(&vif->stations);
++ free((void *) vif->section);
++ free(vif->config);
++ free(vif);
++}
++
+ /* vlist update call for wireless interface list */
+ static void
+ vif_update(struct vlist_tree *tree, struct vlist_node *node_new,
+@@ -884,9 +890,7 @@ vif_update(struct vlist_tree *tree, stru
+ } else if (vif_old) {
+ D(WIRELESS, "Delete wireless interface %s on device %s\n", vif_old->name, wdev->name);
+ wireless_interface_handle_link(vif_old, NULL, false);
+- free((void *) vif_old->section);
+- free(vif_old->config);
+- free(vif_old);
++ vif_free(vif_old);
+ }
+
+ wdev->config_update = true;
+@@ -921,14 +925,10 @@ static void
+ vlan_update(struct vlist_tree *tree, struct vlist_node *node_new,
+ struct vlist_node *node_old)
+ {
+- struct wireless_vlan *vlan_old = container_of(node_old, struct wireless_vlan, node);
+- struct wireless_vlan *vlan_new = container_of(node_new, struct wireless_vlan, node);
+- struct wireless_device *wdev;
+-
+- if (vlan_old)
+- wdev = vlan_old->wdev;
+- else
+- wdev = vlan_new->wdev;
++ struct wireless_vlan *vlan_old = container_of_safe(node_old, struct wireless_vlan, node);
++ struct wireless_vlan *vlan_new = container_of_safe(node_new, struct wireless_vlan, node);
++ struct wireless_interface *vif = container_of(tree, struct wireless_interface, vlans);
++ struct wireless_device *wdev = vif->wdev;
+
+ if (vlan_old && vlan_new) {
+ free((void *) vlan_old->section);
+@@ -951,7 +951,7 @@ vlan_update(struct vlist_tree *tree, str
+ vlan_new->config = blob_memdup(vlan_new->config);
+ wireless_vlan_init_config(vlan_new);
+ } else if (vlan_old) {
+- D(WIRELESS, "Delete wireless interface %s on device %s\n", vlan_old->name, wdev->name);
++ D(WIRELESS, "Delete wireless vlan %s on device %s\n", vlan_old->name, wdev->name);
+ wireless_vlan_handle_link(vlan_old, false);
+ free((void *) vlan_old->section);
+ free(vlan_old->config);
+@@ -966,14 +966,10 @@ static void
+ station_update(struct vlist_tree *tree, struct vlist_node *node_new,
+ struct vlist_node *node_old)
+ {
+- struct wireless_station *sta_old = container_of(node_old, struct wireless_station, node);
+- struct wireless_station *sta_new = container_of(node_new, struct wireless_station, node);
+- struct wireless_device *wdev;
+-
+- if (sta_old)
+- wdev = sta_old->wdev;
+- else
+- wdev = sta_new->wdev;
++ struct wireless_station *sta_old = container_of_safe(node_old, struct wireless_station, node);
++ struct wireless_station *sta_new = container_of_safe(node_new, struct wireless_station, node);
++ struct wireless_interface *vif = container_of(tree, struct wireless_interface, stations);
++ struct wireless_device *wdev = vif->wdev;
+
+ if (sta_old && sta_new) {
+ free((void *) sta_old->section);
+@@ -1088,10 +1084,6 @@ wireless_device_create(struct wireless_d
+ INIT_LIST_HEAD(&wdev->script_proc);
+ vlist_init(&wdev->interfaces, avl_strcmp, vif_update);
+ wdev->interfaces.keep_old = true;
+- vlist_init(&wdev->vlans, avl_strcmp, vlan_update);
+- wdev->vlans.keep_old = true;
+- vlist_init(&wdev->stations, avl_strcmp, station_update);
+- wdev->stations.keep_old = true;
+
+ wdev->timeout.cb = wireless_device_setup_timeout;
+ wdev->script_task.cb = wireless_device_script_task_cb;
+@@ -1108,12 +1100,12 @@ wireless_device_create(struct wireless_d
+
+ /* creates a wireless station object. Called by config */
+ void
+-wireless_station_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section)
++wireless_station_create(struct wireless_interface *vif, struct blob_attr *data, const char *section)
+ {
+ struct wireless_station *sta;
+ struct blob_attr *tb[__STA_ATTR_MAX];
+ struct blob_attr *cur;
+- char *name_buf, *vif_buf;
++ char *name_buf;
+ char name[8];
+
+ blobmsg_parse(sta_policy, __STA_ATTR_MAX, tb, blob_data(data), blob_len(data));
+@@ -1122,18 +1114,15 @@ wireless_station_create(struct wireless_
+ if (cur && blobmsg_get_bool(cur))
+ return;
+
+- sprintf(name, "%d", wdev->sta_idx++);
++ sprintf(name, "%d", vif->sta_idx++);
+
+ sta = calloc_a(sizeof(*sta),
+- &name_buf, strlen(name) + 1,
+- &vif_buf, strlen(vif) + 1);
++ &name_buf, strlen(name) + 1);
+ sta->name = strcpy(name_buf, name);
+- sta->vif = strcpy(vif_buf, vif);
+- sta->wdev = wdev;
+ sta->config = data;
+ sta->section = section;
+
+- vlist_add(&wdev->stations, &sta->node, sta->name);
++ vlist_add(&vif->stations, &sta->node, sta->name);
+ }
+
+ /* ubus callback network.wireless.status, runs for every interface, encode the station */
+@@ -1151,12 +1140,12 @@ wireless_station_status(struct wireless_
+
+ /* create a vlan object. Called by config */
+ void
+-wireless_vlan_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section)
++wireless_vlan_create(struct wireless_interface *vif, struct blob_attr *data, const char *section)
+ {
+ struct wireless_vlan *vlan;
+ struct blob_attr *tb[__VLAN_ATTR_MAX];
+ struct blob_attr *cur;
+- char *name_buf, *vif_buf;
++ char *name_buf;
+ char name[8];
+
+ blobmsg_parse(vlan_policy, __VLAN_ATTR_MAX, tb, blob_data(data), blob_len(data));
+@@ -1165,19 +1154,14 @@ wireless_vlan_create(struct wireless_dev
+ if (cur && blobmsg_get_bool(cur))
+ return;
+
+- sprintf(name, "%d", wdev->vlan_idx++);
++ sprintf(name, "%d", vif->vlan_idx++);
+
+- vlan = calloc_a(sizeof(*vlan),
+- &name_buf, strlen(name) + 1,
+- &vif_buf, strlen(vif) + 1);
++ vlan = calloc_a(sizeof(*vlan), &name_buf, strlen(name) + 1);
+ vlan->name = strcpy(name_buf, name);
+- vlan->vif = strcpy(vif_buf, vif);
+- vlan->wdev = wdev;
+ vlan->config = data;
+ vlan->section = section;
+- vlan->isolate = false;
+
+- vlist_add(&wdev->vlans, &vlan->node, vlan->name);
++ vlist_add(&vif->vlans, &vlan->node, vlan->name);
+ }
+
+ /* ubus callback network.wireless.status, runs for every interface, encode the vlan informations */
+@@ -1220,6 +1204,12 @@ struct wireless_interface* wireless_inte
+ vif->section = section;
+ vif->isolate = false;
+
++ vlist_init(&vif->vlans, avl_strcmp, vlan_update);
++ vif->vlans.keep_old = true;
++
++ vlist_init(&vif->stations, avl_strcmp, station_update);
++ vif->stations.keep_old = true;
++
+ vlist_add(&wdev->interfaces, &vif->node, vif->name);
+
+ return vlist_find(&wdev->interfaces, name, vif, node);
+@@ -1240,14 +1230,12 @@ wireless_interface_status(struct wireles
+ blobmsg_add_string(b, "ifname", iface->ifname);
+ put_container(b, iface->config, "config");
+ j = blobmsg_open_array(b, "vlans");
+- vlist_for_each_element(&iface->wdev->vlans, vlan, node)
+- if (!strcmp(iface->name, vlan->vif))
+- wireless_vlan_status(vlan, b);
++ vlist_for_each_element(&iface->vlans, vlan, node)
++ wireless_vlan_status(vlan, b);
+ blobmsg_close_array(b, j);
+ j = blobmsg_open_array(b, "stations");
+- vlist_for_each_element(&iface->wdev->stations, sta, node)
+- if (!strcmp(iface->name, sta->vif))
+- wireless_station_status(sta, b);
++ vlist_for_each_element(&iface->stations, sta, node)
++ wireless_station_status(sta, b);
+ blobmsg_close_array(b, j);
+ blobmsg_close_table(b, i);
+ }
+@@ -1496,7 +1484,9 @@ wireless_device_notify(struct wireless_d
+ }
+
+ if ((cur = tb[NOTIFY_ATTR_VLAN]) != NULL) {
+- vlan = vlist_find(&wdev->vlans, blobmsg_data(cur), vlan, node);
++ if (!vif)
++ return UBUS_STATUS_NOT_FOUND;
++ vlan = vlist_find(&vif->vlans, blobmsg_data(cur), vlan, node);
+ if (!vlan)
+ return UBUS_STATUS_NOT_FOUND;
+ }
+@@ -1516,19 +1506,19 @@ wireless_device_notify(struct wireless_d
+ wireless_device_mark_up(wdev);
+ break;
+ case NOTIFY_CMD_SET_DATA:
+- if (vif)
+- pdata = &vif->data;
+- else if (vlan)
++ if (vlan)
+ pdata = &vlan->data;
++ else if (vif)
++ pdata = &vif->data;
+ else
+ pdata = &wdev->data;
+
+ free(*pdata);
+ *pdata = blob_memdup(cur);
+- if (vif)
+- wireless_interface_set_data(vif);
+- else if (vlan)
++ if (vlan)
+ wireless_vlan_set_data(vlan);
++ else if (vif)
++ wireless_interface_set_data(vif);
+ break;
+ case NOTIFY_CMD_PROCESS_ADD:
+ return wireless_device_add_process(wdev, cur);
+--- a/wireless.h
++++ b/wireless.h
+@@ -44,8 +44,6 @@ struct wireless_device {
+
+ struct wireless_driver *drv;
+ struct vlist_tree interfaces;
+- struct vlist_tree vlans;
+- struct vlist_tree stations;
+ char *name;
+
+ struct netifd_process script_task;
+@@ -73,8 +71,6 @@ struct wireless_device {
+ int retry;
+
+ int vif_idx;
+- int vlan_idx;
+- int sta_idx;
+ };
+
+ struct wireless_interface {
+@@ -82,6 +78,8 @@ struct wireless_interface {
+ const char *section;
+ char *name;
+
++ struct vlist_tree vlans;
++ struct vlist_tree stations;
+ struct wireless_device *wdev;
+
+ struct blob_attr *config;
+@@ -94,6 +92,8 @@ struct wireless_interface {
+ bool isolate;
+ bool ap_mode;
+ int multicast_to_unicast;
++ int vlan_idx;
++ int sta_idx;
+ };
+
+ struct wireless_vlan {
+@@ -101,9 +101,6 @@ struct wireless_vlan {
+ const char *section;
+ char *name;
+
+- struct wireless_device *wdev;
+- char *vif;
+-
+ struct blob_attr *config;
+ struct blob_attr *data;
+
+@@ -119,9 +116,6 @@ struct wireless_station {
+ const char *section;
+ char *name;
+
+- struct wireless_device *wdev;
+- char *vif;
+-
+ struct blob_attr *config;
+ struct blob_attr *data;
+ };
+@@ -143,8 +137,8 @@ void wireless_device_reconf(struct wirel
+ void wireless_device_status(struct wireless_device *wdev, struct blob_buf *b);
+ void wireless_device_get_validate(struct wireless_device *wdev, struct blob_buf *b);
+ struct wireless_interface* wireless_interface_create(struct wireless_device *wdev, struct blob_attr *data, const char *section);
+-void wireless_vlan_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section);
+-void wireless_station_create(struct wireless_device *wdev, char *vif, struct blob_attr *data, const char *section);
++void wireless_vlan_create(struct wireless_interface *vif, struct blob_attr *data, const char *section);
++void wireless_station_create(struct wireless_interface *vif, struct blob_attr *data, const char *section);
+ int wireless_device_notify(struct wireless_device *wdev, struct blob_attr *data,
+ struct ubus_request_data *req);
+
--
2.39.2

View File

@@ -381,9 +381,9 @@ index 65ae662c4d..90d9210410 100644
# Here we make the assumption that if we're in open mode
# with WPS enabled, we got to be in unconfigured state.
wps_not_configured=1
+ vlan_possible=1
+ [ "$macfilter" = radius ] && {
+ append_radius_server
+ vlan_possible=1
+ }
;;
psk|sae|psk-sae)

26
profiles/cig_wf186h.yml Normal file
View File

@@ -0,0 +1,26 @@
---
profile: cig_wf186h
target: ipq807x
subtarget: ipq50xx
description: Build image for the Cigtech Wall Plate WF186h
image: bin/targets/ipq807x/ipq50xx/openwrt-ipq807x-cig_wf186h-squashfs-sysupgrade.tar
feeds:
- name: ipq807x
path: ../../feeds/ipq807x
include:
- wifi-ax
- ucentral-ap
packages:
- ipq807x
- ath11k-fwtest
- ftm
diffconfig: |
CONFIG_PACKAGE_i2c-tools=y
CONFIG_PACKAGE_libi2c=y
CONFIG_PACKAGE_coreutils=y
CONFIG_PACKAGE_coreutils-stty=y
CONFIG_PACKAGE_kmod-switch-rtl8366-smi=y
CONFIG_PACKAGE_kmod-switch-rtl8367c=y