mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-10-31 02:17:58 +00:00 
			
		
		
		
	Compare commits
	
		
			36 Commits
		
	
	
		
			v2.11.0-rc
			...
			v2.11.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | bb5d3ecd2d | ||
|   | d9f237b450 | ||
|   | 4f5a3b0c2b | ||
|   | dd41f15987 | ||
|   | 007cfe9c16 | ||
|   | 52884b2835 | ||
|   | 6a6af16f48 | ||
|   | 2818722b19 | ||
|   | 194eba2d21 | ||
|   | 3d41a22fba | ||
|   | acd4b79dd4 | ||
|   | befac1e065 | ||
|   | 7e4e221ccb | ||
|   | 1d9b69ee6f | ||
|   | 018f20119d | ||
|   | 9a6e41adb8 | ||
|   | 970b22856f | ||
|   | 95032994fe | ||
|   | 48cda63dc5 | ||
|   | 8e9f79964a | ||
|   | 3c7df86373 | ||
|   | 38e6aee074 | ||
|   | 0a13684bb6 | ||
|   | e7ca6e8455 | ||
|   | f17e635d34 | ||
|   | 90e78c6068 | ||
|   | 550bb6fb7e | ||
|   | b3a0ebe534 | ||
|   | 6d16e50bbe | ||
|   | 513eec1c5f | ||
|   | 6a797e8a64 | ||
|   | 082134bc43 | ||
|   | 03ec2de777 | ||
|   | 989d39d1f2 | ||
|   | b6b298ad68 | ||
|   | be1cb862f1 | 
| @@ -18,7 +18,7 @@ DEFAULT_PACKAGES += kmod-qca-nss-dp kmod-qca-ssdk swconfig \ | |||||||
| 	kmod-usb-phy-ipq807x kmod-usb-dwc3-of-simple \ | 	kmod-usb-phy-ipq807x kmod-usb-dwc3-of-simple \ | ||||||
| 	kmod-ath11k-ahb kmod-qrtr_mproc wpad \ | 	kmod-ath11k-ahb kmod-qrtr_mproc wpad \ | ||||||
| 	kmod-gpio-button-hotplug kmod-bootconfig \ | 	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 | 	uboot-envtools | ||||||
|  |  | ||||||
| $(eval $(call BuildTarget)) | $(eval $(call BuildTarget)) | ||||||
|   | |||||||
| @@ -64,8 +64,11 @@ qcom_setup_interfaces() | |||||||
| 		ucidef_set_interface_wan "eth0"		 | 		ucidef_set_interface_wan "eth0"		 | ||||||
| 		;; | 		;; | ||||||
|        cig,wf186w) |        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) | 	yuncore,fap650) | ||||||
| 		ucidef_set_interface_lan "eth3 eth2 eth1 eth0" | 		ucidef_set_interface_lan "eth3 eth2 eth1 eth0" | ||||||
| 		ucidef_set_interface_wan "eth4" | 		ucidef_set_interface_wan "eth4" | ||||||
| @@ -180,6 +183,15 @@ qcom_setup_macs() | |||||||
| 	       # ip link set eth1 address $wan_mac | 	       # ip link set eth1 address $wan_mac | ||||||
| 	       # ucidef_set_label_macaddr $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-a1|\ | ||||||
| 	cybertan,eww631-b1) | 	cybertan,eww631-b1) | ||||||
| 		mac=$(grep -i -m 1 BaseMacAddress= /dev/`cat /proc/mtd | grep APPSBLENV | cut -d: -f1` | cut -d= -f2) | 		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 | 		ucidef_set_label_macaddr $wan_mac | ||||||
| 		;; | 		;; | ||||||
| 	cig,wf660a) | 	cig,wf660a) | ||||||
| 		mmc_dev=$(echo $(find_mmc_part "0:APPSBLENV") | sed 's/^.\{5\}//') | 		mmc_dev=$(find_mtd_chardev "0:APPSBLENV") | ||||||
| 		[ -z mmc_dev ] && return | 		[ -z "$mmc_dev" ] && mmc_dev=$(find_mmc_part "0:APPSBLENV") | ||||||
| 		mac=$(grep BaseMacAddress= /dev/$mmc_dev | cut -dx -f2) | 		[ -z "$mmc_dev" ] && return | ||||||
|  | 		mac=$(grep BaseMacAddress= $mmc_dev | cut -dx -f2) | ||||||
| 		[ -z "$mac" ] && return; | 		[ -z "$mac" ] && return; | ||||||
| 		wan_mac=$(macaddr_canonicalize $mac) | 		wan_mac=$(macaddr_canonicalize $mac) | ||||||
| 		ucidef_set_network_device_mac eth0 $wan_mac | 		ucidef_set_network_device_mac eth0 $wan_mac | ||||||
|   | |||||||
| @@ -61,8 +61,9 @@ ath11k_generate_macs_pax1800() { | |||||||
|  |  | ||||||
| ath11k_generate_macs_wf660a() { | ath11k_generate_macs_wf660a() { | ||||||
| 	touch /lib/firmware/ath11k-macs | 	touch /lib/firmware/ath11k-macs | ||||||
| 	mmc_dev=$(find_mmc_part 0:APPSBLENV) | 	mmc_dev=$(find_mtd_chardev "0:APPSBLENV") | ||||||
| 	[ -n $mmc_dev ] && mac=$(grep BaseMacAddress= $mmc_dev | cut -dx -f2) | 	[ -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) | 	eth=$(macaddr_canonicalize $mac) | ||||||
| 	mac1=$(macaddr_add $eth 1) | 	mac1=$(macaddr_add $eth 1) | ||||||
| 	mac2=$(macaddr_add $eth 2) | 	mac2=$(macaddr_add $eth 2) | ||||||
| @@ -85,6 +86,19 @@ ath11k_generate_macs_wf186w() { | |||||||
| 	echo -ne \\x${mac3//:/\\x} >> /lib/firmware/ath11k-macs | 	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() { | caldata_die() { | ||||||
| 	echo "caldata: " "$*" | 	echo "caldata: " "$*" | ||||||
| @@ -159,6 +173,7 @@ case "$FIRMWARE" in | |||||||
| ath11k/IPQ5018/hw1.0/caldata.bin) | ath11k/IPQ5018/hw1.0/caldata.bin) | ||||||
| 	case "$board" in | 	case "$board" in | ||||||
| 	cig,wf186w|\ | 	cig,wf186w|\ | ||||||
|  | 	cig,wf186h|\ | ||||||
| 	cybertan,eww622-a1|\ | 	cybertan,eww622-a1|\ | ||||||
| 	cybertan,eww631-a1|\ | 	cybertan,eww631-a1|\ | ||||||
| 	cybertan,eww631-b1|\ | 	cybertan,eww631-b1|\ | ||||||
| @@ -180,6 +195,7 @@ ath11k/IPQ5018/hw1.0/caldata.bin) | |||||||
| ath11k/qcn6122/hw1.0/caldata_1.bin) | ath11k/qcn6122/hw1.0/caldata_1.bin) | ||||||
| 	case "$board" in | 	case "$board" in | ||||||
| 	cig,wf186w|\ | 	cig,wf186w|\ | ||||||
|  | 	cig,wf186h|\ | ||||||
| 	wallys,dr5018|\ | 	wallys,dr5018|\ | ||||||
| 	hfcl,ion4xi_w|\ | 	hfcl,ion4xi_w|\ | ||||||
| 	hfcl,ion4x_w|\ | 	hfcl,ion4x_w|\ | ||||||
| @@ -269,6 +285,9 @@ ath11k-macs) | |||||||
| 	cig,wf186w) | 	cig,wf186w) | ||||||
| 		ath11k_generate_macs_wf186w | 		ath11k_generate_macs_wf186w | ||||||
| 		;; | 		;; | ||||||
|  | 	cig,wf186h) | ||||||
|  | 		ath11k_generate_macs_wf186h | ||||||
|  | 		;; | ||||||
| 	esac | 	esac | ||||||
| 	;; | 	;; | ||||||
| *) | *) | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								feeds/ipq807x/ipq807x/base-files/etc/hotplug.d/net/50-dvlan
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								feeds/ipq807x/ipq807x/base-files/etc/hotplug.d/net/50-dvlan
									
									
									
									
									
										Normal 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 | ||||||
| @@ -52,7 +52,7 @@ do_flash_emmc() { | |||||||
| 	tar Oxf $tar_file ${board_dir}/$part | dd of=${emmcblock} | 	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 tar_file="$1" | ||||||
|  |  | ||||||
| 	local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$') | 	local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$') | ||||||
| @@ -84,11 +84,17 @@ emmc_do_upgrade_bootconfig() { | |||||||
| 	fi | 	fi | ||||||
|  |  | ||||||
| 	for part in "0:BOOTCONFIG" "0:BOOTCONFIG1"; do | 	for part in "0:BOOTCONFIG" "0:BOOTCONFIG1"; do | ||||||
| 		local emmcblock=$(find_mmc_part $part) |                local mtdchar=$(echo $(find_mtd_chardev $part) | sed 's/^.\{5\}//') | ||||||
| 		echo erase ${emmcblock} |                if [ -n "$mtdchar" ]; then | ||||||
| 		dd if=/dev/zero of=${emmcblock} 2> /dev/null |                        echo start to update $mtdchar | ||||||
| 		echo update $emmcblock |                        mtd -qq write /proc/boot_info/getbinary_bootconfig "/dev/${mtdchar}" 2>/dev/null && echo update mtd $mtdchar | ||||||
| 		dd if=/tmp/bootconfig of=${emmcblock} 2> /dev/null |                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 | 	done | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -111,6 +117,7 @@ platform_check_image() { | |||||||
| 	board=$(board_name) | 	board=$(board_name) | ||||||
| 	case $board in | 	case $board in | ||||||
| 	cig,wf186w|\ | 	cig,wf186w|\ | ||||||
|  | 	cig,wf186h|\ | ||||||
| 	cig,wf188|\ | 	cig,wf188|\ | ||||||
| 	cig,wf660a|\ | 	cig,wf660a|\ | ||||||
| 	cig,wf188n|\ | 	cig,wf188n|\ | ||||||
| @@ -174,7 +181,7 @@ platform_do_upgrade() { | |||||||
| 		qca_do_upgrade $1 | 		qca_do_upgrade $1 | ||||||
| 		;; | 		;; | ||||||
| 	cig,wf660a) | 	cig,wf660a) | ||||||
| 		emmc_do_upgrade_bootconfig $1 | 		spi_nor_emmc_do_upgrade_bootconfig $1 | ||||||
| 		;; | 		;; | ||||||
| 	motorola,q14) | 	motorola,q14) | ||||||
| 		emmc_do_upgrade $1 | 		emmc_do_upgrade $1 | ||||||
| @@ -267,6 +274,7 @@ platform_do_upgrade() { | |||||||
| 		platform_do_upgrade_dualboot_datachk "$1" | 		platform_do_upgrade_dualboot_datachk "$1" | ||||||
| 		;; | 		;; | ||||||
| 	cig,wf186w|\ | 	cig,wf186w|\ | ||||||
|  | 	cig,wf186h|\ | ||||||
| 	yuncore,ax840|\ | 	yuncore,ax840|\ | ||||||
| 	yuncore,fap655) | 	yuncore,fap655) | ||||||
| 		[ -f /proc/boot_info/rootfs/upgradepartition ] && { | 		[ -f /proc/boot_info/rootfs/upgradepartition ] && { | ||||||
|   | |||||||
| @@ -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"; | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
| @@ -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"; | ||||||
|  | }; | ||||||
| @@ -28,6 +28,15 @@ define Device/cig_wf186w | |||||||
| endef | endef | ||||||
| TARGET_DEVICES += cig_wf186w | 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 | define Device/cybertan_eww622_a1 | ||||||
|   DEVICE_TITLE := CyberTan EWW622-A1 |   DEVICE_TITLE := CyberTan EWW622-A1 | ||||||
|   DEVICE_DTS := qcom-ipq5018-eww622-a1 |   DEVICE_DTS := qcom-ipq5018-eww622-a1 | ||||||
|   | |||||||
| @@ -82,7 +82,7 @@ CONFIG_MIGRATION=y | |||||||
| CONFIG_MPILIB=y | CONFIG_MPILIB=y | ||||||
| CONFIG_MSM_SECURE_BUFFER=y | CONFIG_MSM_SECURE_BUFFER=y | ||||||
| CONFIG_NEED_SG_DMA_LENGTH=y | CONFIG_NEED_SG_DMA_LENGTH=y | ||||||
| CONFIG_NET_SWITCHDEV=y | # CONFIG_NET_SWITCHDEV is not set | ||||||
| CONFIG_NUM_ALT_PARTITION=16 | CONFIG_NUM_ALT_PARTITION=16 | ||||||
| CONFIG_OF_IOMMU=y | CONFIG_OF_IOMMU=y | ||||||
| CONFIG_OID_REGISTRY=y | CONFIG_OID_REGISTRY=y | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ CONFIG_ARCH_IPQ807x=y | |||||||
| CONFIG_IPQ_ADSS_807x=y | CONFIG_IPQ_ADSS_807x=y | ||||||
| CONFIG_IPQ_APSS_807x=y | CONFIG_IPQ_APSS_807x=y | ||||||
| CONFIG_IPQ_GCC_807x=y | CONFIG_IPQ_GCC_807x=y | ||||||
| CONFIG_NET_SWITCHDEV=y | # CONFIG_NET_SWITCHDEV is not set | ||||||
| CONFIG_NUM_ALT_PARTITION=16 | CONFIG_NUM_ALT_PARTITION=16 | ||||||
| CONFIG_PINCTRL_IPQ807x=y | CONFIG_PINCTRL_IPQ807x=y | ||||||
| # CONFIG_IPC_LOGGING is not set | # CONFIG_IPC_LOGGING is not set | ||||||
|   | |||||||
| @@ -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; | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| import * as nl80211 from "nl80211"; | import * as nl80211 from "nl80211"; | ||||||
| import * as rtnl from "rtnl"; | import * as rtnl from "rtnl"; | ||||||
| import { readfile } from "fs"; | import { readfile, glob, basename, readlink } from "fs"; | ||||||
|  |  | ||||||
| const iftypes = { | const iftypes = { | ||||||
| 	ap: nl80211.const.NL80211_IFTYPE_AP, | 	ap: nl80211.const.NL80211_IFTYPE_AP, | ||||||
| @@ -94,6 +94,156 @@ function wdev_create(phy, name, data) | |||||||
| 	return null; | 	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 = { | const vlist_proto = { | ||||||
| 	update: function(values, arg) { | 	update: function(values, arg) { | ||||||
| 		let data = this.data; | 		let data = this.data; | ||||||
| @@ -150,7 +300,7 @@ function is_equal(val1, val2) { | |||||||
| 			if (!is_equal(val1[key], val2[key])) | 			if (!is_equal(val1[key], val2[key])) | ||||||
| 				return false; | 				return false; | ||||||
| 		for (let key in val2) | 		for (let key in val2) | ||||||
| 			if (!val1[key]) | 			if (val1[key] == null) | ||||||
| 				return false; | 				return false; | ||||||
| 		return true; | 		return true; | ||||||
| 	} else { | 	} else { | ||||||
| @@ -165,4 +315,4 @@ function vlist_new(cb) { | |||||||
| 		}, vlist_proto); | 		}, 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 }; | ||||||
|   | |||||||
| @@ -725,8 +725,7 @@ hostapd_set_bss_options() { | |||||||
| 		[ -n "$wpa_strict_rekey" ] && append bss_conf "wpa_strict_rekey=$wpa_strict_rekey" "$N" | 		[ -n "$wpa_strict_rekey" ] && append bss_conf "wpa_strict_rekey=$wpa_strict_rekey" "$N" | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	set_default nasid "${macaddr//\:}" | 	[ -n "$nasid" ] && append bss_conf "nas_identifier=$nasid" "$N" | ||||||
| 	append bss_conf "nas_identifier=$nasid" "$N" |  | ||||||
|  |  | ||||||
| 	[ -n "$acct_server" ] && { | 	[ -n "$acct_server" ] && { | ||||||
| 		append bss_conf "acct_server_addr=$acct_server" "$N" | 		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 | 			# Here we make the assumption that if we're in open mode | ||||||
| 			# with WPS enabled, we got to be in unconfigured state. | 			# with WPS enabled, we got to be in unconfigured state. | ||||||
| 			wps_not_configured=1 | 			wps_not_configured=1 | ||||||
|  | 			vlan_possible=1 | ||||||
| 			[ "$macfilter" = radius ] && { | 			[ "$macfilter" = radius ] && { | ||||||
| 				append_radius_server | 				append_radius_server | ||||||
| 				vlan_possible=1 |  | ||||||
| 			} | 			} | ||||||
| 		;; | 		;; | ||||||
| 		psk|sae|psk-sae) | 		psk|sae|psk-sae) | ||||||
| @@ -795,6 +794,9 @@ hostapd_set_bss_options() { | |||||||
| 			[ "$eapol_version" -ge "1" -a "$eapol_version" -le "2" ] && append bss_conf "eapol_version=$eapol_version" "$N" | 			[ "$eapol_version" -ge "1" -a "$eapol_version" -le "2" ] && append bss_conf "eapol_version=$eapol_version" "$N" | ||||||
|  |  | ||||||
| 			set_default dynamic_vlan 0 | 			set_default dynamic_vlan 0 | ||||||
|  | 			[ "$macfilter" = radius ] && { | ||||||
|  | 				append_radius_server | ||||||
|  | 			} | ||||||
| 			vlan_possible=1 | 			vlan_possible=1 | ||||||
| 			wps_possible=1 | 			wps_possible=1 | ||||||
| 		;; | 		;; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| let libubus = require("ubus"); | let libubus = require("ubus"); | ||||||
| import { open, readfile } from "fs"; | 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(); | let ubus = libubus.connect(); | ||||||
|  |  | ||||||
| @@ -26,12 +26,11 @@ function iface_remove(cfg) | |||||||
| 	if (!cfg || !cfg.bss || !cfg.bss[0] || !cfg.bss[0].ifname) | 	if (!cfg || !cfg.bss || !cfg.bss[0] || !cfg.bss[0].ifname) | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
| 	hostapd.remove_iface(cfg.bss[0].ifname); |  | ||||||
| 	for (let bss in cfg.bss) | 	for (let bss in cfg.bss) | ||||||
| 		wdev_remove(bss.ifname); | 		wdev_remove(bss.ifname); | ||||||
| } | } | ||||||
|  |  | ||||||
| function iface_gen_config(phy, config) | function iface_gen_config(phy, config, start_disabled) | ||||||
| { | { | ||||||
| 	let str = `data: | 	let str = `data: | ||||||
| ${join("\n", config.radio.data)} | ${join("\n", config.radio.data)} | ||||||
| @@ -41,18 +40,93 @@ channel=${config.radio.channel} | |||||||
| 	for (let i = 0; i < length(config.bss); i++) { | 	for (let i = 0; i < length(config.bss); i++) { | ||||||
| 		let bss = config.bss[i]; | 		let bss = config.bss[i]; | ||||||
| 		let type = i > 0 ? "bss" : "interface"; | 		let type = i > 0 ? "bss" : "interface"; | ||||||
|  | 		let nasid = bss.nasid ?? replace(bss.bssid, ":", ""); | ||||||
|  |  | ||||||
| 		str += ` | 		str += ` | ||||||
| ${type}=${bss.ifname} | ${type}=${bss.ifname} | ||||||
|  | bssid=${bss.bssid} | ||||||
| ${join("\n", bss.data)} | ${join("\n", bss.data)} | ||||||
|  | nas_identifier=${nasid} | ||||||
|  | `; | ||||||
|  | 		if (start_disabled) | ||||||
|  | 			str += ` | ||||||
|  | start_disabled=1 | ||||||
| `; | `; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return str; | 	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=${phy}:${config_inline}`); | ||||||
|  | 	if (ret < 0) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
|  | 	if (!phy_status) | ||||||
|  | 		return true; | ||||||
|  |  | ||||||
|  | 	let iface = hostapd.interfaces[phy]; | ||||||
|  | 	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; | ||||||
|  |  | ||||||
|  | 	hostapd.remove_iface(phy); | ||||||
| 	iface_remove(old_config); | 	iface_remove(old_config); | ||||||
| 	iface_remove(config); | 	iface_remove(config); | ||||||
|  |  | ||||||
| @@ -61,15 +135,29 @@ function iface_restart(phy, config, old_config) | |||||||
| 		return; | 		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 bss = config.bss[0]; | ||||||
| 	let err = wdev_create(phy, bss.ifname, { mode: "ap" }); | 	let err = wdev_create(phy, bss.ifname, { mode: "ap" }); | ||||||
| 	if (err) | 	if (err) | ||||||
| 		hostapd.printf(`Failed to create ${bss.ifname} on phy ${phy}: ${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 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 }); | 	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}`); | 		hostapd.printf(`hostapd.add_iface failed for phy ${phy} ifname=${bss.ifname}`); | ||||||
| 	ubus.call("wpa_supplicant", "phy_set_state", { phy: phy, stop: false }); | 	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}`); | 	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)) | 	if (!old_config || !is_equal(old_config.radio, config.radio)) | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| @@ -122,82 +267,230 @@ function iface_reload_config(phy, config, old_config) | |||||||
| 	if (!old_config.bss || !old_config.bss[0]) | 	if (!old_config.bss || !old_config.bss[0]) | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| 	if (config.bss[0].ifname != old_config.bss[0].ifname) | 	let iface = hostapd.interfaces[phy]; | ||||||
| 		return false; | 	if (!iface) { | ||||||
|  | 		hostapd.printf(`Could not find previous interface ${iface_name}`); | ||||||
| 	let iface_name = config.bss[0].ifname; |  | ||||||
| 	let iface = hostapd.interfaces[iface_name]; |  | ||||||
| 	if (!iface) |  | ||||||
| 		return false; | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	let iface_name = old_config.bss[0].ifname; | ||||||
| 	let first_bss = hostapd.bss[iface_name]; | 	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; | 		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); | 	let config_inline = iface_gen_config(phy, config); | ||||||
|  |  | ||||||
| 	bss_reload_psk(first_bss, config.bss[0], old_config.bss[0]); | 	// Step 7: fill in the gaps with new interfaces | ||||||
| 	if (!is_equal(config.bss[0], old_config.bss[0])) { | 	for (let i = 0; i < length(config.bss); i++) { | ||||||
| 		if (phy_is_fullmac(phy)) | 		let ifname = config.bss[i].ifname; | ||||||
| 			return false; | 		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; | 			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}'`); | 		hostapd.printf(`Reload config for bss '${config.bss[0].ifname}' on phy '${phy}'`); | ||||||
| 		if (first_bss.set_config(config_inline, 0) < 0) { | 		if (bss.set_config(config_inline, i) < 0) { | ||||||
| 			hostapd.printf(`Failed to set config`); | 			hostapd.printf(`Failed to set config for bss ${ifname}`); | ||||||
| 			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`); |  | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -205,23 +498,47 @@ function iface_reload_config(phy, config, old_config) | |||||||
| 	return true; | 	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) | function iface_set_config(phy, config) | ||||||
| { | { | ||||||
| 	let old_config = hostapd.data.config[phy]; | 	let old_config = hostapd.data.config[phy]; | ||||||
|  |  | ||||||
| 	hostapd.data.config[phy] = config; | 	hostapd.data.config[phy] = config; | ||||||
|  |  | ||||||
| 	if (!config) | 	if (!config) { | ||||||
|  | 		hostapd.remove_iface(phy); | ||||||
| 		return iface_remove(old_config); | 		return iface_remove(old_config); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	let ret = iface_reload_config(phy, config, old_config); | 	let phydev = phy_open(phy); | ||||||
| 	if (ret) { | 	if (!phydev) { | ||||||
| 		hostapd.printf(`Reloaded settings for phy ${phy}`); | 		hostapd.printf(`Failed to open phy ${phy}`); | ||||||
| 		return 0; | 		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}`); | 	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) | function config_add_bss(config, name) | ||||||
| @@ -268,16 +585,28 @@ function iface_load_config(filename) | |||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		if (val[0] == "#num_global_macaddr" || | ||||||
|  | 		    val[0] == "mbssid") | ||||||
|  | 			config[val[0]] = int(val[1]); | ||||||
|  |  | ||||||
| 		push(config.radio.data, line); | 		push(config.radio.data, line); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	while ((line = trim(f.read("line"))) != null) { | 	while ((line = trim(f.read("line"))) != null) { | ||||||
|  | 		if (line == "#default_macaddr") | ||||||
|  | 			bss.default_macaddr = true; | ||||||
|  |  | ||||||
| 		let val = split(line, "=", 2); | 		let val = split(line, "=", 2); | ||||||
| 		if (!val[0]) | 		if (!val[0]) | ||||||
| 			continue; | 			continue; | ||||||
|  |  | ||||||
| 		if (val[0] == "bssid") | 		if (val[0] == "bssid") { | ||||||
| 			bss.bssid = val[1]; | 			bss.bssid = lc(val[1]); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (val[0] == "nas_identifier") | ||||||
|  | 			bss.nasid = val[1]; | ||||||
|  |  | ||||||
| 		if (val[0] == "bss") { | 		if (val[0] == "bss") { | ||||||
| 			bss = config_add_bss(config, val[1]); | 			bss = config_add_bss(config, val[1]); | ||||||
| @@ -294,28 +623,33 @@ function iface_load_config(filename) | |||||||
| 	return config; | 	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 = { | let main_obj = { | ||||||
| 	reload: { | 	reload: { | ||||||
| 		args: { | 		args: { | ||||||
| 			phy: "", | 			phy: "", | ||||||
| 		}, | 		}, | ||||||
| 		call: function(req) { | 		call: ex_wrap(function(req) { | ||||||
| 			try { | 			let phy_list = req.args.phy ? [ req.args.phy ] : keys(hostapd.data.config); | ||||||
| 				let phy_list = req.args.phy ? [ req.args.phy ] : keys(hostapd.data.config); | 			for (let phy_name in phy_list) { | ||||||
| 				for (let phy_name in phy_list) { | 				let phy = hostapd.data.config[phy_name]; | ||||||
| 					let phy = hostapd.data.config[phy_name]; | 				let config = iface_load_config(phy.orig_file); | ||||||
| 					let config = iface_load_config(phy.orig_file); | 				iface_set_config(phy_name, config); | ||||||
| 					iface_set_config(phy_name, config); |  | ||||||
| 				} |  | ||||||
| 			} catch(e) { |  | ||||||
| 				hostapd.printf(`Error reloading config: ${e}\n${e.stacktrace[0].context}`); |  | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; |  | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} | 		}) | ||||||
| 	}, | 	}, | ||||||
| 	apsta_state: { | 	apsta_state: { | ||||||
| 		args: { | 		args: { | ||||||
| @@ -326,7 +660,7 @@ let main_obj = { | |||||||
| 			csa: true, | 			csa: true, | ||||||
| 			csa_count: 0, | 			csa_count: 0, | ||||||
| 		}, | 		}, | ||||||
| 		call: function(req) { | 		call: ex_wrap(function(req) { | ||||||
| 			if (req.args.up == null || !req.args.phy) | 			if (req.args.up == null || !req.args.phy) | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; | 				return libubus.STATUS_INVALID_ARGUMENT; | ||||||
|  |  | ||||||
| @@ -335,7 +669,7 @@ let main_obj = { | |||||||
| 			if (!config || !config.bss || !config.bss[0] || !config.bss[0].ifname) | 			if (!config || !config.bss || !config.bss[0] || !config.bss[0].ifname) | ||||||
| 				return 0; | 				return 0; | ||||||
|  |  | ||||||
| 			let iface = hostapd.interfaces[config.bss[0].ifname]; | 			let iface = hostapd.interfaces[phy]; | ||||||
| 			if (!iface) | 			if (!iface) | ||||||
| 				return 0; | 				return 0; | ||||||
|  |  | ||||||
| @@ -344,34 +678,10 @@ let main_obj = { | |||||||
| 				return 0; | 				return 0; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			let freq = req.args.frequency; | 			if (!req.args.frequency) | ||||||
| 			if (!freq) |  | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; | 				return libubus.STATUS_INVALID_ARGUMENT; | ||||||
|  |  | ||||||
| 			let sec_offset = req.args.sec_chan_offset; | 			let freq_info = iface_freq_info(iface, config, req.args); | ||||||
| 			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); |  | ||||||
| 			if (!freq_info) | 			if (!freq_info) | ||||||
| 				return libubus.STATUS_UNKNOWN_ERROR; | 				return libubus.STATUS_UNKNOWN_ERROR; | ||||||
|  |  | ||||||
| @@ -380,14 +690,34 @@ let main_obj = { | |||||||
| 				freq_info.csa_count = req.args.csa_count ?? 10; | 				freq_info.csa_count = req.args.csa_count ?? 10; | ||||||
| 				ret = iface.switch_channel(freq_info); | 				ret = iface.switch_channel(freq_info); | ||||||
| 			} else { | 			} else { | ||||||
| 				iface.stop(); |  | ||||||
| 				ret = iface.start(freq_info); | 				ret = iface.start(freq_info); | ||||||
| 			} | 			} | ||||||
| 			if (!ret) | 			if (!ret) | ||||||
| 				return libubus.STATUS_UNKNOWN_ERROR; | 				return libubus.STATUS_UNKNOWN_ERROR; | ||||||
|  |  | ||||||
| 			return 0; | 			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: { | 	config_set: { | ||||||
| 		args: { | 		args: { | ||||||
| @@ -395,7 +725,7 @@ let main_obj = { | |||||||
| 			config: "", | 			config: "", | ||||||
| 			prev_config: "", | 			prev_config: "", | ||||||
| 		}, | 		}, | ||||||
| 		call: function(req) { | 		call: ex_wrap(function(req) { | ||||||
| 			let phy = req.args.phy; | 			let phy = req.args.phy; | ||||||
| 			let file = req.args.config; | 			let file = req.args.config; | ||||||
| 			let prev_file = req.args.prev_config; | 			let prev_file = req.args.prev_config; | ||||||
| @@ -403,34 +733,29 @@ let main_obj = { | |||||||
| 			if (!phy) | 			if (!phy) | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; | 				return libubus.STATUS_INVALID_ARGUMENT; | ||||||
|  |  | ||||||
| 			try { | 			if (prev_file && !hostapd.data.config[phy]) { | ||||||
| 				if (prev_file && !hostapd.data.config[phy]) { | 				let config = iface_load_config(prev_file); | ||||||
| 					let config = iface_load_config(prev_file); | 				if (config) | ||||||
| 					if (config) | 					config.radio.data = []; | ||||||
| 						config.radio.data = []; | 				hostapd.data.config[phy] = config; | ||||||
| 					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; |  | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | 			let config = iface_load_config(file); | ||||||
|  |  | ||||||
|  | 			hostapd.printf(`Set new config for phy ${phy}: ${file}`); | ||||||
|  | 			iface_set_config(phy, config); | ||||||
|  |  | ||||||
| 			return { | 			return { | ||||||
| 				pid: hostapd.getpid() | 				pid: hostapd.getpid() | ||||||
| 			}; | 			}; | ||||||
| 		} | 		}) | ||||||
| 	}, | 	}, | ||||||
| 	config_add: { | 	config_add: { | ||||||
| 		args: { | 		args: { | ||||||
| 			iface: "", | 			iface: "", | ||||||
| 			config: "", | 			config: "", | ||||||
| 		}, | 		}, | ||||||
| 		call: function(req) { | 		call: ex_wrap(function(req) { | ||||||
| 			if (!req.args.iface || !req.args.config) | 			if (!req.args.iface || !req.args.config) | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; | 				return libubus.STATUS_INVALID_ARGUMENT; | ||||||
|  |  | ||||||
| @@ -440,19 +765,19 @@ let main_obj = { | |||||||
| 			return { | 			return { | ||||||
| 				pid: hostapd.getpid() | 				pid: hostapd.getpid() | ||||||
| 			}; | 			}; | ||||||
| 		} | 		}) | ||||||
| 	}, | 	}, | ||||||
| 	config_remove: { | 	config_remove: { | ||||||
| 		args: { | 		args: { | ||||||
| 			iface: "" | 			iface: "" | ||||||
| 		}, | 		}, | ||||||
| 		call: function(req) { | 		call: ex_wrap(function(req) { | ||||||
| 			if (!req.args.iface) | 			if (!req.args.iface) | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; | 				return libubus.STATUS_INVALID_ARGUMENT; | ||||||
|  |  | ||||||
| 			hostapd.remove_iface(req.args.iface); | 			hostapd.remove_iface(req.args.iface); | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} | 		}) | ||||||
| 	}, | 	}, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,11 +1,14 @@ | |||||||
| #!/usr/bin/env ucode | #!/usr/bin/env ucode | ||||||
| 'use strict'; | '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"; | import { readfile, writefile, basename, readlink, glob } from "fs"; | ||||||
|  | let libubus = require("ubus"); | ||||||
|  |  | ||||||
| let keep_devices = {}; | let keep_devices = {}; | ||||||
| let phy = shift(ARGV); | let phy = shift(ARGV); | ||||||
| let new_config = shift(ARGV); | let command = shift(ARGV); | ||||||
|  | let phydev; | ||||||
|  |  | ||||||
| const mesh_params = [ | const mesh_params = [ | ||||||
| 	"mesh_retry_timeout", "mesh_confirm_timeout", "mesh_holding_timeout", "mesh_max_peer_links", | 	"mesh_retry_timeout", "mesh_confirm_timeout", "mesh_holding_timeout", "mesh_max_peer_links", | ||||||
| 	"mesh_max_retries", "mesh_ttl", "mesh_element_ttl", "mesh_hwmp_max_preq_retries", | 	"mesh_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" ]); | 		system([ "ip", "link", "set", "dev", ifname, "down" ]); | ||||||
| 		wdev_remove(ifname); | 		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); | 	wdev_create(phy, ifname, wdev); | ||||||
| 	system([ "ip", "link", "set", "dev", ifname, "up" ]); | 	system([ "ip", "link", "set", "dev", ifname, "up" ]); | ||||||
| 	if (wdev.freq) | 	if (wdev.freq) | ||||||
| @@ -47,7 +55,7 @@ function iface_start(wdev) | |||||||
| 		system(cmd); | 		system(cmd); | ||||||
| 	} else if (wdev.mode == "mesh") { | 	} else if (wdev.mode == "mesh") { | ||||||
| 		let cmd = [ "iw", "dev", ifname, "mesh", "join", wdev.ssid, "freq", wdev.freq, wdev.htmode ]; | 		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]) | 			if (wdev[key]) | ||||||
| 				push(cmd, key, wdev[key]); | 				push(cmd, key, wdev[key]); | ||||||
| 		system(cmd); | 		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`; | Commands: | ||||||
|  | 	set_config <config> [<device]...] - set phy configuration | ||||||
| for (let dev in ARGV) | 	get_macaddr <id>		  - get phy MAC address for vif index <id> | ||||||
| 	keep_devices[dev] = true; | `); | ||||||
|  |  | ||||||
| if (!phy || !new_config) { |  | ||||||
| 	warn(`Usage: ${basename(sourcepath())} <phy> <config> [<device]...]\n`); |  | ||||||
| 	exit(1); | 	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`); | 	warn(`PHY ${phy} does not exist\n`); | ||||||
| 	exit(1); | 	exit(1); | ||||||
| } | } | ||||||
|  |  | ||||||
| new_config = json(new_config); | commands[command](ARGV); | ||||||
| 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)); |  | ||||||
|   | |||||||
| @@ -1,11 +1,12 @@ | |||||||
| let libubus = require("ubus"); | let libubus = require("ubus"); | ||||||
| import { open, readfile } from "fs"; | 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(); | let ubus = libubus.connect(); | ||||||
|  |  | ||||||
| wpas.data.config = {}; | wpas.data.config = {}; | ||||||
| wpas.data.iface_phy = {}; | wpas.data.iface_phy = {}; | ||||||
|  | wpas.data.macaddr_list = {}; | ||||||
|  |  | ||||||
| function iface_stop(iface) | function iface_stop(iface) | ||||||
| { | { | ||||||
| @@ -20,16 +21,23 @@ function iface_stop(iface) | |||||||
| 	iface.running = false; | 	iface.running = false; | ||||||
| } | } | ||||||
|  |  | ||||||
| function iface_start(phy, iface) | function iface_start(phydev, iface, macaddr_list) | ||||||
| { | { | ||||||
|  | 	let phy = phydev.name; | ||||||
|  |  | ||||||
| 	if (iface.running) | 	if (iface.running) | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
| 	let ifname = iface.config.iface; | 	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; | 	wpas.data.iface_phy[ifname] = phy; | ||||||
| 	wdev_remove(ifname); | 	wdev_remove(ifname); | ||||||
| 	let ret = wdev_create(phy, ifname, iface.config); | 	let ret = wdev_create(phy, ifname, wdev_config); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		wpas.printf(`Failed to create device ${ifname}: ${ret}`); | 		wpas.printf(`Failed to create device ${ifname}: ${ret}`); | ||||||
| 	wpas.add_iface(iface.config); | 	wpas.add_iface(iface.config); | ||||||
| @@ -43,6 +51,11 @@ function iface_cb(new_if, old_if) | |||||||
| 		return; | 		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) | 	if (old_if) | ||||||
| 		iface_stop(old_if); | 		iface_stop(old_if); | ||||||
| } | } | ||||||
| @@ -73,9 +86,22 @@ function set_config(phy_name, config_list) | |||||||
| function start_pending(phy_name) | function start_pending(phy_name) | ||||||
| { | { | ||||||
| 	let phy = wpas.data.config[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) | 	for (let ifname in phy.data) | ||||||
| 		iface_start(phy_name, phy.data[ifname]); | 		iface_start(phydev, phy.data[ifname]); | ||||||
| } | } | ||||||
|  |  | ||||||
| let main_obj = { | let main_obj = { | ||||||
| @@ -106,6 +132,55 @@ let main_obj = { | |||||||
| 			return 0; | 			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: { | 	config_set: { | ||||||
| 		args: { | 		args: { | ||||||
| 			phy: "", | 			phy: "", | ||||||
| @@ -116,6 +191,7 @@ let main_obj = { | |||||||
| 			if (!req.args.phy) | 			if (!req.args.phy) | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; | 				return libubus.STATUS_INVALID_ARGUMENT; | ||||||
|  |  | ||||||
|  | 			wpas.printf(`Set new config for phy ${req.args.phy}`); | ||||||
| 			try { | 			try { | ||||||
| 				if (req.args.config) | 				if (req.args.config) | ||||||
| 					set_config(req.args.phy, 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) { | 	switch (state) { | ||||||
| 	case "DISCONNECTED": | 	case "DISCONNECTED": | ||||||
| 	case "AUTHENTICATING": | 	case "AUTHENTICATING": | ||||||
|  | 	case "SCANNING": | ||||||
| 		msg.up = false; | 		msg.up = false; | ||||||
| 		break; | 		break; | ||||||
| 	case "INTERFACE_DISABLED": | 	case "INTERFACE_DISABLED": | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ start_service() { | |||||||
| 		procd_open_instance hostapd | 		procd_open_instance hostapd | ||||||
| 		procd_set_param command /usr/sbin/hostapd -s -g /var/run/hostapd/global | 		procd_set_param command /usr/sbin/hostapd -s -g /var/run/hostapd/global | ||||||
| 		procd_set_param respawn 3600 1 0 | 		procd_set_param respawn 3600 1 0 | ||||||
|  | 		procd_set_param limits core="unlimited" | ||||||
| 		[ -x /sbin/ujail -a -e /etc/capabilities/wpad.json ] && { | 		[ -x /sbin/ujail -a -e /etc/capabilities/wpad.json ] && { | ||||||
| 			procd_add_jail hostapd | 			procd_add_jail hostapd | ||||||
| 			procd_set_param capabilities /etc/capabilities/wpad.json | 			procd_set_param capabilities /etc/capabilities/wpad.json | ||||||
| @@ -29,6 +30,7 @@ start_service() { | |||||||
| 		procd_open_instance supplicant | 		procd_open_instance supplicant | ||||||
| 		procd_set_param command /usr/sbin/wpa_supplicant -n -s -g /var/run/wpa_supplicant/global | 		procd_set_param command /usr/sbin/wpa_supplicant -n -s -g /var/run/wpa_supplicant/global | ||||||
| 		procd_set_param respawn 3600 1 0 | 		procd_set_param respawn 3600 1 0 | ||||||
|  | 		procd_set_param limits core="unlimited" | ||||||
| 		[ -x /sbin/ujail -a -e /etc/capabilities/wpad.json ] && { | 		[ -x /sbin/ujail -a -e /etc/capabilities/wpad.json ] && { | ||||||
| 			procd_add_jail wpa_supplicant | 			procd_add_jail wpa_supplicant | ||||||
| 			procd_set_param capabilities /etc/capabilities/wpad.json | 			procd_set_param capabilities /etc/capabilities/wpad.json | ||||||
|   | |||||||
| @@ -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; | ||||||
|  |   | ||||||
| @@ -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; | ||||||
| @@ -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"); | ||||||
| @@ -0,0 +1,28 @@ | |||||||
|  | From: Felix Fietkau <nbd@nbd.name> | ||||||
|  | Date: Wed, 20 Sep 2023 13:41:10 +0200 | ||||||
|  | Subject: [PATCH] hostapd: cancel channel_list_update_timeout in | ||||||
|  |  hostapd_cleanup_iface_partial | ||||||
|  |  | ||||||
|  | Fixes a crash when disabling an interface during channel list update | ||||||
|  |  | ||||||
|  | Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | --- a/src/ap/hostapd.c | ||||||
|  | +++ b/src/ap/hostapd.c | ||||||
|  | @@ -501,6 +501,7 @@ static void sta_track_deinit(struct host | ||||||
|  |  void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) | ||||||
|  |  { | ||||||
|  |  	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); | ||||||
|  | +	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); | ||||||
|  |  #ifdef NEED_AP_MLME | ||||||
|  |  	hostapd_stop_setup_timers(iface); | ||||||
|  |  #endif /* NEED_AP_MLME */ | ||||||
|  | @@ -529,7 +530,6 @@ void hostapd_cleanup_iface_partial(struc | ||||||
|  |  static void hostapd_cleanup_iface(struct hostapd_iface *iface) | ||||||
|  |  { | ||||||
|  |  	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); | ||||||
|  | -	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); | ||||||
|  |  	eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface, | ||||||
|  |  			     NULL); | ||||||
|  |   | ||||||
| @@ -1,5 +1,7 @@ | |||||||
| --- a/hostapd/Makefile | Index: hostapd-2021-02-20-59e9794c/hostapd/Makefile | ||||||
| +++ b/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 | @@ -166,6 +166,12 @@ OBJS += ../src/common/hw_features_common | ||||||
|   |   | ||||||
|  OBJS += ../src/eapol_auth/eapol_auth_sm.o |  OBJS += ../src/eapol_auth/eapol_auth_sm.o | ||||||
| @@ -13,8 +15,10 @@ | |||||||
|   |   | ||||||
|  ifdef CONFIG_CODE_COVERAGE |  ifdef CONFIG_CODE_COVERAGE | ||||||
|  CFLAGS += -O0 -fprofile-arcs -ftest-coverage |  CFLAGS += -O0 -fprofile-arcs -ftest-coverage | ||||||
| --- a/src/ap/hostapd.h | Index: hostapd-2021-02-20-59e9794c/src/ap/hostapd.h | ||||||
| +++ b/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 @@ | @@ -17,6 +17,7 @@ | ||||||
|  #include "utils/list.h" |  #include "utils/list.h" | ||||||
|  #include "ap_config.h" |  #include "ap_config.h" | ||||||
| @@ -39,8 +43,10 @@ | |||||||
|  void hostapd_interface_deinit(struct hostapd_iface *iface); |  void hostapd_interface_deinit(struct hostapd_iface *iface); | ||||||
|  void hostapd_interface_free(struct hostapd_iface *iface); |  void hostapd_interface_free(struct hostapd_iface *iface); | ||||||
|  struct hostapd_iface * hostapd_alloc_iface(void); |  struct hostapd_iface * hostapd_alloc_iface(void); | ||||||
| --- a/src/ap/hostapd.c | Index: hostapd-2021-02-20-59e9794c/src/ap/hostapd.c | ||||||
| +++ b/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 | @@ -376,6 +376,7 @@ void hostapd_free_hapd_data(struct hosta | ||||||
|  	hapd->beacon_set_done = 0; |  	hapd->beacon_set_done = 0; | ||||||
|   |   | ||||||
| @@ -82,8 +88,10 @@ | |||||||
|  	hostapd_interface_deinit(iface); |  	hostapd_interface_deinit(iface); | ||||||
|  	wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", |  	wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", | ||||||
|  		   __func__, driver, drv_priv); |  		   __func__, driver, drv_priv); | ||||||
| --- a/src/ap/ieee802_11.c | Index: hostapd-2021-02-20-59e9794c/src/ap/ieee802_11.c | ||||||
| +++ b/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 | @@ -3421,13 +3421,18 @@ static void handle_auth(struct hostapd_d | ||||||
|  	u16 auth_alg, auth_transaction, status_code; |  	u16 auth_alg, auth_transaction, status_code; | ||||||
|  	u16 resp = WLAN_STATUS_SUCCESS; |  	u16 resp = WLAN_STATUS_SUCCESS; | ||||||
| @@ -109,7 +117,7 @@ | |||||||
|  		goto fail; |  		goto fail; | ||||||
|  	} |  	} | ||||||
| +	ubus_resp = hostapd_ubus_handle_event(hapd, &req); | +	ubus_resp = hostapd_ubus_handle_event(hapd, &req); | ||||||
| +	if (0 && ubus_resp) { | +	if (ubus_resp) { | ||||||
| +		wpa_printf(MSG_DEBUG, "Station " MACSTR " rejected by ubus handler.\n", | +		wpa_printf(MSG_DEBUG, "Station " MACSTR " rejected by ubus handler.\n", | ||||||
| +			MAC2STR(mgmt->sa)); | +			MAC2STR(mgmt->sa)); | ||||||
| +		resp = ubus_resp > 0 ? (u16) ubus_resp : WLAN_STATUS_UNSPECIFIED_FAILURE; | +		resp = ubus_resp > 0 ? (u16) ubus_resp : WLAN_STATUS_UNSPECIFIED_FAILURE; | ||||||
| @@ -144,7 +152,7 @@ | |||||||
|  #endif /* CONFIG_FILS */ |  #endif /* CONFIG_FILS */ | ||||||
|   |   | ||||||
| +	ubus_resp = hostapd_ubus_handle_event(hapd, &req); | +	ubus_resp = hostapd_ubus_handle_event(hapd, &req); | ||||||
| +	if (0 && ubus_resp) { | +	if (ubus_resp) { | ||||||
| +		wpa_printf(MSG_DEBUG, "Station " MACSTR " assoc rejected by ubus handler.\n", | +		wpa_printf(MSG_DEBUG, "Station " MACSTR " assoc rejected by ubus handler.\n", | ||||||
| +		       MAC2STR(mgmt->sa)); | +		       MAC2STR(mgmt->sa)); | ||||||
| +		resp = ubus_resp > 0 ? (u16) ubus_resp : WLAN_STATUS_UNSPECIFIED_FAILURE; | +		resp = ubus_resp > 0 ? (u16) ubus_resp : WLAN_STATUS_UNSPECIFIED_FAILURE; | ||||||
| @@ -170,8 +178,10 @@ | |||||||
|  	sta = ap_get_sta(hapd, mgmt->sa); |  	sta = ap_get_sta(hapd, mgmt->sa); | ||||||
|  	if (sta == NULL) { |  	if (sta == NULL) { | ||||||
|  		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " |  		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " | ||||||
| --- a/src/ap/beacon.c | Index: hostapd-2021-02-20-59e9794c/src/ap/beacon.c | ||||||
| +++ b/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 | @@ -823,6 +823,12 @@ void handle_probe_req(struct hostapd_dat | ||||||
|  	u16 csa_offs[2]; |  	u16 csa_offs[2]; | ||||||
|  	size_t csa_offs_len; |  	size_t csa_offs_len; | ||||||
| @@ -198,8 +208,10 @@ | |||||||
|  	/* TODO: verify that supp_rates contains at least one matching rate |  	/* TODO: verify that supp_rates contains at least one matching rate | ||||||
|  	 * with AP configuration */ |  	 * with AP configuration */ | ||||||
|   |   | ||||||
| --- a/src/ap/drv_callbacks.c | Index: hostapd-2021-02-20-59e9794c/src/ap/drv_callbacks.c | ||||||
| +++ b/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 | @@ -145,6 +145,10 @@ int hostapd_notif_assoc(struct hostapd_d | ||||||
|  	u16 reason = WLAN_REASON_UNSPECIFIED; |  	u16 reason = WLAN_REASON_UNSPECIFIED; | ||||||
|  	int status = WLAN_STATUS_SUCCESS; |  	int status = WLAN_STATUS_SUCCESS; | ||||||
| @@ -224,8 +236,22 @@ | |||||||
|  #ifdef CONFIG_P2P |  #ifdef CONFIG_P2P | ||||||
|  	if (elems.p2p) { |  	if (elems.p2p) { | ||||||
|  		wpabuf_free(sta->p2p_ie); |  		wpabuf_free(sta->p2p_ie); | ||||||
| --- a/src/ap/sta_info.c | @@ -981,9 +991,11 @@ void hostapd_event_ch_switch(struct host | ||||||
| +++ b/src/ap/sta_info.c |   | ||||||
|  |  		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 | @@ -458,6 +458,7 @@ void ap_handle_timer(void *eloop_ctx, vo | ||||||
|  		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, |  		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, | ||||||
|  			       HOSTAPD_LEVEL_INFO, "deauthenticated due to " |  			       HOSTAPD_LEVEL_INFO, "deauthenticated due to " | ||||||
| @@ -304,8 +330,10 @@ | |||||||
|   |   | ||||||
|  		if (hapd->msg_ctx_parent && |  		if (hapd->msg_ctx_parent && | ||||||
|  		    hapd->msg_ctx_parent != hapd->msg_ctx) |  		    hapd->msg_ctx_parent != hapd->msg_ctx) | ||||||
| --- a/src/ap/wpa_auth_glue.c | Index: hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_glue.c | ||||||
| +++ b/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 | @@ -265,6 +265,7 @@ static void hostapd_wpa_auth_psk_failure | ||||||
|  	struct hostapd_data *hapd = ctx; |  	struct hostapd_data *hapd = ctx; | ||||||
|  	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR, |  	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR, | ||||||
| @@ -314,8 +342,10 @@ | |||||||
|  } |  } | ||||||
|   |   | ||||||
|   |   | ||||||
| --- a/wpa_supplicant/Makefile | Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/Makefile | ||||||
| +++ b/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 | @@ -169,6 +169,13 @@ ifdef CONFIG_EAPOL_TEST | ||||||
|  CFLAGS += -Werror -DEAPOL_TEST |  CFLAGS += -Werror -DEAPOL_TEST | ||||||
|  endif |  endif | ||||||
| @@ -340,8 +370,10 @@ | |||||||
|  endif |  endif | ||||||
|   |   | ||||||
|  CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY |  CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY | ||||||
| --- a/wpa_supplicant/wpa_supplicant.c | Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/wpa_supplicant.c | ||||||
| +++ b/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 | @@ -6943,6 +6943,8 @@ struct wpa_supplicant * wpa_supplicant_a | ||||||
|  	} |  	} | ||||||
|  #endif /* CONFIG_P2P */ |  #endif /* CONFIG_P2P */ | ||||||
| @@ -373,8 +405,10 @@ | |||||||
|  	return 0; |  	return 0; | ||||||
|  } |  } | ||||||
|   |   | ||||||
| --- a/wpa_supplicant/wpa_supplicant_i.h | Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/wpa_supplicant_i.h | ||||||
| +++ b/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 @@ | @@ -19,6 +19,7 @@ | ||||||
|  #include "wps/wps_defs.h" |  #include "wps/wps_defs.h" | ||||||
|  #include "config_ssid.h" |  #include "config_ssid.h" | ||||||
| @@ -400,8 +434,10 @@ | |||||||
|  #ifdef CONFIG_MATCH_IFACE |  #ifdef CONFIG_MATCH_IFACE | ||||||
|  	int matched; |  	int matched; | ||||||
|  #endif /* CONFIG_MATCH_IFACE */ |  #endif /* CONFIG_MATCH_IFACE */ | ||||||
| --- a/wpa_supplicant/wps_supplicant.c | Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/wps_supplicant.c | ||||||
| +++ b/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 @@ | @@ -33,6 +33,7 @@ | ||||||
|  #include "p2p/p2p.h" |  #include "p2p/p2p.h" | ||||||
|  #include "p2p_supplicant.h" |  #include "p2p_supplicant.h" | ||||||
| @@ -419,8 +455,10 @@ | |||||||
|  	if (wpa_s->conf->wps_cred_processing == 1) |  	if (wpa_s->conf->wps_cred_processing == 1) | ||||||
|  		return 0; |  		return 0; | ||||||
|   |   | ||||||
| --- a/wpa_supplicant/main.c | Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/main.c | ||||||
| +++ b/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[]) | @@ -202,7 +202,7 @@ int main(int argc, char *argv[]) | ||||||
|   |   | ||||||
|  	for (;;) { |  	for (;;) { | ||||||
| @@ -440,8 +478,10 @@ | |||||||
|  		case 'o': |  		case 'o': | ||||||
|  			params.override_driver = optarg; |  			params.override_driver = optarg; | ||||||
|  			break; |  			break; | ||||||
| --- a/src/ap/rrm.c | Index: hostapd-2021-02-20-59e9794c/src/ap/rrm.c | ||||||
| +++ b/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 | @@ -89,6 +89,9 @@ static void hostapd_handle_beacon_report | ||||||
|  		return; |  		return; | ||||||
|  	wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s", |  	wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s", | ||||||
| @@ -452,8 +492,10 @@ | |||||||
|  } |  } | ||||||
|   |   | ||||||
|   |   | ||||||
| --- a/src/ap/vlan_init.c | Index: hostapd-2021-02-20-59e9794c/src/ap/vlan_init.c | ||||||
| +++ b/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 @@ | @@ -22,6 +22,7 @@ | ||||||
|  static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan, |  static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan, | ||||||
|  		       int existsok) |  		       int existsok) | ||||||
| @@ -490,8 +532,10 @@ | |||||||
|  	return hostapd_vlan_if_remove(hapd, vlan->ifname); |  	return hostapd_vlan_if_remove(hapd, vlan->ifname); | ||||||
|  } |  } | ||||||
|   |   | ||||||
| --- a/src/ap/dfs.c | Index: hostapd-2021-02-20-59e9794c/src/ap/dfs.c | ||||||
| +++ b/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 | @@ -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=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", | ||||||
|  		freq, ht_enabled, chan_offset, chan_width, cf1, cf2); |  		freq, ht_enabled, chan_offset, chan_width, cf1, cf2); | ||||||
| @@ -501,8 +545,10 @@ | |||||||
|  	/* Proceed only if DFS is not offloaded to the driver */ |  	/* Proceed only if DFS is not offloaded to the driver */ | ||||||
|  	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) |  	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) | ||||||
|  		return 0; |  		return 0; | ||||||
| --- a/src/ap/airtime_policy.c | Index: hostapd-2021-02-20-59e9794c/src/ap/airtime_policy.c | ||||||
| +++ b/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 | @@ -108,8 +108,14 @@ static void set_sta_weights(struct hosta | ||||||
|  { |  { | ||||||
|  	struct sta_info *sta; |  	struct sta_info *sta; | ||||||
| @@ -532,8 +578,10 @@ | |||||||
|  		if (weight) |  		if (weight) | ||||||
|  			return sta_set_airtime_weight(hapd, sta, weight); |  			return sta_set_airtime_weight(hapd, sta, weight); | ||||||
|  	} |  	} | ||||||
| --- a/src/ap/sta_info.h | Index: hostapd-2021-02-20-59e9794c/src/ap/sta_info.h | ||||||
| +++ b/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 { | @@ -323,6 +323,7 @@ struct sta_info { | ||||||
|  #endif /* CONFIG_TESTING_OPTIONS */ |  #endif /* CONFIG_TESTING_OPTIONS */ | ||||||
|  #ifdef CONFIG_AIRTIME_POLICY |  #ifdef CONFIG_AIRTIME_POLICY | ||||||
| @@ -542,8 +590,10 @@ | |||||||
|  	struct os_reltime backlogged_until; |  	struct os_reltime backlogged_until; | ||||||
|  #endif /* CONFIG_AIRTIME_POLICY */ |  #endif /* CONFIG_AIRTIME_POLICY */ | ||||||
|   |   | ||||||
| --- a/src/ap/wnm_ap.c | Index: hostapd-2021-02-20-59e9794c/src/ap/wnm_ap.c | ||||||
| +++ b/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 | @@ -442,7 +442,8 @@ static void ieee802_11_rx_bss_trans_mgmt | ||||||
|  	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", |  	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", | ||||||
|  		    pos, end - pos); |  		    pos, end - pos); | ||||||
| @@ -582,8 +632,10 @@ | |||||||
|  	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", |  	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", | ||||||
|  		    pos, end - pos); |  		    pos, end - pos); | ||||||
|  } |  } | ||||||
| --- a/src/utils/eloop.c | Index: hostapd-2021-02-20-59e9794c/src/utils/eloop.c | ||||||
| +++ b/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 { | @@ -77,6 +77,9 @@ struct eloop_sock_table { | ||||||
|  struct eloop_data { |  struct eloop_data { | ||||||
|  	int max_sock; |  	int max_sock; | ||||||
| @@ -632,8 +684,10 @@ | |||||||
|   |   | ||||||
|  void eloop_terminate(void) |  void eloop_terminate(void) | ||||||
|  { |  { | ||||||
| --- a/src/utils/eloop.h | Index: hostapd-2021-02-20-59e9794c/src/utils/eloop.h | ||||||
| +++ b/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 | @@ -65,6 +65,9 @@ typedef void (*eloop_timeout_handler)(vo | ||||||
|   */ |   */ | ||||||
|  typedef void (*eloop_signal_handler)(int sig, void *signal_ctx); |  typedef void (*eloop_signal_handler)(int sig, void *signal_ctx); | ||||||
| @@ -663,8 +717,10 @@ | |||||||
|  /** |  /** | ||||||
|   * eloop_run - Start the event loop |   * eloop_run - Start the event loop | ||||||
|   * |   * | ||||||
|  | Index: hostapd-2021-02-20-59e9794c/src/utils/uloop.c | ||||||
|  | =================================================================== | ||||||
| --- /dev/null | --- /dev/null | ||||||
| +++ b/src/utils/uloop.c | +++ hostapd-2021-02-20-59e9794c/src/utils/uloop.c | ||||||
| @@ -0,0 +1,64 @@ | @@ -0,0 +1,64 @@ | ||||||
| +#include <libubox/uloop.h> | +#include <libubox/uloop.h> | ||||||
| +#include "includes.h" | +#include "includes.h" | ||||||
|   | |||||||
| @@ -107,14 +107,14 @@ | |||||||
|  	hostapd_ubus_free_bss(hapd); |  	hostapd_ubus_free_bss(hapd); | ||||||
|  	accounting_deinit(hapd); |  	accounting_deinit(hapd); | ||||||
|  	hostapd_deinit_wpa(hapd); |  	hostapd_deinit_wpa(hapd); | ||||||
| @@ -530,6 +533,7 @@ void hostapd_cleanup_iface_partial(struc | @@ -502,6 +505,7 @@ static void sta_track_deinit(struct host | ||||||
|  static void hostapd_cleanup_iface(struct hostapd_iface *iface) |  void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) | ||||||
|  { |  { | ||||||
|  	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); |  	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); | ||||||
| +	hostapd_ucode_free_iface(iface); | +	hostapd_ucode_free_iface(iface); | ||||||
|  	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); |  	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); | ||||||
|  	eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface, |  #ifdef NEED_AP_MLME | ||||||
|  			     NULL); |  	hostapd_stop_setup_timers(iface); | ||||||
| @@ -1104,7 +1108,7 @@ static int db_table_create_radius_attrib | @@ -1104,7 +1108,7 @@ static int db_table_create_radius_attrib | ||||||
|   * initialized. Most of the modules that are initialized here will be |   * initialized. Most of the modules that are initialized here will be | ||||||
|   * deinitialized in hostapd_cleanup(). |   * deinitialized in hostapd_cleanup(). | ||||||
| @@ -159,6 +159,16 @@ | |||||||
|  				hostapd_cleanup(hapd); |  				hostapd_cleanup(hapd); | ||||||
|  				hapd_iface->bss[hapd_iface->num_bss - 1] = NULL; |  				hapd_iface->bss[hapd_iface->num_bss - 1] = NULL; | ||||||
|  				hapd_iface->conf->num_bss--; |  				hapd_iface->conf->num_bss--; | ||||||
|  | @@ -3137,7 +3142,8 @@ int hostapd_remove_iface(struct hapd_int | ||||||
|  |  		hapd_iface = interfaces->iface[i]; | ||||||
|  |  		if (hapd_iface == NULL) | ||||||
|  |  			return -1; | ||||||
|  | -		if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) { | ||||||
|  | +		if (!os_strcmp(hapd_iface->phy, buf) || | ||||||
|  | +		    !os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) { | ||||||
|  |  			wpa_printf(MSG_INFO, "Remove interface '%s'", buf); | ||||||
|  |  			hapd_iface->driver_ap_teardown = | ||||||
|  |  				!!(hapd_iface->drv_flags & | ||||||
| --- a/wpa_supplicant/Makefile | --- a/wpa_supplicant/Makefile | ||||||
| +++ b/wpa_supplicant/Makefile | +++ b/wpa_supplicant/Makefile | ||||||
| @@ -172,8 +172,20 @@ endif | @@ -172,8 +172,20 @@ endif | ||||||
| @@ -287,7 +297,33 @@ | |||||||
|   |   | ||||||
| --- a/src/drivers/driver.h | --- a/src/drivers/driver.h | ||||||
| +++ b/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 |  	 * struct ch_switch | ||||||
| @@ -295,7 +331,7 @@ | |||||||
|  	 * @freq: Frequency of new channel in MHz |  	 * @freq: Frequency of new channel in MHz | ||||||
|  	 * @ht_enabled: Whether this is an HT channel |  	 * @ht_enabled: Whether this is an HT channel | ||||||
|  	 * @ch_offset: Secondary channel offset |  	 * @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 |  	 * @cf2: Center frequency 2 | ||||||
|  	 */ |  	 */ | ||||||
|  	struct ch_switch { |  	struct ch_switch { | ||||||
| @@ -348,3 +384,187 @@ | |||||||
|  	switch (event) { |  	switch (event) { | ||||||
|  	case EVENT_AUTH: |  	case EVENT_AUTH: | ||||||
|  #ifdef CONFIG_FST |  #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 | ||||||
|  | @@ -1224,7 +1224,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); | ||||||
|  | @@ -1260,7 +1260,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); | ||||||
|  | @@ -7614,6 +7614,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, | ||||||
|  | @@ -7673,21 +7674,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) { | ||||||
|  | @@ -8047,6 +8044,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) | ||||||
|  |  { | ||||||
|  | @@ -9391,6 +9432,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, | ||||||
|  | @@ -11973,6 +12045,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, | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ | |||||||
|   |   | ||||||
| --- a/src/ap/x_snoop.c | --- a/src/ap/x_snoop.c | ||||||
| +++ b/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; |  		return -1; | ||||||
|  	} |  	} | ||||||
|   |   | ||||||
| @@ -29,13 +29,20 @@ | |||||||
|  		wpa_printf(MSG_DEBUG, |  		wpa_printf(MSG_DEBUG, | ||||||
|  			   "x_snoop: Failed to enable proxyarp on the bridge port"); |  			   "x_snoop: Failed to enable proxyarp on the bridge port"); | ||||||
|  		return -1; |  		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 |  #ifdef CONFIG_IPV6 | ||||||
| -	if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) { | -	if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) { | ||||||
| +	if (!conf->snoop_iface[0] && | +	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, |  		wpa_printf(MSG_DEBUG, | ||||||
|  			   "x_snoop: Failed to enable multicast snooping on the bridge"); |  			   "x_snoop: Failed to enable multicast snooping on the bridge"); | ||||||
|  		return -1; |  		return -1; | ||||||
| @@ -44,15 +51,27 @@ | |||||||
|  	struct hostapd_bss_config *conf = hapd->conf; |  	struct hostapd_bss_config *conf = hapd->conf; | ||||||
|  	struct l2_packet_data *l2; |  	struct l2_packet_data *l2; | ||||||
| +	const char *ifname = conf->bridge; | +	const char *ifname = conf->bridge; | ||||||
|   | + | ||||||
| -	l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1); |  | ||||||
| +	if (conf->snoop_iface[0]) | +	if (conf->snoop_iface[0]) | ||||||
| +		ifname = conf->snoop_iface; | +		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); | +	l2 = l2_packet_init(ifname, NULL, ETH_P_ALL, handler, hapd, 1); | ||||||
|  	if (l2 == NULL) { |  	if (l2 == NULL) { | ||||||
|  		wpa_printf(MSG_DEBUG, |  		wpa_printf(MSG_DEBUG, | ||||||
|  			   "x_snoop: Failed to initialize L2 packet processing %s", |  			   "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 | --- a/hostapd/config_file.c | ||||||
| +++ b/hostapd/config_file.c | +++ b/hostapd/config_file.c | ||||||
| @@ -2343,6 +2343,8 @@ static int hostapd_config_fill(struct ho | @@ -2343,6 +2343,8 @@ static int hostapd_config_fill(struct ho | ||||||
| @@ -64,3 +83,55 @@ | |||||||
|  	} else if (os_strcmp(buf, "vlan_bridge") == 0) { |  	} else if (os_strcmp(buf, "vlan_bridge") == 0) { | ||||||
|  		os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge)); |  		os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge)); | ||||||
|  	} else if (os_strcmp(buf, "wds_bridge") == 0) { |  	} 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)) | ||||||
|   | |||||||
| @@ -19,18 +19,6 @@ | |||||||
|   |   | ||||||
|  	enum hostapd_logger_level logger_syslog_level, logger_stdout_level; |  	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 | --- a/src/ap/ap_config.c | ||||||
| +++ b/src/ap/ap_config.c | +++ b/src/ap/ap_config.c | ||||||
| @@ -785,6 +785,7 @@ void hostapd_config_free_bss(struct host | @@ -785,6 +785,7 @@ void hostapd_config_free_bss(struct host | ||||||
|   | |||||||
| @@ -50,42 +50,4 @@ | |||||||
|  	return NL_SKIP; |  	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); |  | ||||||
|   | |||||||
							
								
								
									
										48
									
								
								feeds/ipq807x_v5.4/hostapd/patches/999-ft-anonce.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								feeds/ipq807x_v5.4/hostapd/patches/999-ft-anonce.patch
									
									
									
									
									
										Normal 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]; | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| --- a/src/ap/ieee802_11.c | --- a/src/ap/ieee802_11.c | ||||||
| +++ b/src/ap/ieee802_11.c | +++ b/src/ap/ieee802_11.c | ||||||
| @@ -57,6 +57,15 @@ | @@ -57,6 +57,17 @@ | ||||||
|  #include "gas_query_ap.h" |  #include "gas_query_ap.h" | ||||||
|   |   | ||||||
|   |   | ||||||
| @@ -8,6 +8,8 @@ | |||||||
| +ewma(int new, int old) | +ewma(int new, int old) | ||||||
| +{ | +{ | ||||||
| +	#define ALPHA	10 | +	#define ALPHA	10 | ||||||
|  | +	if (!old) | ||||||
|  | +		return new; | ||||||
| +	if (new >= 0) | +	if (new >= 0) | ||||||
| +		return old; | +		return old; | ||||||
| +	return ((ALPHA * new) + ((100 - ALPHA) * old)) / 100; | +	return ((ALPHA * new) + ((100 - ALPHA) * old)) / 100; | ||||||
| @@ -61,28 +63,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 | --- a/src/ap/hostapd.h | ||||||
| +++ b/src/ap/hostapd.h | +++ b/src/ap/hostapd.h | ||||||
| @@ -451,6 +451,7 @@ struct hostapd_data { | @@ -451,6 +451,7 @@ struct hostapd_data { | ||||||
|   | |||||||
| @@ -153,7 +153,7 @@ hostapd_bss_ban_client(struct hostapd_data *hapd, u8 *addr, int time) | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	eloop_register_timeout(0, time * 1000, hostapd_bss_del_ban, ban, hapd); | 	eloop_register_timeout(time, 0, hostapd_bss_del_ban, ban, hapd); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int | static int | ||||||
| @@ -305,7 +305,42 @@ hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj, | |||||||
| 			blobmsg_add_u32(&b, "rx", sta_driver_data.current_rx_rate * 100); | 			blobmsg_add_u32(&b, "rx", sta_driver_data.current_rx_rate * 100); | ||||||
| 			blobmsg_add_u32(&b, "tx", sta_driver_data.current_tx_rate * 100); | 			blobmsg_add_u32(&b, "tx", sta_driver_data.current_tx_rate * 100); | ||||||
| 			blobmsg_close_table(&b, r); | 			blobmsg_close_table(&b, r); | ||||||
|  | 			blobmsg_add_u32(&b, "retries", sta_driver_data.tx_retry_count); | ||||||
|  | 			blobmsg_add_u32(&b, "failed", sta_driver_data.tx_retry_failed); | ||||||
| 			blobmsg_add_u32(&b, "signal", sta_driver_data.signal); | 			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); | 		hostapd_parse_capab_blobmsg(sta); | ||||||
| @@ -424,6 +459,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); | 			hapd->iface->cac_started ? hapd->iface->dfs_cac_ms / 1000 - now.sec : 0); | ||||||
| 	blobmsg_close_table(&b, dfs_table); | 	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); | 	ubus_send_reply(ctx, req, b.head); | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| @@ -1698,6 +1739,19 @@ void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 * | |||||||
| 	ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1); | 	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) | void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta) | ||||||
| { | { | ||||||
|   | |||||||
							
								
								
									
										1845
									
								
								feeds/ipq807x_v5.4/hostapd/src/src/ap/ubus.c.orig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1845
									
								
								feeds/ipq807x_v5.4/hostapd/src/src/ap/ubus.c.orig
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -65,6 +65,7 @@ void hostapd_ubus_free(struct hapd_interfaces *interfaces); | |||||||
| int hostapd_ubus_notify_bss_transition_query( | int hostapd_ubus_notify_bss_transition_query( | ||||||
| 	struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason, | 	struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason, | ||||||
| 	const u8 *candidate_list, u16 candidate_list_len); | 	const u8 *candidate_list, u16 candidate_list_len); | ||||||
|  | void hostapd_ubus_notify_csa(struct hostapd_data *hapd, int freq); | ||||||
|  |  | ||||||
| #else | #else | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,6 +7,8 @@ | |||||||
| #include "beacon.h" | #include "beacon.h" | ||||||
| #include "hw_features.h" | #include "hw_features.h" | ||||||
| #include "ap_drv_ops.h" | #include "ap_drv_ops.h" | ||||||
|  | #include "dfs.h" | ||||||
|  | #include "acs.h" | ||||||
| #include <libubox/uloop.h> | #include <libubox/uloop.h> | ||||||
|  |  | ||||||
| static uc_resource_type_t *global_type, *bss_type, *iface_type; | 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; | 	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 * | static uc_value_t * | ||||||
| uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs) | 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; | 	struct hostapd_config *conf; | ||||||
| 	uc_value_t *file = uc_fn_arg(0); | 	uc_value_t *file = uc_fn_arg(0); | ||||||
| 	uc_value_t *index = uc_fn_arg(1); | 	uc_value_t *index = uc_fn_arg(1); | ||||||
|  | 	uc_value_t *files_only = uc_fn_arg(2); | ||||||
| 	unsigned int i, idx = 0; | 	unsigned int i, idx = 0; | ||||||
| 	int ret = -1; | 	int ret = -1; | ||||||
|  |  | ||||||
| @@ -129,9 +220,28 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs) | |||||||
|  |  | ||||||
| 	iface = hapd->iface; | 	iface = hapd->iface; | ||||||
| 	conf = interfaces->config_read_cb(ucv_string_get(file)); | 	conf = interfaces->config_read_cb(ucv_string_get(file)); | ||||||
| 	if (!conf || idx > conf->num_bss || !conf->bss[idx]) | 	if (!conf) | ||||||
| 		goto out; | 		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_bss_deinit_no_free(hapd); | ||||||
| 	hostapd_drv_stop_ap(hapd); | 	hostapd_drv_stop_ap(hapd); | ||||||
| 	hostapd_free_hapd_data(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]; | 			iface->conf->bss[i] = conf->bss[idx]; | ||||||
| 	hapd->conf = conf->bss[idx]; | 	hapd->conf = conf->bss[idx]; | ||||||
| 	conf->bss[idx] = old_bss; | 	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; | 	ret = 0; | ||||||
|  | free: | ||||||
|  | 	hostapd_config_free(conf); | ||||||
| out: | out: | ||||||
| 	return ucv_int64_new(ret); | 	return ucv_int64_new(ret); | ||||||
| } | } | ||||||
| @@ -178,10 +290,15 @@ uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs) | |||||||
| 	struct hostapd_iface *iface; | 	struct hostapd_iface *iface; | ||||||
| 	int i, idx; | 	int i, idx; | ||||||
|  |  | ||||||
| 	if (!hapd || hapd == hapd->iface->bss[0]) | 	if (!hapd) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  |  | ||||||
| 	iface = hapd->iface; | 	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++) | 	for (idx = 0; idx < iface->num_bss; idx++) | ||||||
| 		if (iface->bss[idx] == hapd) | 		if (iface->bss[idx] == hapd) | ||||||
| 			break; | 			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++) | 	for (i = idx + 1; i < iface->num_bss; i++) | ||||||
| 		iface->bss[i - 1] = iface->bss[i]; | 		iface->bss[i - 1] = iface->bss[i]; | ||||||
|  |  | ||||||
| 	iface->num_bss--; | 	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_drv_stop_ap(hapd); | ||||||
| 	hostapd_bss_deinit(hapd); | 	hostapd_bss_deinit(hapd); | ||||||
| 	hostapd_remove_iface_bss_conf(iface->conf, hapd->conf); | 	hostapd_remove_iface_bss_conf(iface->conf, hapd->conf); | ||||||
| @@ -266,6 +388,58 @@ out: | |||||||
| 	return ret; | 	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 * | static uc_value_t * | ||||||
| uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs) | uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs) | ||||||
| { | { | ||||||
| @@ -297,12 +471,35 @@ uc_hostapd_iface_stop(uc_vm_t *vm, size_t nargs) | |||||||
| 	struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface"); | 	struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface"); | ||||||
| 	int i; | 	int i; | ||||||
|  |  | ||||||
|  | 	if (!iface) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	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++) { | 	for (i = 0; i < iface->num_bss; i++) { | ||||||
| 		struct hostapd_data *hapd = iface->bss[i]; | 		struct hostapd_data *hapd = iface->bss[i]; | ||||||
|  |  | ||||||
| 		hostapd_drv_stop_ap(hapd); | 		hostapd_drv_stop_ap(hapd); | ||||||
| 		hapd->started = 0; | 		hapd->beacon_set_done = 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	return NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
| static uc_value_t * | static uc_value_t * | ||||||
| @@ -311,67 +508,85 @@ uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs) | |||||||
| 	struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface"); | 	struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface"); | ||||||
| 	uc_value_t *info = uc_fn_arg(0); | 	uc_value_t *info = uc_fn_arg(0); | ||||||
| 	struct hostapd_config *conf; | 	struct hostapd_config *conf; | ||||||
|  | 	bool changed = false; | ||||||
| 	uint64_t intval; | 	uint64_t intval; | ||||||
| 	int i; | 	int i; | ||||||
|  |  | ||||||
| 	if (!iface) | 	if (!iface) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  |  | ||||||
| 	if (!info) | 	if (!info) { | ||||||
|  | 		iface->freq = 0; | ||||||
| 		goto out; | 		goto out; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if (ucv_type(info) != UC_OBJECT) | 	if (ucv_type(info) != UC_OBJECT) | ||||||
| 		return NULL; | 		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; | 	conf = iface->conf; | ||||||
| 	if ((intval = ucv_int64_get(ucv_object_get(info, "op_class", NULL))) &&	!errno) | 	UPDATE_VAL(op_class, "op_class"); | ||||||
| 		conf->op_class = intval; | 	UPDATE_VAL(hw_mode, "hw_mode"); | ||||||
| 	if ((intval = ucv_int64_get(ucv_object_get(info, "hw_mode", NULL))) && !errno) | 	UPDATE_VAL(channel, "channel"); | ||||||
| 		conf->hw_mode = intval; | 	UPDATE_VAL(secondary_channel, "sec_channel"); | ||||||
| 	if ((intval = ucv_int64_get(ucv_object_get(info, "channel", NULL))) && !errno) | 	if (!changed && | ||||||
| 		conf->channel = intval; | 	    (iface->bss[0]->beacon_set_done || | ||||||
| 	if ((intval = ucv_int64_get(ucv_object_get(info, "sec_channel", NULL))) && !errno) | 	     iface->state == HAPD_IFACE_DFS)) | ||||||
| 		conf->secondary_channel = intval; | 		return ucv_boolean_new(true); | ||||||
| #ifdef CONFIG_IEEE80211AC |  | ||||||
| 	if ((intval = ucv_int64_get(ucv_object_get(info, "center_seg0_idx", NULL))) && !errno) { | 	intval = ucv_int64_get(ucv_object_get(info, "center_seg0_idx", NULL)); | ||||||
| 		conf->vht_oper_centr_freq_seg0_idx = intval; | 	if (!errno) | ||||||
| #ifdef CONFIG_IEEE80211AX | 		hostapd_set_oper_centr_freq_seg0_idx(conf, intval); | ||||||
| 		conf->he_oper_centr_freq_seg0_idx = intval; |  | ||||||
| #endif | 	intval = ucv_int64_get(ucv_object_get(info, "center_seg1_idx", NULL)); | ||||||
| #ifdef CONFIG_IEEE80211BE | 	if (!errno) | ||||||
| 		conf->eht_oper_centr_freq_seg0_idx = intval; | 		hostapd_set_oper_centr_freq_seg1_idx(conf, 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 |  | ||||||
| 	} |  | ||||||
| 	intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL)); | 	intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL)); | ||||||
| 	if (!errno) { | 	if (!errno) | ||||||
| 		conf->vht_oper_chwidth = intval; | 		hostapd_set_oper_chwidth(conf, intval); | ||||||
| #ifdef CONFIG_IEEE80211AX |  | ||||||
| 		conf->he_oper_chwidth = intval; | 	intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL)); | ||||||
| #endif | 	if (!errno) | ||||||
| #ifdef CONFIG_IEEE80211BE | 		iface->freq = intval; | ||||||
| 		conf->eht_oper_chwidth = intval; | 	else | ||||||
| #endif | 		iface->freq = 0; | ||||||
| 	} | 	conf->acs = 0; | ||||||
| #endif |  | ||||||
|  |  | ||||||
| out: | 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); | 		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++) { | 	for (i = 0; i < iface->num_bss; i++) { | ||||||
| 		struct hostapd_data *hapd = iface->bss[i]; | 		struct hostapd_data *hapd = iface->bss[i]; | ||||||
| 		int ret; | 		int ret; | ||||||
|  |  | ||||||
| 		hapd->started = 1; | 		hapd->conf->start_disabled = 0; | ||||||
| 		hostapd_set_freq(hapd, conf->hw_mode, iface->freq, | 		hostapd_set_freq(hapd, conf->hw_mode, iface->freq, | ||||||
| 				 conf->channel, | 				 conf->channel, | ||||||
| 				 conf->enable_edmg, | 				 conf->enable_edmg, | ||||||
| @@ -436,6 +651,55 @@ uc_hostapd_iface_switch_channel(uc_vm_t *vm, size_t nargs) | |||||||
| 	return ucv_boolean_new(!ret); | 	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) | int hostapd_ucode_init(struct hapd_interfaces *ifaces) | ||||||
| { | { | ||||||
| 	static const uc_function_list_t global_fns[] = { | 	static const uc_function_list_t global_fns[] = { | ||||||
| @@ -449,9 +713,11 @@ int hostapd_ucode_init(struct hapd_interfaces *ifaces) | |||||||
| 	static const uc_function_list_t bss_fns[] = { | 	static const uc_function_list_t bss_fns[] = { | ||||||
| 		{ "ctrl", uc_hostapd_bss_ctrl }, | 		{ "ctrl", uc_hostapd_bss_ctrl }, | ||||||
| 		{ "set_config", uc_hostapd_bss_set_config }, | 		{ "set_config", uc_hostapd_bss_set_config }, | ||||||
|  | 		{ "rename", uc_hostapd_bss_rename }, | ||||||
| 		{ "delete", uc_hostapd_bss_delete }, | 		{ "delete", uc_hostapd_bss_delete }, | ||||||
| 	}; | 	}; | ||||||
| 	static const uc_function_list_t iface_fns[] = { | 	static const uc_function_list_t iface_fns[] = { | ||||||
|  | 		{ "set_bss_order", uc_hostapd_iface_set_bss_order }, | ||||||
| 		{ "add_bss", uc_hostapd_iface_add_bss }, | 		{ "add_bss", uc_hostapd_iface_add_bss }, | ||||||
| 		{ "stop", uc_hostapd_iface_stop }, | 		{ "stop", uc_hostapd_iface_stop }, | ||||||
| 		{ "start", uc_hostapd_iface_start }, | 		{ "start", uc_hostapd_iface_start }, | ||||||
|   | |||||||
| @@ -129,7 +129,10 @@ uc_value_t *uc_wpa_freq_info(uc_vm_t *vm, size_t nargs) | |||||||
| 	tmp_channel &= ~((8 << width) - 1); | 	tmp_channel &= ~((8 << width) - 1); | ||||||
| 	center_idx = tmp_channel + center_ofs + (4 << 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; | 	center_idx = (center_idx - channel) * 5 + freq_val; | ||||||
| 	ucv_object_add(ret, "center_freq1", ucv_int64_new(center_idx)); | 	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 *wpa_ucode_registry_remove(uc_value_t *reg, int idx) | ||||||
| { | { | ||||||
| 	uc_value_t *val = wpa_ucode_registry_get(reg, idx); | 	uc_value_t *val = wpa_ucode_registry_get(reg, idx); | ||||||
|  | 	void **dataptr; | ||||||
|  |  | ||||||
| 	if (val) | 	if (!val) | ||||||
| 		ucv_array_set(reg, idx - 1, NULL); | 		return NULL; | ||||||
|  |  | ||||||
|  | 	ucv_array_set(reg, idx - 1, NULL); | ||||||
|  | 	dataptr = ucv_resource_dataptr(val, NULL); | ||||||
|  | 	if (dataptr) | ||||||
|  | 		*dataptr = NULL; | ||||||
|  |  | ||||||
| 	return val; | 	return val; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ | |||||||
| #include "utils/common.h" | #include "utils/common.h" | ||||||
| #include "utils/ucode.h" | #include "utils/ucode.h" | ||||||
| #include "drivers/driver.h" | #include "drivers/driver.h" | ||||||
|  | #include "ap/hostapd.h" | ||||||
| #include "wpa_supplicant_i.h" | #include "wpa_supplicant_i.h" | ||||||
| #include "wps_supplicant.h" | #include "wps_supplicant.h" | ||||||
| #include "bss.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); | 		ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION); | ||||||
| 		if (ie && ie[1] >= 2) { | 		if (ie && ie[1] >= 2) { | ||||||
| 			const struct ieee80211_ht_operation *ht_oper; | 			const struct ieee80211_ht_operation *ht_oper; | ||||||
|  | 			int sec; | ||||||
|  |  | ||||||
| 			ht_oper = (const void *) (ie + 2); | 			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; | 				sec_chan = 1; | ||||||
| 			else if (ht_oper->ht_param & | 			else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) | ||||||
| 				 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) |  | ||||||
| 				sec_chan = -1; | 				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)); | 		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; | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -20,7 +20,7 @@ DEFAULT_PACKAGES += kmod-qca-nss-dp kmod-qca-ssdk swconfig \ | |||||||
| 	kmod-usb-phy-ipq5018 kmod-usb-dwc3-qcom-internal \ | 	kmod-usb-phy-ipq5018 kmod-usb-dwc3-qcom-internal \ | ||||||
| 	kmod-ath11k-ahb  ath11k-firmware-ipq5018 \ | 	kmod-ath11k-ahb  ath11k-firmware-ipq5018 \ | ||||||
| 	kmod-gpio-button-hotplug iwinfo \ | 	kmod-gpio-button-hotplug iwinfo \ | ||||||
| 	qca-ssdk-shell kmod-qca-nss-drv-bridge-mgr \ | 	qca-ssdk-shell \ | ||||||
| 	uboot-envtools | 	uboot-envtools | ||||||
|  |  | ||||||
| $(eval $(call BuildTarget)) | $(eval $(call BuildTarget)) | ||||||
|   | |||||||
| @@ -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; | ||||||
| @@ -20,7 +20,7 @@ DEFAULT_PACKAGES += kmod-qca-nss-dp kmod-qca-ssdk swconfig \ | |||||||
| 	kmod-usb-phy-ipq807x kmod-usb-dwc3-qcom-internal \ | 	kmod-usb-phy-ipq807x kmod-usb-dwc3-qcom-internal \ | ||||||
| 	kmod-ath11k-ahb  ath11k-firmware-ipq60xx \ | 	kmod-ath11k-ahb  ath11k-firmware-ipq60xx \ | ||||||
| 	kmod-gpio-button-hotplug iwinfo \ | 	kmod-gpio-button-hotplug iwinfo \ | ||||||
| 	qca-ssdk-shell kmod-qca-nss-drv-bridge-mgr \ | 	qca-ssdk-shell \ | ||||||
| 	uboot-envtools | 	uboot-envtools | ||||||
|  |  | ||||||
| $(eval $(call BuildTarget)) | $(eval $(call BuildTarget)) | ||||||
|   | |||||||
| @@ -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; | ||||||
| @@ -20,7 +20,7 @@ DEFAULT_PACKAGES += kmod-qca-nss-dp kmod-qca-ssdk swconfig \ | |||||||
| 	kmod-usb-phy-ipq807x kmod-usb-dwc3-qcom-internal \ | 	kmod-usb-phy-ipq807x kmod-usb-dwc3-qcom-internal \ | ||||||
| 	kmod-ath11k-ahb ath11k-firmware-ipq807x \ | 	kmod-ath11k-ahb ath11k-firmware-ipq807x \ | ||||||
| 	kmod-gpio-button-hotplug iwinfo \ | 	kmod-gpio-button-hotplug iwinfo \ | ||||||
| 	qca-ssdk-shell kmod-qca-nss-drv-bridge-mgr \ | 	qca-ssdk-shell \ | ||||||
| 	uboot-envtools | 	uboot-envtools | ||||||
|  |  | ||||||
| $(eval $(call BuildTarget)) | $(eval $(call BuildTarget)) | ||||||
|   | |||||||
| @@ -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; | ||||||
| @@ -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; | ||||||
| @@ -488,6 +488,7 @@ ${channel:+channel=$channel} | |||||||
| ${channel_list:+chanlist=$channel_list} | ${channel_list:+chanlist=$channel_list} | ||||||
| ${hostapd_noscan:+noscan=1} | ${hostapd_noscan:+noscan=1} | ||||||
| ${tx_burst:+tx_queue_data2_burst=$tx_burst} | ${tx_burst:+tx_queue_data2_burst=$tx_burst} | ||||||
|  | #num_global_macaddr=$num_global_macaddr | ||||||
| $base_cfg | $base_cfg | ||||||
|  |  | ||||||
| EOF | EOF | ||||||
| @@ -528,6 +529,7 @@ mac80211_hostapd_setup_bss() { | |||||||
| 	cat >> /var/run/hostapd-$phy.conf <<EOF | 	cat >> /var/run/hostapd-$phy.conf <<EOF | ||||||
| $hostapd_cfg | $hostapd_cfg | ||||||
| bssid=$macaddr | bssid=$macaddr | ||||||
|  | ${default_macaddr:+#default_macaddr} | ||||||
| ${dtim_period:+dtim_period=$dtim_period} | ${dtim_period:+dtim_period=$dtim_period} | ||||||
| ${max_listen_int:+max_listen_interval=$max_listen_int} | ${max_listen_int:+max_listen_interval=$max_listen_int} | ||||||
| EOF | EOF | ||||||
| @@ -542,57 +544,9 @@ mac80211_get_addr() { | |||||||
|  |  | ||||||
| mac80211_generate_mac() { | mac80211_generate_mac() { | ||||||
| 	local phy="$1" | 	local phy="$1" | ||||||
| 	local multiple_bssid="$2" |  | ||||||
| 	local id="${macidx:-0}" | 	local id="${macidx:-0}" | ||||||
|  |  | ||||||
| 	local ref="$(cat /sys/class/ieee80211/${phy}/macaddress)" | 	wdev_tool "$phy" get_macaddr id=$id num_global=$num_global_macaddr mbssid=$multiple_bssid | ||||||
| 	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 )) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| find_phy() { | find_phy() { | ||||||
| @@ -626,11 +580,14 @@ mac80211_prepare_vif() { | |||||||
| 	set_default powersave 0 | 	set_default powersave 0 | ||||||
| 	json_add_string _ifname "$ifname" | 	json_add_string _ifname "$ifname" | ||||||
|  |  | ||||||
|  | 	default_macaddr= | ||||||
| 	[ -n "$macaddr" ] || { | 	[ -n "$macaddr" ] || { | ||||||
| 		macaddr="$(mac80211_generate_mac $phy $multiple_bssid)" | 		macaddr="$(mac80211_generate_mac $phy)" | ||||||
|  		macidx="$(($macidx + 1))" |  		macidx="$(($macidx + 1))" | ||||||
|  | 		default_macaddr=1 | ||||||
| 	} | 	} | ||||||
| 	json_add_string _macaddr "$macaddr" | 	json_add_string _macaddr "$macaddr" | ||||||
|  | 	json_add_string _default_macaddr "$default_macaddr" | ||||||
| 	json_select .. | 	json_select .. | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -754,7 +711,7 @@ mac80211_setup_adhoc() { | |||||||
|  |  | ||||||
| 	json_add_object "$ifname" | 	json_add_object "$ifname" | ||||||
| 	json_add_string mode adhoc | 	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 ssid "$ssid" | ||||||
| 	json_add_string freq "$freq" | 	json_add_string freq "$freq" | ||||||
| 	json_add_string htmode "$iw_htmode" | 	json_add_string htmode "$iw_htmode" | ||||||
| @@ -780,7 +737,7 @@ mac80211_setup_mesh() { | |||||||
|  |  | ||||||
| 	json_add_object "$ifname" | 	json_add_object "$ifname" | ||||||
| 	json_add_string mode mesh | 	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 ssid "$ssid" | ||||||
| 	json_add_string freq "$freq" | 	json_add_string freq "$freq" | ||||||
| 	json_add_string htmode "$iw_htmode" | 	json_add_string htmode "$iw_htmode" | ||||||
| @@ -831,7 +788,6 @@ wpa_supplicant_init_config() { | |||||||
| wpa_supplicant_add_interface() { | wpa_supplicant_add_interface() { | ||||||
| 	local ifname="$1" | 	local ifname="$1" | ||||||
| 	local mode="$2" | 	local mode="$2" | ||||||
| 	local hostapd_ctrl="$3" |  | ||||||
| 	local prev | 	local prev | ||||||
|  |  | ||||||
| 	_wpa_supplicant_common "$ifname" | 	_wpa_supplicant_common "$ifname" | ||||||
| @@ -843,9 +799,8 @@ wpa_supplicant_add_interface() { | |||||||
| 	json_add_string iface "$ifname" | 	json_add_string iface "$ifname" | ||||||
| 	json_add_string mode "$mode" | 	json_add_string mode "$mode" | ||||||
| 	json_add_string config "$_config" | 	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 "$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" | 	[ -n "$wds" ] && json_add_boolean 4addr "$wds" | ||||||
| 	json_add_boolean powersave "$powersave" | 	json_add_boolean powersave "$powersave" | ||||||
| 	[ "$mode" = "mesh" ] && mac80211_add_mesh_params | 	[ "$mode" = "mesh" ] && mac80211_add_mesh_params | ||||||
| @@ -920,7 +875,7 @@ mac80211_setup_supplicant() { | |||||||
| 		wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan" | 		wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan" | ||||||
| 	fi | 	fi | ||||||
|  |  | ||||||
| 	wpa_supplicant_add_interface "$ifname" "$mode" "$hostapd_ctrl" | 	wpa_supplicant_add_interface "$ifname" "$mode" | ||||||
|  |  | ||||||
| 	return 0 | 	return 0 | ||||||
| } | } | ||||||
| @@ -932,6 +887,7 @@ mac80211_setup_vif() { | |||||||
| 	json_select config | 	json_select config | ||||||
| 	json_get_var ifname _ifname | 	json_get_var ifname _ifname | ||||||
| 	json_get_var macaddr _macaddr | 	json_get_var macaddr _macaddr | ||||||
|  | 	json_get_var default_macaddr _default_macaddr | ||||||
| 	json_get_vars mode wds powersave | 	json_get_vars mode wds powersave | ||||||
|  |  | ||||||
| 	set_default powersave 0 | 	set_default powersave 0 | ||||||
| @@ -1014,7 +970,7 @@ mac80211_reset_config() { | |||||||
| 	hostapd_conf_file="/var/run/hostapd-$phy.conf" | 	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 hostapd config_set '{ "phy": "'"$phy"'", "config": "", "prev_config": "'"$hostapd_conf_file"'" }' > /dev/null | ||||||
| 	ubus call wpa_supplicant config_set '{ "phy": "'"$phy"'", "config": [] }' > /dev/null | 	ubus call wpa_supplicant config_set '{ "phy": "'"$phy"'", "config": [] }' > /dev/null | ||||||
| 	wdev_tool "$phy" '{}' | 	wdev_tool "$phy" set_config '{}' | ||||||
| } | } | ||||||
|  |  | ||||||
| drv_mac80211_setup() { | drv_mac80211_setup() { | ||||||
| @@ -1116,7 +1072,7 @@ drv_mac80211_setup() { | |||||||
|  |  | ||||||
| 	mac80211_prepare_iw_htmode | 	mac80211_prepare_iw_htmode | ||||||
| 	active_ifnames= | 	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 | 	for_each_interface "ap sta adhoc mesh monitor" mac80211_setup_vif | ||||||
|  |  | ||||||
| 	[ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_set_config "$phy" | 	[ -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" | 	[ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_start "$phy" | ||||||
|  |  | ||||||
| 	json_set_namespace wdev_uc prev | 	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" | 	json_set_namespace "$prev" | ||||||
|  |  | ||||||
| 	for_each_interface "ap sta adhoc mesh monitor" mac80211_set_vif_txpower | 	for_each_interface "ap sta adhoc mesh monitor" mac80211_set_vif_txpower | ||||||
|   | |||||||
| @@ -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; | ||||||
| @@ -771,10 +771,10 @@ hostapd_set_bss_options() { | |||||||
| 			wps_possible=1 | 			wps_possible=1 | ||||||
| 			# Here we make the assumption that if we're in open mode | 			# Here we make the assumption that if we're in open mode | ||||||
| 			# with WPS enabled, we got to be in unconfigured state. | 			# with WPS enabled, we got to be in unconfigured state. | ||||||
|  | 			vlan_possible=1 | ||||||
| 			wps_not_configured=1 | 			wps_not_configured=1 | ||||||
| 			[ "$macfilter" = radius ] && { | 			[ "$macfilter" = radius ] && { | ||||||
| 				append_radius_server | 				append_radius_server | ||||||
| 				vlan_possible=1 |  | ||||||
| 			} | 			} | ||||||
| 		;; | 		;; | ||||||
| 		psk|sae|psk-sae) | 		psk|sae|psk-sae) | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ boot() { | |||||||
| 	case "$(board_name)" in | 	case "$(board_name)" in | ||||||
| 	cig,wf660a) | 	cig,wf660a) | ||||||
| 		mmc_dev=$(echo $(find_mmc_part "0:ETHPHYFW") | sed 's/^.\{5\}//') | 		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 | 	esac | ||||||
|  |  | ||||||
| @@ -75,7 +75,10 @@ boot() { | |||||||
| 			PART_NAME=rootfs_1 | 			PART_NAME=rootfs_1 | ||||||
| 		fi	 | 		fi	 | ||||||
| 		;; | 		;; | ||||||
| 	yuncore,ax840) | 	cig,wf186w|\ | ||||||
|  | 	cig,wf186h|\ | ||||||
|  | 	yuncore,ax840|\ | ||||||
|  | 	yuncore,fap655) | ||||||
| 		PART_NAME=rootfs_1 | 		PART_NAME=rootfs_1 | ||||||
| 		;; | 		;; | ||||||
| 	*) | 	*) | ||||||
|   | |||||||
| @@ -4,10 +4,10 @@ PKG_NAME:=ucentral-client | |||||||
| PKG_RELEASE:=1 | PKG_RELEASE:=1 | ||||||
|  |  | ||||||
| PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-client.git | 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_PROTO:=git | ||||||
| PKG_SOURCE_DATE:=2022-06-22 | PKG_SOURCE_DATE:=2022-06-22 | ||||||
| PKG_SOURCE_VERSION:=d898a7afb595d6c2350d38d027bf142e72060662 | PKG_SOURCE_VERSION:=3bbcd36c6111e08df6c8f13e0079826ec417cc85 | ||||||
|  |  | ||||||
| PKG_LICENSE:=BSD-3-Clause | PKG_LICENSE:=BSD-3-Clause | ||||||
| PKG_MAINTAINER:=John Crispin <john@phrozen.org> | PKG_MAINTAINER:=John Crispin <john@phrozen.org> | ||||||
|   | |||||||
| @@ -231,14 +231,27 @@ function dhcp_subscriber_remove_cb(remove) { | |||||||
| 	printf('dhcp remove: %.J\n', 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) { | function dhcp_relay_subscriber_notify_cb(notify) { | ||||||
| 	let ifname = split(notify.data.info.device, '-v'); | 	let ifname = split(notify.data.info.device, '-v'); | ||||||
| 	let hapd = hostapd[ifname[0]]; | 	let hapd = hostapd[ifname[0]]; | ||||||
| 	let vlan = ifname[1]; | 	let vlan = ifname[1]; | ||||||
| 	if (hapd) { | 	if (hapd) { | ||||||
| 		vlan ??= hapd.config.vlan_id; | 		vlan ??= hapd.config.vlan_id; | ||||||
| 		let circuit_id = `${vlan}`; | 		let circuit_id = match_dhcp_relay_option82(relay['vlan' + vlan]?.circuit_id, hapd); | ||||||
| 		let remote_id = hapd.bssid; | 		let remote_id = match_dhcp_relay_option82(relay['vlan' + vlan]?.remote_id, hapd); | ||||||
| 		return { | 		return { | ||||||
| 			address: relay['vlan' + vlan]?.server, | 			address: relay['vlan' + vlan]?.server, | ||||||
| 			options: [ | 			options: [ | ||||||
|   | |||||||
| @@ -4,10 +4,10 @@ PKG_NAME:=ucentral-schema | |||||||
| PKG_RELEASE:=1 | PKG_RELEASE:=1 | ||||||
|  |  | ||||||
| PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-schema.git | PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-schema.git | ||||||
| PKG_MIRROR_HASH:=6da4c8a82c5393d54bfe1a91479730cc126e7de1cf1565a0274d600759e668e0 | PKG_MIRROR_HASH:=edb9bc0b8209226f585c724c88720eab2263c33eff6ebe2f2a5898896eb1fc11 | ||||||
| PKG_SOURCE_PROTO:=git | PKG_SOURCE_PROTO:=git | ||||||
| PKG_SOURCE_DATE:=2022-05-29 | PKG_SOURCE_DATE:=2022-05-29 | ||||||
| PKG_SOURCE_VERSION:=708b1de986b63c35e4f5e79a3183ffb4a36f40a1 | PKG_SOURCE_VERSION:=e9529eab9cae27f170bdb440eb60d7a0a2588cea | ||||||
|  |  | ||||||
| PKG_MAINTAINER:=John Crispin <john@phrozen.org> | PKG_MAINTAINER:=John Crispin <john@phrozen.org> | ||||||
| PKG_LICENSE:=BSD-3-Clause | PKG_LICENSE:=BSD-3-Clause | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ board=$(board_name) | |||||||
|  |  | ||||||
| case "$board" in | case "$board" in | ||||||
| cig,wf186w|\ | cig,wf186w|\ | ||||||
|  | cig,wf186h|\ | ||||||
| cig,wf194c4|\ | cig,wf194c4|\ | ||||||
| cig,wf194c|\ | cig,wf194c|\ | ||||||
| cig,wf610d|\ | cig,wf610d|\ | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								feeds/ucentral/ucentral-schema/files/etc/uci-defaults/99-ucentral-event
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										10
									
								
								feeds/ucentral/ucentral-schema/files/etc/uci-defaults/99-ucentral-event
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,5 +1,15 @@ | |||||||
| #!/bin/sh | #!/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') | wan=$(cat /etc/board.json | jsonfilter -e '@.network.wan.device') | ||||||
| [ -z "$wan" ] && eval $(jsonfilter -i /etc/board.json -e 'wan=@.network.wan.ports.*') | [ -z "$wan" ] && eval $(jsonfilter -i /etc/board.json -e 'wan=@.network.wan.ports.*') | ||||||
| for w in $wan; do | for w in $wan; do | ||||||
|   | |||||||
| @@ -68,7 +68,7 @@ global.start = function() { | |||||||
| 		global.uci = require('uci').cursor(); | 		global.uci = require('uci').cursor(); | ||||||
| 		global.ubus.conn = require('ubus').connect(); | 		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'); | 			printf('loading ' + module + '\n'); | ||||||
| 			global[module] = require(module); | 			global[module] = require(module); | ||||||
| 			if (exists(global[module], 'init')) | 			if (exists(global[module], 'init')) | ||||||
|   | |||||||
| @@ -1,64 +1,75 @@ | |||||||
| function result(error, text, data) { | function result(error, event, text, data) { | ||||||
| 	let res = { | 	let res = { | ||||||
| 		error: error, | 		error: error, | ||||||
| 		text: text || 'unknown', | 		text: text || 'unknown', | ||||||
| 		...(data ? { data } : {}), | 		...(data ? data : {}), | ||||||
| 	}; | 	}; | ||||||
|  | 	if (event) | ||||||
|  | 		global.event.send('rrm.bss.command', res); | ||||||
| 	return res; | 	return res; | ||||||
| } | } | ||||||
|  |  | ||||||
| const actions = { | 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) { | 	kick: function(msg) { | ||||||
| 		if (global.station.kick(msg)) | 		if (!global.station.kick(msg)) | ||||||
| 			return result(1, 'station ' + msg.mac + ' is unknown'); | 			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": "channel": 1}' | ||||||
| 	// 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": "ssid": "Pluto" }' | ||||||
| 	// ubus call usteer2 get_beacon_request '{"addr": "4e:7f:3e:2c:8a:68"}' | 	// ubus call usteer2 get_beacon_request '{"addr": "4e:7f:3e:2c:8a:68"}' | ||||||
| 	beacon_request: function(msg) { | 	beacon_request: function(msg) { | ||||||
| 		if (!global.station.beacon_request(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) { | 	channel_switch: function(msg) { | ||||||
| 		if (!global.local.switch_chan(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) { | 	tx_power: function(msg) { | ||||||
| 		if (!global.phy.txpower(msg)) | 		if (!global.phy.txpower(msg)) | ||||||
| 			return result(1, 'PHY ' + msg,phy + ' failed to set TX power'); | 			return result(1, msg.event, 'BSS ' + msg.bssid + ' failed to set TX power', { action: 'tx_power', bssid: msg.bssid }); | ||||||
|  | 	 | ||||||
| 		return result(0, 'PHY ' + msg.phy + ' changed TX power'); | 		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) { | 	bss_transition: function(msg) { | ||||||
| 		if (!global.station.bss_transition(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 { | return { | ||||||
| 	handle: function(msg) { | 	handle: function(msg) { | ||||||
| 		if (!actions[msg.action]) | 		if (!actions[msg.action]) | ||||||
| 			return result(1, 'unknown action ' + msg.action); | 			return result(1, msg.event, 'unknown action ' + msg.action); | ||||||
| 		try { | 		try { | ||||||
| 			return actions[msg.action](msg); | 			return actions[msg.action](msg); | ||||||
| 		} catch(e) { | 		} 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'); | ||||||
| 		} | 		} | ||||||
| 	}, | 	}, | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -6,7 +6,16 @@ let state = {}; | |||||||
| let hapd = {}; | let hapd = {}; | ||||||
| let handlers = {}; | 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) | 	if (band == '2G' && channel >= 1 && channel <= 13) | ||||||
| 		return 2407 + channel * 5; | 		return 2407 + channel * 5; | ||||||
| 	else if (band == '2G' && channel == 14) | 	else if (band == '2G' && channel == 14) | ||||||
| @@ -58,23 +67,6 @@ function hapd_update() { | |||||||
| 	return 5000; | 	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) { | function hapd_subunsub(path, sub) { | ||||||
| 	/* check if this is a hostapd instance */ | 	/* check if this is a hostapd instance */ | ||||||
| 	let name = split(path, '.'); | 	let name = split(path, '.'); | ||||||
| @@ -88,6 +80,7 @@ function hapd_subunsub(path, sub) { | |||||||
| 	/* the hostapd instance disappeared */ | 	/* the hostapd instance disappeared */ | ||||||
| 	if (!sub) { | 	if (!sub) { | ||||||
| 		global.event.send('rrm.bss.del', { bssid: hapd[name] }); | 		global.event.send('rrm.bss.del', { bssid: hapd[name] }); | ||||||
|  | 		global.neighbor.local_del(name); | ||||||
| 		delete hapd[name]; | 		delete hapd[name]; | ||||||
| 		delete state[name]; | 		delete state[name]; | ||||||
| 		return; | 		return; | ||||||
| @@ -122,14 +115,15 @@ function hapd_subunsub(path, sub) { | |||||||
|  |  | ||||||
| 	/* ask hostapd for the local neighbourhood report data */ | 	/* ask hostapd for the local neighbourhood report data */ | ||||||
| 	let rrm = global.ubus.conn.call(path, 'rrm_nr_get_own'); | 	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; | 		hapd[name].rrm_nr = rrm.value; | ||||||
|  | 		global.neighbor.local_add(name, rrm.value); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	global.neighbor.update(); | ||||||
|  | 	 | ||||||
| 	/* trigger an initial channel survey */ | 	/* trigger an initial channel survey */ | ||||||
| 	channel_survey(name); | 	//channel_survey(name); | ||||||
|  |  | ||||||
| 	/* update the neighborhood reports */ |  | ||||||
| 	hapd_nr_update(hapd[name].ssid); |  | ||||||
|  |  | ||||||
| 	/* send an event */ | 	/* send an event */ | ||||||
| 	global.event.send('rrm.bss.add', { | 	global.event.send('rrm.bss.add', { | ||||||
| @@ -137,7 +131,8 @@ function hapd_subunsub(path, sub) { | |||||||
| 		ssid: hapd[name].ssid, | 		ssid: hapd[name].ssid, | ||||||
| 		freq: hapd[name].freq, | 		freq: hapd[name].freq, | ||||||
| 		channel: hapd[name].channel, | 		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); | 	printf('%.J\n', req); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function channel_switch_handler(type, data) { | ||||||
|  | 	global.event.send('rrm.bss.channel-switch', { bssid: data.bssid, freq: data.freq }); | ||||||
|  | } | ||||||
|  |  | ||||||
| return { | return { | ||||||
| 	status: function() { | 	status: function() { | ||||||
| 		return hapd; | 		return hapd; | ||||||
| @@ -193,7 +192,8 @@ return { | |||||||
| 				ucentral_subunsub(true); | 				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) { | 	register_handler: function(event, handler) { | ||||||
| @@ -203,16 +203,36 @@ return { | |||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	switch_chan: function(msg) { | 	switch_chan: function(msg) { | ||||||
| 		if (!msg.addr || !msg.params?.band || !msg.params?.channel) | 		if (!msg.bssid || !msg.channel) | ||||||
| 			return false; | 			return false; | ||||||
| 		for (let bss, v in hapd) { | 		for (let bss, v in hapd) { | ||||||
| 			if (v.bssid != lc(msg.addr)) | 			if (v.bssid != lc(msg.bssid)) | ||||||
| 				continue; | 				continue; | ||||||
| 			return global.ubus.conn.call('hostapd.' + bss, 'switch_chan', { | 			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 | 				bcn_count: 10 | ||||||
| 			}) == null; | 			}) == null; | ||||||
| 		} | 		} | ||||||
| 		return false; | 		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; | ||||||
|  | 	}, | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										53
									
								
								feeds/ucentral/usteer2/files/usr/share/usteer/neighbor.uc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								feeds/ucentral/usteer2/files/usr/share/usteer/neighbor.uc
									
									
									
									
									
										Normal 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; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
| @@ -147,12 +147,12 @@ return { | |||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	txpower: function(msg) { | 	txpower: function(msg) { | ||||||
| 		if (!msg.phy || !msg.params?.level) | 		if (!msg.bssid || !msg.level) | ||||||
| 			return false; | 			return false; | ||||||
| 		if (!this.phys[msg.phy]) | 		let wiphy = global.local.bssid_to_phy(msg.bssid); | ||||||
| 			return false; | 		if (wiphy < 0) | ||||||
|  | 			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}); | 		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; | 		return true; | ||||||
| 	}, | 	}, | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -164,7 +164,7 @@ return { | |||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	beacon_request: function(msg) { | 	beacon_request: function(msg) { | ||||||
| 		if (!msg.addr || (!msg.params?.channel && !msg.params?.ssid)) | 		if (!msg.addr || (!msg.channel && !msg.ssid)) | ||||||
| 			return false; | 			return false; | ||||||
|  |  | ||||||
| 		let station = stations[msg.addr]; | 		let station = stations[msg.addr]; | ||||||
| @@ -185,20 +185,20 @@ return { | |||||||
| 		let payload = { | 		let payload = { | ||||||
| 			addr: msg.addr, | 			addr: msg.addr, | ||||||
| 			mode: msg.params?.mode || 1, | 			mode: msg.params?.mode || 1, | ||||||
| 			op_class: msg.params?.op_class || 128, | 			op_class: msg.op_class || 128, | ||||||
| 			duration: msg.params?.duration || 100, | 			duration: msg.duration || 100, | ||||||
| 		}; | 		}; | ||||||
| 		if (msg.params.channel) | 		if (msg.channel) | ||||||
| 			payload.channel = msg.params.channel; | 			payload.channel = msg.channel; | ||||||
| 		else | 		else | ||||||
| 			payload.ssid = msg.params.ssid; | 			payload.ssid = msg.ssid; | ||||||
| 		global.ubus.conn.call(`hostapd.${station.device}`, 'rrm_beacon_req', payload); | 		global.ubus.conn.call(`hostapd.${station.device}`, 'rrm_beacon_req', payload); | ||||||
|  |  | ||||||
| 		return true; | 		return true; | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	kick: function(msg) { | 	kick: function(msg) { | ||||||
| 		if (!msg.addr || !msg.params?.ban_time || !msg.params?.reason) | 		if (!msg.addr || !msg.ban_time || !msg.reason) | ||||||
| 			return false; | 			return false; | ||||||
|  |  | ||||||
| 		if (!exists(stations, msg.addr)) | 		if (!exists(stations, msg.addr)) | ||||||
| @@ -206,9 +206,9 @@ return { | |||||||
|  |  | ||||||
| 		let payload = { | 		let payload = { | ||||||
| 			addr: msg.addr, | 			addr: msg.addr, | ||||||
| 			reason: msg.params.reason, | 			reason: msg.reason, | ||||||
| 			deauth: 1, | 			deauth: 1, | ||||||
| 			ban_time: msg.params.ban_time | 			ban_time: msg.ban_time | ||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| 		/* tell hostapd to kick a station via ubus */ | 		/* tell hostapd to kick a station via ubus */ | ||||||
| @@ -223,17 +223,16 @@ return { | |||||||
| 		return stations; | 		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) { | 	bss_transition: function(msg) { | ||||||
| 		if (!msg.addr || !msg.params?.neighbors) | 		if (!msg.addr || !msg.neighbors) | ||||||
| 			return false; | 			return false; | ||||||
| 		if (!stations[msg.addr]) | 		if (!stations[msg.addr]) | ||||||
| 			return false; | 			return false; | ||||||
|  |  | ||||||
| 		let neighbors = []; | 		let neighbors = []; | ||||||
| 		for (let i = 0; i < 5; i++) | 		for (let i = 0; i < 5; i++) | ||||||
| 			if (msg.params?.neighbors[i]) | 			if (msg.neighbors[i]) | ||||||
| 				push(neighbors, replace(msg.params?.neighbors[i], ':', '')); | 				push(neighbors, replace(msg.neighbors[i], ':', '')); | ||||||
|  |  | ||||||
| 		let ret = global.ubus.conn.call(`hostapd.${stations[msg.addr].device}`, 'wnm_disassoc_imminent', { | 		let ret = global.ubus.conn.call(`hostapd.${stations[msg.addr].device}`, 'wnm_disassoc_imminent', { | ||||||
| 			addr: msg.addr, duration: 20, abridged: 1, neighbors }) == null; | 			addr: msg.addr, duration: 20, abridged: 1, neighbors }) == null; | ||||||
|   | |||||||
| @@ -26,6 +26,7 @@ endef | |||||||
| ALLWIFIBOARDS:= \ | ALLWIFIBOARDS:= \ | ||||||
| 	cig-wf188 \ | 	cig-wf188 \ | ||||||
| 	cig-wf186w \ | 	cig-wf186w \ | ||||||
|  | 	cig-wf186h \ | ||||||
| 	cig-wf660a \ | 	cig-wf660a \ | ||||||
| 	cig-wf194c \ | 	cig-wf194c \ | ||||||
| 	cig-wf194c4 \ | 	cig-wf194c4 \ | ||||||
| @@ -348,6 +349,7 @@ endef | |||||||
|  |  | ||||||
| $(eval $(call generate-ath11k-wifi-package,cig-wf188,Cigtech WF188)) | $(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-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-wf660a,Cigtech WF660a)) | ||||||
| $(eval $(call generate-ath11k-wifi-package,cig-wf194c,Cigtech WF194c)) | $(eval $(call generate-ath11k-wifi-package,cig-wf194c,Cigtech WF194c)) | ||||||
| $(eval $(call generate-ath11k-wifi-package,cig-wf194c4,Cigtech WF194c4)) | $(eval $(call generate-ath11k-wifi-package,cig-wf194c4,Cigtech WF194c4)) | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								feeds/wifi-ax/ath11k-wifi/board-cig-wf186h.bin.IPQ5018
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								feeds/wifi-ax/ath11k-wifi/board-cig-wf186h.bin.IPQ5018
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								feeds/wifi-ax/ath11k-wifi/board-cig-wf186h.bin.QCN6122
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								feeds/wifi-ax/ath11k-wifi/board-cig-wf186h.bin.QCN6122
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| import * as nl80211 from "nl80211"; | import * as nl80211 from "nl80211"; | ||||||
| import * as rtnl from "rtnl"; | import * as rtnl from "rtnl"; | ||||||
| import { readfile } from "fs"; | import { readfile, glob, basename, readlink } from "fs"; | ||||||
|  |  | ||||||
| const iftypes = { | const iftypes = { | ||||||
| 	ap: nl80211.const.NL80211_IFTYPE_AP, | 	ap: nl80211.const.NL80211_IFTYPE_AP, | ||||||
| @@ -94,6 +94,156 @@ function wdev_create(phy, name, data) | |||||||
| 	return null; | 	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 = { | const vlist_proto = { | ||||||
| 	update: function(values, arg) { | 	update: function(values, arg) { | ||||||
| 		let data = this.data; | 		let data = this.data; | ||||||
| @@ -150,7 +300,7 @@ function is_equal(val1, val2) { | |||||||
| 			if (!is_equal(val1[key], val2[key])) | 			if (!is_equal(val1[key], val2[key])) | ||||||
| 				return false; | 				return false; | ||||||
| 		for (let key in val2) | 		for (let key in val2) | ||||||
| 			if (!val1[key]) | 			if (val1[key] == null) | ||||||
| 				return false; | 				return false; | ||||||
| 		return true; | 		return true; | ||||||
| 	} else { | 	} else { | ||||||
| @@ -165,4 +315,4 @@ function vlist_new(cb) { | |||||||
| 		}, vlist_proto); | 		}, 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 }; | ||||||
|   | |||||||
| @@ -725,8 +725,7 @@ hostapd_set_bss_options() { | |||||||
| 		[ -n "$wpa_strict_rekey" ] && append bss_conf "wpa_strict_rekey=$wpa_strict_rekey" "$N" | 		[ -n "$wpa_strict_rekey" ] && append bss_conf "wpa_strict_rekey=$wpa_strict_rekey" "$N" | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	set_default nasid "${macaddr//\:}" | 	[ -n "$nasid" ] && append bss_conf "nas_identifier=$nasid" "$N" | ||||||
| 	append bss_conf "nas_identifier=$nasid" "$N" |  | ||||||
|  |  | ||||||
| 	[ -n "$acct_server" ] && { | 	[ -n "$acct_server" ] && { | ||||||
| 		append bss_conf "acct_server_addr=$acct_server" "$N" | 		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 | 			# Here we make the assumption that if we're in open mode | ||||||
| 			# with WPS enabled, we got to be in unconfigured state. | 			# with WPS enabled, we got to be in unconfigured state. | ||||||
| 			wps_not_configured=1 | 			wps_not_configured=1 | ||||||
|  | 			vlan_possible=1 | ||||||
| 			[ "$macfilter" = radius ] && { | 			[ "$macfilter" = radius ] && { | ||||||
| 				append_radius_server | 				append_radius_server | ||||||
| 				vlan_possible=1 |  | ||||||
| 			} | 			} | ||||||
| 		;; | 		;; | ||||||
| 		psk|sae|psk-sae) | 		psk|sae|psk-sae) | ||||||
| @@ -794,6 +793,9 @@ hostapd_set_bss_options() { | |||||||
| 			} | 			} | ||||||
| 			[ "$eapol_version" -ge "1" -a "$eapol_version" -le "2" ] && append bss_conf "eapol_version=$eapol_version" "$N" | 			[ "$eapol_version" -ge "1" -a "$eapol_version" -le "2" ] && append bss_conf "eapol_version=$eapol_version" "$N" | ||||||
|  |  | ||||||
|  | 			[ "$macfilter" = radius ] && { | ||||||
|  | 				append_radius_server | ||||||
|  | 			} | ||||||
| 			set_default dynamic_vlan 0 | 			set_default dynamic_vlan 0 | ||||||
| 			vlan_possible=1 | 			vlan_possible=1 | ||||||
| 			wps_possible=1 | 			wps_possible=1 | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| let libubus = require("ubus"); | let libubus = require("ubus"); | ||||||
| import { open, readfile } from "fs"; | 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(); | let ubus = libubus.connect(); | ||||||
|  |  | ||||||
| @@ -26,12 +26,11 @@ function iface_remove(cfg) | |||||||
| 	if (!cfg || !cfg.bss || !cfg.bss[0] || !cfg.bss[0].ifname) | 	if (!cfg || !cfg.bss || !cfg.bss[0] || !cfg.bss[0].ifname) | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
| 	hostapd.remove_iface(cfg.bss[0].ifname); |  | ||||||
| 	for (let bss in cfg.bss) | 	for (let bss in cfg.bss) | ||||||
| 		wdev_remove(bss.ifname); | 		wdev_remove(bss.ifname); | ||||||
| } | } | ||||||
|  |  | ||||||
| function iface_gen_config(phy, config) | function iface_gen_config(phy, config, start_disabled) | ||||||
| { | { | ||||||
| 	let str = `data: | 	let str = `data: | ||||||
| ${join("\n", config.radio.data)} | ${join("\n", config.radio.data)} | ||||||
| @@ -41,18 +40,93 @@ channel=${config.radio.channel} | |||||||
| 	for (let i = 0; i < length(config.bss); i++) { | 	for (let i = 0; i < length(config.bss); i++) { | ||||||
| 		let bss = config.bss[i]; | 		let bss = config.bss[i]; | ||||||
| 		let type = i > 0 ? "bss" : "interface"; | 		let type = i > 0 ? "bss" : "interface"; | ||||||
|  | 		let nasid = bss.nasid ?? replace(bss.bssid, ":", ""); | ||||||
|  |  | ||||||
| 		str += ` | 		str += ` | ||||||
| ${type}=${bss.ifname} | ${type}=${bss.ifname} | ||||||
|  | bssid=${bss.bssid} | ||||||
| ${join("\n", bss.data)} | ${join("\n", bss.data)} | ||||||
|  | nas_identifier=${nasid} | ||||||
|  | `; | ||||||
|  | 		if (start_disabled) | ||||||
|  | 			str += ` | ||||||
|  | start_disabled=1 | ||||||
| `; | `; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return str; | 	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=${phy}:${config_inline}`); | ||||||
|  | 	if (ret < 0) | ||||||
|  | 		return false; | ||||||
|  |  | ||||||
|  | 	if (!phy_status) | ||||||
|  | 		return true; | ||||||
|  |  | ||||||
|  | 	let iface = hostapd.interfaces[phy]; | ||||||
|  | 	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; | ||||||
|  |  | ||||||
|  | 	hostapd.remove_iface(phy); | ||||||
| 	iface_remove(old_config); | 	iface_remove(old_config); | ||||||
| 	iface_remove(config); | 	iface_remove(config); | ||||||
|  |  | ||||||
| @@ -61,15 +135,29 @@ function iface_restart(phy, config, old_config) | |||||||
| 		return; | 		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 bss = config.bss[0]; | ||||||
| 	let err = wdev_create(phy, bss.ifname, { mode: "ap" }); | 	let err = wdev_create(phy, bss.ifname, { mode: "ap" }); | ||||||
| 	if (err) | 	if (err) | ||||||
| 		hostapd.printf(`Failed to create ${bss.ifname} on phy ${phy}: ${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 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 }); | 	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}`); | 		hostapd.printf(`hostapd.add_iface failed for phy ${phy} ifname=${bss.ifname}`); | ||||||
| 	ubus.call("wpa_supplicant", "phy_set_state", { phy: phy, stop: false }); | 	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}`); | 	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)) | 	if (!old_config || !is_equal(old_config.radio, config.radio)) | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| @@ -122,82 +267,230 @@ function iface_reload_config(phy, config, old_config) | |||||||
| 	if (!old_config.bss || !old_config.bss[0]) | 	if (!old_config.bss || !old_config.bss[0]) | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| 	if (config.bss[0].ifname != old_config.bss[0].ifname) | 	let iface = hostapd.interfaces[phy]; | ||||||
| 		return false; | 	if (!iface) { | ||||||
|  | 		hostapd.printf(`Could not find previous interface ${iface_name}`); | ||||||
| 	let iface_name = config.bss[0].ifname; |  | ||||||
| 	let iface = hostapd.interfaces[iface_name]; |  | ||||||
| 	if (!iface) |  | ||||||
| 		return false; | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	let iface_name = old_config.bss[0].ifname; | ||||||
| 	let first_bss = hostapd.bss[iface_name]; | 	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; | 		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); | 	let config_inline = iface_gen_config(phy, config); | ||||||
|  |  | ||||||
| 	bss_reload_psk(first_bss, config.bss[0], old_config.bss[0]); | 	// Step 7: fill in the gaps with new interfaces | ||||||
| 	if (!is_equal(config.bss[0], old_config.bss[0])) { | 	for (let i = 0; i < length(config.bss); i++) { | ||||||
| 		if (phy_is_fullmac(phy)) | 		let ifname = config.bss[i].ifname; | ||||||
| 			return false; | 		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; | 			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}'`); | 		hostapd.printf(`Reload config for bss '${config.bss[0].ifname}' on phy '${phy}'`); | ||||||
| 		if (first_bss.set_config(config_inline, 0) < 0) { | 		if (bss.set_config(config_inline, i) < 0) { | ||||||
| 			hostapd.printf(`Failed to set config`); | 			hostapd.printf(`Failed to set config for bss ${ifname}`); | ||||||
| 			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`); |  | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -205,23 +498,47 @@ function iface_reload_config(phy, config, old_config) | |||||||
| 	return true; | 	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) | function iface_set_config(phy, config) | ||||||
| { | { | ||||||
| 	let old_config = hostapd.data.config[phy]; | 	let old_config = hostapd.data.config[phy]; | ||||||
|  |  | ||||||
| 	hostapd.data.config[phy] = config; | 	hostapd.data.config[phy] = config; | ||||||
|  |  | ||||||
| 	if (!config) | 	if (!config) { | ||||||
|  | 		hostapd.remove_iface(phy); | ||||||
| 		return iface_remove(old_config); | 		return iface_remove(old_config); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	let ret = iface_reload_config(phy, config, old_config); | 	let phydev = phy_open(phy); | ||||||
| 	if (ret) { | 	if (!phydev) { | ||||||
| 		hostapd.printf(`Reloaded settings for phy ${phy}`); | 		hostapd.printf(`Failed to open phy ${phy}`); | ||||||
| 		return 0; | 		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}`); | 	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) | function config_add_bss(config, name) | ||||||
| @@ -268,16 +585,28 @@ function iface_load_config(filename) | |||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		if (val[0] == "#num_global_macaddr" || | ||||||
|  | 		    val[0] == "mbssid") | ||||||
|  | 			config[val[0]] = int(val[1]); | ||||||
|  |  | ||||||
| 		push(config.radio.data, line); | 		push(config.radio.data, line); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	while ((line = trim(f.read("line"))) != null) { | 	while ((line = trim(f.read("line"))) != null) { | ||||||
|  | 		if (line == "#default_macaddr") | ||||||
|  | 			bss.default_macaddr = true; | ||||||
|  |  | ||||||
| 		let val = split(line, "=", 2); | 		let val = split(line, "=", 2); | ||||||
| 		if (!val[0]) | 		if (!val[0]) | ||||||
| 			continue; | 			continue; | ||||||
|  |  | ||||||
| 		if (val[0] == "bssid") | 		if (val[0] == "bssid") { | ||||||
| 			bss.bssid = val[1]; | 			bss.bssid = lc(val[1]); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (val[0] == "nas_identifier") | ||||||
|  | 			bss.nasid = val[1]; | ||||||
|  |  | ||||||
| 		if (val[0] == "bss") { | 		if (val[0] == "bss") { | ||||||
| 			bss = config_add_bss(config, val[1]); | 			bss = config_add_bss(config, val[1]); | ||||||
| @@ -294,28 +623,33 @@ function iface_load_config(filename) | |||||||
| 	return config; | 	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 = { | let main_obj = { | ||||||
| 	reload: { | 	reload: { | ||||||
| 		args: { | 		args: { | ||||||
| 			phy: "", | 			phy: "", | ||||||
| 		}, | 		}, | ||||||
| 		call: function(req) { | 		call: ex_wrap(function(req) { | ||||||
| 			try { | 			let phy_list = req.args.phy ? [ req.args.phy ] : keys(hostapd.data.config); | ||||||
| 				let phy_list = req.args.phy ? [ req.args.phy ] : keys(hostapd.data.config); | 			for (let phy_name in phy_list) { | ||||||
| 				for (let phy_name in phy_list) { | 				let phy = hostapd.data.config[phy_name]; | ||||||
| 					let phy = hostapd.data.config[phy_name]; | 				let config = iface_load_config(phy.orig_file); | ||||||
| 					let config = iface_load_config(phy.orig_file); | 				iface_set_config(phy_name, config); | ||||||
| 					iface_set_config(phy_name, config); |  | ||||||
| 				} |  | ||||||
| 			} catch(e) { |  | ||||||
| 				hostapd.printf(`Error reloading config: ${e}\n${e.stacktrace[0].context}`); |  | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; |  | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} | 		}) | ||||||
| 	}, | 	}, | ||||||
| 	apsta_state: { | 	apsta_state: { | ||||||
| 		args: { | 		args: { | ||||||
| @@ -326,7 +660,7 @@ let main_obj = { | |||||||
| 			csa: true, | 			csa: true, | ||||||
| 			csa_count: 0, | 			csa_count: 0, | ||||||
| 		}, | 		}, | ||||||
| 		call: function(req) { | 		call: ex_wrap(function(req) { | ||||||
| 			if (req.args.up == null || !req.args.phy) | 			if (req.args.up == null || !req.args.phy) | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; | 				return libubus.STATUS_INVALID_ARGUMENT; | ||||||
|  |  | ||||||
| @@ -335,7 +669,7 @@ let main_obj = { | |||||||
| 			if (!config || !config.bss || !config.bss[0] || !config.bss[0].ifname) | 			if (!config || !config.bss || !config.bss[0] || !config.bss[0].ifname) | ||||||
| 				return 0; | 				return 0; | ||||||
|  |  | ||||||
| 			let iface = hostapd.interfaces[config.bss[0].ifname]; | 			let iface = hostapd.interfaces[phy]; | ||||||
| 			if (!iface) | 			if (!iface) | ||||||
| 				return 0; | 				return 0; | ||||||
|  |  | ||||||
| @@ -344,34 +678,10 @@ let main_obj = { | |||||||
| 				return 0; | 				return 0; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			let freq = req.args.frequency; | 			if (!req.args.frequency) | ||||||
| 			if (!freq) |  | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; | 				return libubus.STATUS_INVALID_ARGUMENT; | ||||||
|  |  | ||||||
| 			let sec_offset = req.args.sec_chan_offset; | 			let freq_info = iface_freq_info(iface, config, req.args); | ||||||
| 			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); |  | ||||||
| 			if (!freq_info) | 			if (!freq_info) | ||||||
| 				return libubus.STATUS_UNKNOWN_ERROR; | 				return libubus.STATUS_UNKNOWN_ERROR; | ||||||
|  |  | ||||||
| @@ -380,14 +690,34 @@ let main_obj = { | |||||||
| 				freq_info.csa_count = req.args.csa_count ?? 10; | 				freq_info.csa_count = req.args.csa_count ?? 10; | ||||||
| 				ret = iface.switch_channel(freq_info); | 				ret = iface.switch_channel(freq_info); | ||||||
| 			} else { | 			} else { | ||||||
| 				iface.stop(); |  | ||||||
| 				ret = iface.start(freq_info); | 				ret = iface.start(freq_info); | ||||||
| 			} | 			} | ||||||
| 			if (!ret) | 			if (!ret) | ||||||
| 				return libubus.STATUS_UNKNOWN_ERROR; | 				return libubus.STATUS_UNKNOWN_ERROR; | ||||||
|  |  | ||||||
| 			return 0; | 			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: { | 	config_set: { | ||||||
| 		args: { | 		args: { | ||||||
| @@ -395,7 +725,7 @@ let main_obj = { | |||||||
| 			config: "", | 			config: "", | ||||||
| 			prev_config: "", | 			prev_config: "", | ||||||
| 		}, | 		}, | ||||||
| 		call: function(req) { | 		call: ex_wrap(function(req) { | ||||||
| 			let phy = req.args.phy; | 			let phy = req.args.phy; | ||||||
| 			let file = req.args.config; | 			let file = req.args.config; | ||||||
| 			let prev_file = req.args.prev_config; | 			let prev_file = req.args.prev_config; | ||||||
| @@ -403,34 +733,29 @@ let main_obj = { | |||||||
| 			if (!phy) | 			if (!phy) | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; | 				return libubus.STATUS_INVALID_ARGUMENT; | ||||||
|  |  | ||||||
| 			try { | 			if (prev_file && !hostapd.data.config[phy]) { | ||||||
| 				if (prev_file && !hostapd.data.config[phy]) { | 				let config = iface_load_config(prev_file); | ||||||
| 					let config = iface_load_config(prev_file); | 				if (config) | ||||||
| 					if (config) | 					config.radio.data = []; | ||||||
| 						config.radio.data = []; | 				hostapd.data.config[phy] = config; | ||||||
| 					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; |  | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | 			let config = iface_load_config(file); | ||||||
|  |  | ||||||
|  | 			hostapd.printf(`Set new config for phy ${phy}: ${file}`); | ||||||
|  | 			iface_set_config(phy, config); | ||||||
|  |  | ||||||
| 			return { | 			return { | ||||||
| 				pid: hostapd.getpid() | 				pid: hostapd.getpid() | ||||||
| 			}; | 			}; | ||||||
| 		} | 		}) | ||||||
| 	}, | 	}, | ||||||
| 	config_add: { | 	config_add: { | ||||||
| 		args: { | 		args: { | ||||||
| 			iface: "", | 			iface: "", | ||||||
| 			config: "", | 			config: "", | ||||||
| 		}, | 		}, | ||||||
| 		call: function(req) { | 		call: ex_wrap(function(req) { | ||||||
| 			if (!req.args.iface || !req.args.config) | 			if (!req.args.iface || !req.args.config) | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; | 				return libubus.STATUS_INVALID_ARGUMENT; | ||||||
|  |  | ||||||
| @@ -440,19 +765,19 @@ let main_obj = { | |||||||
| 			return { | 			return { | ||||||
| 				pid: hostapd.getpid() | 				pid: hostapd.getpid() | ||||||
| 			}; | 			}; | ||||||
| 		} | 		}) | ||||||
| 	}, | 	}, | ||||||
| 	config_remove: { | 	config_remove: { | ||||||
| 		args: { | 		args: { | ||||||
| 			iface: "" | 			iface: "" | ||||||
| 		}, | 		}, | ||||||
| 		call: function(req) { | 		call: ex_wrap(function(req) { | ||||||
| 			if (!req.args.iface) | 			if (!req.args.iface) | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; | 				return libubus.STATUS_INVALID_ARGUMENT; | ||||||
|  |  | ||||||
| 			hostapd.remove_iface(req.args.iface); | 			hostapd.remove_iface(req.args.iface); | ||||||
| 			return 0; | 			return 0; | ||||||
| 		} | 		}) | ||||||
| 	}, | 	}, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,11 +1,14 @@ | |||||||
| #!/usr/bin/env ucode | #!/usr/bin/env ucode | ||||||
| 'use strict'; | '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"; | import { readfile, writefile, basename, readlink, glob } from "fs"; | ||||||
|  | let libubus = require("ubus"); | ||||||
|  |  | ||||||
| let keep_devices = {}; | let keep_devices = {}; | ||||||
| let phy = shift(ARGV); | let phy = shift(ARGV); | ||||||
| let new_config = shift(ARGV); | let command = shift(ARGV); | ||||||
|  | let phydev; | ||||||
|  |  | ||||||
| const mesh_params = [ | const mesh_params = [ | ||||||
| 	"mesh_retry_timeout", "mesh_confirm_timeout", "mesh_holding_timeout", "mesh_max_peer_links", | 	"mesh_retry_timeout", "mesh_confirm_timeout", "mesh_holding_timeout", "mesh_max_peer_links", | ||||||
| 	"mesh_max_retries", "mesh_ttl", "mesh_element_ttl", "mesh_hwmp_max_preq_retries", | 	"mesh_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" ]); | 		system([ "ip", "link", "set", "dev", ifname, "down" ]); | ||||||
| 		wdev_remove(ifname); | 		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); | 	wdev_create(phy, ifname, wdev); | ||||||
| 	system([ "ip", "link", "set", "dev", ifname, "up" ]); | 	system([ "ip", "link", "set", "dev", ifname, "up" ]); | ||||||
| 	if (wdev.freq) | 	if (wdev.freq) | ||||||
| @@ -47,7 +55,7 @@ function iface_start(wdev) | |||||||
| 		system(cmd); | 		system(cmd); | ||||||
| 	} else if (wdev.mode == "mesh") { | 	} else if (wdev.mode == "mesh") { | ||||||
| 		let cmd = [ "iw", "dev", ifname, "mesh", "join", wdev.ssid, "freq", wdev.freq, wdev.htmode ]; | 		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]) | 			if (wdev[key]) | ||||||
| 				push(cmd, key, wdev[key]); | 				push(cmd, key, wdev[key]); | ||||||
| 		system(cmd); | 		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`; | Commands: | ||||||
|  | 	set_config <config> [<device]...] - set phy configuration | ||||||
| for (let dev in ARGV) | 	get_macaddr <id>		  - get phy MAC address for vif index <id> | ||||||
| 	keep_devices[dev] = true; | `); | ||||||
|  |  | ||||||
| if (!phy || !new_config) { |  | ||||||
| 	warn(`Usage: ${basename(sourcepath())} <phy> <config> [<device]...]\n`); |  | ||||||
| 	exit(1); | 	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`); | 	warn(`PHY ${phy} does not exist\n`); | ||||||
| 	exit(1); | 	exit(1); | ||||||
| } | } | ||||||
|  |  | ||||||
| new_config = json(new_config); | commands[command](ARGV); | ||||||
| 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)); |  | ||||||
|   | |||||||
| @@ -1,11 +1,12 @@ | |||||||
| let libubus = require("ubus"); | let libubus = require("ubus"); | ||||||
| import { open, readfile } from "fs"; | 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(); | let ubus = libubus.connect(); | ||||||
|  |  | ||||||
| wpas.data.config = {}; | wpas.data.config = {}; | ||||||
| wpas.data.iface_phy = {}; | wpas.data.iface_phy = {}; | ||||||
|  | wpas.data.macaddr_list = {}; | ||||||
|  |  | ||||||
| function iface_stop(iface) | function iface_stop(iface) | ||||||
| { | { | ||||||
| @@ -20,16 +21,23 @@ function iface_stop(iface) | |||||||
| 	iface.running = false; | 	iface.running = false; | ||||||
| } | } | ||||||
|  |  | ||||||
| function iface_start(phy, iface) | function iface_start(phydev, iface, macaddr_list) | ||||||
| { | { | ||||||
|  | 	let phy = phydev.name; | ||||||
|  |  | ||||||
| 	if (iface.running) | 	if (iface.running) | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
| 	let ifname = iface.config.iface; | 	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; | 	wpas.data.iface_phy[ifname] = phy; | ||||||
| 	wdev_remove(ifname); | 	wdev_remove(ifname); | ||||||
| 	let ret = wdev_create(phy, ifname, iface.config); | 	let ret = wdev_create(phy, ifname, wdev_config); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		wpas.printf(`Failed to create device ${ifname}: ${ret}`); | 		wpas.printf(`Failed to create device ${ifname}: ${ret}`); | ||||||
| 	wpas.add_iface(iface.config); | 	wpas.add_iface(iface.config); | ||||||
| @@ -43,6 +51,11 @@ function iface_cb(new_if, old_if) | |||||||
| 		return; | 		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) | 	if (old_if) | ||||||
| 		iface_stop(old_if); | 		iface_stop(old_if); | ||||||
| } | } | ||||||
| @@ -73,9 +86,22 @@ function set_config(phy_name, config_list) | |||||||
| function start_pending(phy_name) | function start_pending(phy_name) | ||||||
| { | { | ||||||
| 	let phy = wpas.data.config[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) | 	for (let ifname in phy.data) | ||||||
| 		iface_start(phy_name, phy.data[ifname]); | 		iface_start(phydev, phy.data[ifname]); | ||||||
| } | } | ||||||
|  |  | ||||||
| let main_obj = { | let main_obj = { | ||||||
| @@ -106,6 +132,55 @@ let main_obj = { | |||||||
| 			return 0; | 			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: { | 	config_set: { | ||||||
| 		args: { | 		args: { | ||||||
| 			phy: "", | 			phy: "", | ||||||
| @@ -116,6 +191,7 @@ let main_obj = { | |||||||
| 			if (!req.args.phy) | 			if (!req.args.phy) | ||||||
| 				return libubus.STATUS_INVALID_ARGUMENT; | 				return libubus.STATUS_INVALID_ARGUMENT; | ||||||
|  |  | ||||||
|  | 			wpas.printf(`Set new config for phy ${req.args.phy}`); | ||||||
| 			try { | 			try { | ||||||
| 				if (req.args.config) | 				if (req.args.config) | ||||||
| 					set_config(req.args.phy, 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) { | 	switch (state) { | ||||||
| 	case "DISCONNECTED": | 	case "DISCONNECTED": | ||||||
| 	case "AUTHENTICATING": | 	case "AUTHENTICATING": | ||||||
|  | 	case "SCANNING": | ||||||
| 		msg.up = false; | 		msg.up = false; | ||||||
| 		break; | 		break; | ||||||
| 	case "INTERFACE_DISABLED": | 	case "INTERFACE_DISABLED": | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ start_service() { | |||||||
| 		procd_open_instance hostapd | 		procd_open_instance hostapd | ||||||
| 		procd_set_param command /usr/sbin/hostapd -s -g /var/run/hostapd/global | 		procd_set_param command /usr/sbin/hostapd -s -g /var/run/hostapd/global | ||||||
| 		procd_set_param respawn 3600 1 0 | 		procd_set_param respawn 3600 1 0 | ||||||
|  | 		procd_set_param limits core="unlimited" | ||||||
| 		[ -x /sbin/ujail -a -e /etc/capabilities/wpad.json ] && { | 		[ -x /sbin/ujail -a -e /etc/capabilities/wpad.json ] && { | ||||||
| 			procd_add_jail hostapd | 			procd_add_jail hostapd | ||||||
| 			procd_set_param capabilities /etc/capabilities/wpad.json | 			procd_set_param capabilities /etc/capabilities/wpad.json | ||||||
| @@ -29,6 +30,7 @@ start_service() { | |||||||
| 		procd_open_instance supplicant | 		procd_open_instance supplicant | ||||||
| 		procd_set_param command /usr/sbin/wpa_supplicant -n -s -g /var/run/wpa_supplicant/global | 		procd_set_param command /usr/sbin/wpa_supplicant -n -s -g /var/run/wpa_supplicant/global | ||||||
| 		procd_set_param respawn 3600 1 0 | 		procd_set_param respawn 3600 1 0 | ||||||
|  | 		procd_set_param limits core="unlimited" | ||||||
| 		[ -x /sbin/ujail -a -e /etc/capabilities/wpad.json ] && { | 		[ -x /sbin/ujail -a -e /etc/capabilities/wpad.json ] && { | ||||||
| 			procd_add_jail wpa_supplicant | 			procd_add_jail wpa_supplicant | ||||||
| 			procd_set_param capabilities /etc/capabilities/wpad.json | 			procd_set_param capabilities /etc/capabilities/wpad.json | ||||||
|   | |||||||
| @@ -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; | ||||||
|  |   | ||||||
| @@ -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; | ||||||
| @@ -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"); | ||||||
| @@ -0,0 +1,28 @@ | |||||||
|  | From: Felix Fietkau <nbd@nbd.name> | ||||||
|  | Date: Wed, 20 Sep 2023 13:41:10 +0200 | ||||||
|  | Subject: [PATCH] hostapd: cancel channel_list_update_timeout in | ||||||
|  |  hostapd_cleanup_iface_partial | ||||||
|  |  | ||||||
|  | Fixes a crash when disabling an interface during channel list update | ||||||
|  |  | ||||||
|  | Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | --- a/src/ap/hostapd.c | ||||||
|  | +++ b/src/ap/hostapd.c | ||||||
|  | @@ -501,6 +501,7 @@ static void sta_track_deinit(struct host | ||||||
|  |  void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) | ||||||
|  |  { | ||||||
|  |  	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); | ||||||
|  | +	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); | ||||||
|  |  #ifdef NEED_AP_MLME | ||||||
|  |  	hostapd_stop_setup_timers(iface); | ||||||
|  |  #endif /* NEED_AP_MLME */ | ||||||
|  | @@ -529,7 +530,6 @@ void hostapd_cleanup_iface_partial(struc | ||||||
|  |  static void hostapd_cleanup_iface(struct hostapd_iface *iface) | ||||||
|  |  { | ||||||
|  |  	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); | ||||||
|  | -	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); | ||||||
|  |  	eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface, | ||||||
|  |  			     NULL); | ||||||
|  |   | ||||||
| @@ -1,5 +1,7 @@ | |||||||
| --- a/hostapd/Makefile | Index: hostapd-2021-02-20-59e9794c/hostapd/Makefile | ||||||
| +++ b/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 | @@ -166,6 +166,12 @@ OBJS += ../src/common/hw_features_common | ||||||
|   |   | ||||||
|  OBJS += ../src/eapol_auth/eapol_auth_sm.o |  OBJS += ../src/eapol_auth/eapol_auth_sm.o | ||||||
| @@ -13,8 +15,10 @@ | |||||||
|   |   | ||||||
|  ifdef CONFIG_CODE_COVERAGE |  ifdef CONFIG_CODE_COVERAGE | ||||||
|  CFLAGS += -O0 -fprofile-arcs -ftest-coverage |  CFLAGS += -O0 -fprofile-arcs -ftest-coverage | ||||||
| --- a/src/ap/hostapd.h | Index: hostapd-2021-02-20-59e9794c/src/ap/hostapd.h | ||||||
| +++ b/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 @@ | @@ -17,6 +17,7 @@ | ||||||
|  #include "utils/list.h" |  #include "utils/list.h" | ||||||
|  #include "ap_config.h" |  #include "ap_config.h" | ||||||
| @@ -39,8 +43,10 @@ | |||||||
|  void hostapd_interface_deinit(struct hostapd_iface *iface); |  void hostapd_interface_deinit(struct hostapd_iface *iface); | ||||||
|  void hostapd_interface_free(struct hostapd_iface *iface); |  void hostapd_interface_free(struct hostapd_iface *iface); | ||||||
|  struct hostapd_iface * hostapd_alloc_iface(void); |  struct hostapd_iface * hostapd_alloc_iface(void); | ||||||
| --- a/src/ap/hostapd.c | Index: hostapd-2021-02-20-59e9794c/src/ap/hostapd.c | ||||||
| +++ b/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 | @@ -376,6 +376,7 @@ void hostapd_free_hapd_data(struct hosta | ||||||
|  	hapd->beacon_set_done = 0; |  	hapd->beacon_set_done = 0; | ||||||
|   |   | ||||||
| @@ -82,8 +88,10 @@ | |||||||
|  	hostapd_interface_deinit(iface); |  	hostapd_interface_deinit(iface); | ||||||
|  	wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", |  	wpa_printf(MSG_DEBUG, "%s: driver=%p drv_priv=%p -> hapd_deinit", | ||||||
|  		   __func__, driver, drv_priv); |  		   __func__, driver, drv_priv); | ||||||
| --- a/src/ap/ieee802_11.c | Index: hostapd-2021-02-20-59e9794c/src/ap/ieee802_11.c | ||||||
| +++ b/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 | @@ -3421,13 +3421,18 @@ static void handle_auth(struct hostapd_d | ||||||
|  	u16 auth_alg, auth_transaction, status_code; |  	u16 auth_alg, auth_transaction, status_code; | ||||||
|  	u16 resp = WLAN_STATUS_SUCCESS; |  	u16 resp = WLAN_STATUS_SUCCESS; | ||||||
| @@ -170,8 +178,10 @@ | |||||||
|  	sta = ap_get_sta(hapd, mgmt->sa); |  	sta = ap_get_sta(hapd, mgmt->sa); | ||||||
|  	if (sta == NULL) { |  	if (sta == NULL) { | ||||||
|  		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " |  		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying " | ||||||
| --- a/src/ap/beacon.c | Index: hostapd-2021-02-20-59e9794c/src/ap/beacon.c | ||||||
| +++ b/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 | @@ -823,6 +823,12 @@ void handle_probe_req(struct hostapd_dat | ||||||
|  	u16 csa_offs[2]; |  	u16 csa_offs[2]; | ||||||
|  	size_t csa_offs_len; |  	size_t csa_offs_len; | ||||||
| @@ -198,8 +208,10 @@ | |||||||
|  	/* TODO: verify that supp_rates contains at least one matching rate |  	/* TODO: verify that supp_rates contains at least one matching rate | ||||||
|  	 * with AP configuration */ |  	 * with AP configuration */ | ||||||
|   |   | ||||||
| --- a/src/ap/drv_callbacks.c | Index: hostapd-2021-02-20-59e9794c/src/ap/drv_callbacks.c | ||||||
| +++ b/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 | @@ -145,6 +145,10 @@ int hostapd_notif_assoc(struct hostapd_d | ||||||
|  	u16 reason = WLAN_REASON_UNSPECIFIED; |  	u16 reason = WLAN_REASON_UNSPECIFIED; | ||||||
|  	int status = WLAN_STATUS_SUCCESS; |  	int status = WLAN_STATUS_SUCCESS; | ||||||
| @@ -224,8 +236,22 @@ | |||||||
|  #ifdef CONFIG_P2P |  #ifdef CONFIG_P2P | ||||||
|  	if (elems.p2p) { |  	if (elems.p2p) { | ||||||
|  		wpabuf_free(sta->p2p_ie); |  		wpabuf_free(sta->p2p_ie); | ||||||
| --- a/src/ap/sta_info.c | @@ -981,9 +991,11 @@ void hostapd_event_ch_switch(struct host | ||||||
| +++ b/src/ap/sta_info.c |   | ||||||
|  |  		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 | @@ -458,6 +458,7 @@ void ap_handle_timer(void *eloop_ctx, vo | ||||||
|  		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, |  		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, | ||||||
|  			       HOSTAPD_LEVEL_INFO, "deauthenticated due to " |  			       HOSTAPD_LEVEL_INFO, "deauthenticated due to " | ||||||
| @@ -304,8 +330,10 @@ | |||||||
|   |   | ||||||
|  		if (hapd->msg_ctx_parent && |  		if (hapd->msg_ctx_parent && | ||||||
|  		    hapd->msg_ctx_parent != hapd->msg_ctx) |  		    hapd->msg_ctx_parent != hapd->msg_ctx) | ||||||
| --- a/src/ap/wpa_auth_glue.c | Index: hostapd-2021-02-20-59e9794c/src/ap/wpa_auth_glue.c | ||||||
| +++ b/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 | @@ -265,6 +265,7 @@ static void hostapd_wpa_auth_psk_failure | ||||||
|  	struct hostapd_data *hapd = ctx; |  	struct hostapd_data *hapd = ctx; | ||||||
|  	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR, |  	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR, | ||||||
| @@ -314,8 +342,10 @@ | |||||||
|  } |  } | ||||||
|   |   | ||||||
|   |   | ||||||
| --- a/wpa_supplicant/Makefile | Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/Makefile | ||||||
| +++ b/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 | @@ -169,6 +169,13 @@ ifdef CONFIG_EAPOL_TEST | ||||||
|  CFLAGS += -Werror -DEAPOL_TEST |  CFLAGS += -Werror -DEAPOL_TEST | ||||||
|  endif |  endif | ||||||
| @@ -340,8 +370,10 @@ | |||||||
|  endif |  endif | ||||||
|   |   | ||||||
|  CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY |  CFLAGS += -DEAP_SERVER -DEAP_SERVER_IDENTITY | ||||||
| --- a/wpa_supplicant/wpa_supplicant.c | Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/wpa_supplicant.c | ||||||
| +++ b/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 | @@ -6943,6 +6943,8 @@ struct wpa_supplicant * wpa_supplicant_a | ||||||
|  	} |  	} | ||||||
|  #endif /* CONFIG_P2P */ |  #endif /* CONFIG_P2P */ | ||||||
| @@ -373,8 +405,10 @@ | |||||||
|  	return 0; |  	return 0; | ||||||
|  } |  } | ||||||
|   |   | ||||||
| --- a/wpa_supplicant/wpa_supplicant_i.h | Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/wpa_supplicant_i.h | ||||||
| +++ b/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 @@ | @@ -19,6 +19,7 @@ | ||||||
|  #include "wps/wps_defs.h" |  #include "wps/wps_defs.h" | ||||||
|  #include "config_ssid.h" |  #include "config_ssid.h" | ||||||
| @@ -400,8 +434,10 @@ | |||||||
|  #ifdef CONFIG_MATCH_IFACE |  #ifdef CONFIG_MATCH_IFACE | ||||||
|  	int matched; |  	int matched; | ||||||
|  #endif /* CONFIG_MATCH_IFACE */ |  #endif /* CONFIG_MATCH_IFACE */ | ||||||
| --- a/wpa_supplicant/wps_supplicant.c | Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/wps_supplicant.c | ||||||
| +++ b/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 @@ | @@ -33,6 +33,7 @@ | ||||||
|  #include "p2p/p2p.h" |  #include "p2p/p2p.h" | ||||||
|  #include "p2p_supplicant.h" |  #include "p2p_supplicant.h" | ||||||
| @@ -419,8 +455,10 @@ | |||||||
|  	if (wpa_s->conf->wps_cred_processing == 1) |  	if (wpa_s->conf->wps_cred_processing == 1) | ||||||
|  		return 0; |  		return 0; | ||||||
|   |   | ||||||
| --- a/wpa_supplicant/main.c | Index: hostapd-2021-02-20-59e9794c/wpa_supplicant/main.c | ||||||
| +++ b/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[]) | @@ -202,7 +202,7 @@ int main(int argc, char *argv[]) | ||||||
|   |   | ||||||
|  	for (;;) { |  	for (;;) { | ||||||
| @@ -440,8 +478,10 @@ | |||||||
|  		case 'o': |  		case 'o': | ||||||
|  			params.override_driver = optarg; |  			params.override_driver = optarg; | ||||||
|  			break; |  			break; | ||||||
| --- a/src/ap/rrm.c | Index: hostapd-2021-02-20-59e9794c/src/ap/rrm.c | ||||||
| +++ b/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 | @@ -89,6 +89,9 @@ static void hostapd_handle_beacon_report | ||||||
|  		return; |  		return; | ||||||
|  	wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s", |  	wpa_msg(hapd->msg_ctx, MSG_INFO, BEACON_RESP_RX MACSTR " %u %02x %s", | ||||||
| @@ -452,8 +492,10 @@ | |||||||
|  } |  } | ||||||
|   |   | ||||||
|   |   | ||||||
| --- a/src/ap/vlan_init.c | Index: hostapd-2021-02-20-59e9794c/src/ap/vlan_init.c | ||||||
| +++ b/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 @@ | @@ -22,6 +22,7 @@ | ||||||
|  static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan, |  static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan, | ||||||
|  		       int existsok) |  		       int existsok) | ||||||
| @@ -490,8 +532,10 @@ | |||||||
|  	return hostapd_vlan_if_remove(hapd, vlan->ifname); |  	return hostapd_vlan_if_remove(hapd, vlan->ifname); | ||||||
|  } |  } | ||||||
|   |   | ||||||
| --- a/src/ap/dfs.c | Index: hostapd-2021-02-20-59e9794c/src/ap/dfs.c | ||||||
| +++ b/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 | @@ -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=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d", | ||||||
|  		freq, ht_enabled, chan_offset, chan_width, cf1, cf2); |  		freq, ht_enabled, chan_offset, chan_width, cf1, cf2); | ||||||
| @@ -501,8 +545,10 @@ | |||||||
|  	/* Proceed only if DFS is not offloaded to the driver */ |  	/* Proceed only if DFS is not offloaded to the driver */ | ||||||
|  	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) |  	if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) | ||||||
|  		return 0; |  		return 0; | ||||||
| --- a/src/ap/airtime_policy.c | Index: hostapd-2021-02-20-59e9794c/src/ap/airtime_policy.c | ||||||
| +++ b/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 | @@ -108,8 +108,14 @@ static void set_sta_weights(struct hosta | ||||||
|  { |  { | ||||||
|  	struct sta_info *sta; |  	struct sta_info *sta; | ||||||
| @@ -532,8 +578,10 @@ | |||||||
|  		if (weight) |  		if (weight) | ||||||
|  			return sta_set_airtime_weight(hapd, sta, weight); |  			return sta_set_airtime_weight(hapd, sta, weight); | ||||||
|  	} |  	} | ||||||
| --- a/src/ap/sta_info.h | Index: hostapd-2021-02-20-59e9794c/src/ap/sta_info.h | ||||||
| +++ b/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 { | @@ -323,6 +323,7 @@ struct sta_info { | ||||||
|  #endif /* CONFIG_TESTING_OPTIONS */ |  #endif /* CONFIG_TESTING_OPTIONS */ | ||||||
|  #ifdef CONFIG_AIRTIME_POLICY |  #ifdef CONFIG_AIRTIME_POLICY | ||||||
| @@ -542,8 +590,10 @@ | |||||||
|  	struct os_reltime backlogged_until; |  	struct os_reltime backlogged_until; | ||||||
|  #endif /* CONFIG_AIRTIME_POLICY */ |  #endif /* CONFIG_AIRTIME_POLICY */ | ||||||
|   |   | ||||||
| --- a/src/ap/wnm_ap.c | Index: hostapd-2021-02-20-59e9794c/src/ap/wnm_ap.c | ||||||
| +++ b/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 | @@ -442,7 +442,8 @@ static void ieee802_11_rx_bss_trans_mgmt | ||||||
|  	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", |  	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", | ||||||
|  		    pos, end - pos); |  		    pos, end - pos); | ||||||
| @@ -582,8 +632,10 @@ | |||||||
|  	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", |  	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries", | ||||||
|  		    pos, end - pos); |  		    pos, end - pos); | ||||||
|  } |  } | ||||||
| --- a/src/utils/eloop.c | Index: hostapd-2021-02-20-59e9794c/src/utils/eloop.c | ||||||
| +++ b/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 { | @@ -77,6 +77,9 @@ struct eloop_sock_table { | ||||||
|  struct eloop_data { |  struct eloop_data { | ||||||
|  	int max_sock; |  	int max_sock; | ||||||
| @@ -632,8 +684,10 @@ | |||||||
|   |   | ||||||
|  void eloop_terminate(void) |  void eloop_terminate(void) | ||||||
|  { |  { | ||||||
| --- a/src/utils/eloop.h | Index: hostapd-2021-02-20-59e9794c/src/utils/eloop.h | ||||||
| +++ b/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 | @@ -65,6 +65,9 @@ typedef void (*eloop_timeout_handler)(vo | ||||||
|   */ |   */ | ||||||
|  typedef void (*eloop_signal_handler)(int sig, void *signal_ctx); |  typedef void (*eloop_signal_handler)(int sig, void *signal_ctx); | ||||||
| @@ -663,8 +717,10 @@ | |||||||
|  /** |  /** | ||||||
|   * eloop_run - Start the event loop |   * eloop_run - Start the event loop | ||||||
|   * |   * | ||||||
|  | Index: hostapd-2021-02-20-59e9794c/src/utils/uloop.c | ||||||
|  | =================================================================== | ||||||
| --- /dev/null | --- /dev/null | ||||||
| +++ b/src/utils/uloop.c | +++ hostapd-2021-02-20-59e9794c/src/utils/uloop.c | ||||||
| @@ -0,0 +1,64 @@ | @@ -0,0 +1,64 @@ | ||||||
| +#include <libubox/uloop.h> | +#include <libubox/uloop.h> | ||||||
| +#include "includes.h" | +#include "includes.h" | ||||||
|   | |||||||
| @@ -107,14 +107,14 @@ | |||||||
|  	hostapd_ubus_free_bss(hapd); |  	hostapd_ubus_free_bss(hapd); | ||||||
|  	accounting_deinit(hapd); |  	accounting_deinit(hapd); | ||||||
|  	hostapd_deinit_wpa(hapd); |  	hostapd_deinit_wpa(hapd); | ||||||
| @@ -530,6 +533,7 @@ void hostapd_cleanup_iface_partial(struc | @@ -502,6 +505,7 @@ static void sta_track_deinit(struct host | ||||||
|  static void hostapd_cleanup_iface(struct hostapd_iface *iface) |  void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) | ||||||
|  { |  { | ||||||
|  	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); |  	wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); | ||||||
| +	hostapd_ucode_free_iface(iface); | +	hostapd_ucode_free_iface(iface); | ||||||
|  	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); |  	eloop_cancel_timeout(channel_list_update_timeout, iface, NULL); | ||||||
|  	eloop_cancel_timeout(hostapd_interface_setup_failure_handler, iface, |  #ifdef NEED_AP_MLME | ||||||
|  			     NULL); |  	hostapd_stop_setup_timers(iface); | ||||||
| @@ -1104,7 +1108,7 @@ static int db_table_create_radius_attrib | @@ -1104,7 +1108,7 @@ static int db_table_create_radius_attrib | ||||||
|   * initialized. Most of the modules that are initialized here will be |   * initialized. Most of the modules that are initialized here will be | ||||||
|   * deinitialized in hostapd_cleanup(). |   * deinitialized in hostapd_cleanup(). | ||||||
| @@ -159,6 +159,16 @@ | |||||||
|  				hostapd_cleanup(hapd); |  				hostapd_cleanup(hapd); | ||||||
|  				hapd_iface->bss[hapd_iface->num_bss - 1] = NULL; |  				hapd_iface->bss[hapd_iface->num_bss - 1] = NULL; | ||||||
|  				hapd_iface->conf->num_bss--; |  				hapd_iface->conf->num_bss--; | ||||||
|  | @@ -3137,7 +3142,8 @@ int hostapd_remove_iface(struct hapd_int | ||||||
|  |  		hapd_iface = interfaces->iface[i]; | ||||||
|  |  		if (hapd_iface == NULL) | ||||||
|  |  			return -1; | ||||||
|  | -		if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) { | ||||||
|  | +		if (!os_strcmp(hapd_iface->phy, buf) || | ||||||
|  | +		    !os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) { | ||||||
|  |  			wpa_printf(MSG_INFO, "Remove interface '%s'", buf); | ||||||
|  |  			hapd_iface->driver_ap_teardown = | ||||||
|  |  				!!(hapd_iface->drv_flags & | ||||||
| --- a/wpa_supplicant/Makefile | --- a/wpa_supplicant/Makefile | ||||||
| +++ b/wpa_supplicant/Makefile | +++ b/wpa_supplicant/Makefile | ||||||
| @@ -172,8 +172,20 @@ endif | @@ -172,8 +172,20 @@ endif | ||||||
| @@ -287,7 +297,33 @@ | |||||||
|   |   | ||||||
| --- a/src/drivers/driver.h | --- a/src/drivers/driver.h | ||||||
| +++ b/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 |  	 * struct ch_switch | ||||||
| @@ -295,7 +331,7 @@ | |||||||
|  	 * @freq: Frequency of new channel in MHz |  	 * @freq: Frequency of new channel in MHz | ||||||
|  	 * @ht_enabled: Whether this is an HT channel |  	 * @ht_enabled: Whether this is an HT channel | ||||||
|  	 * @ch_offset: Secondary channel offset |  	 * @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 |  	 * @cf2: Center frequency 2 | ||||||
|  	 */ |  	 */ | ||||||
|  	struct ch_switch { |  	struct ch_switch { | ||||||
| @@ -348,3 +384,187 @@ | |||||||
|  	switch (event) { |  	switch (event) { | ||||||
|  	case EVENT_AUTH: |  	case EVENT_AUTH: | ||||||
|  #ifdef CONFIG_FST |  #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 | ||||||
|  | @@ -1224,7 +1224,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); | ||||||
|  | @@ -1260,7 +1260,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); | ||||||
|  | @@ -7614,6 +7614,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, | ||||||
|  | @@ -7673,21 +7674,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) { | ||||||
|  | @@ -8047,6 +8044,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) | ||||||
|  |  { | ||||||
|  | @@ -9391,6 +9432,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, | ||||||
|  | @@ -11973,6 +12045,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, | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ | |||||||
|   |   | ||||||
| --- a/src/ap/x_snoop.c | --- a/src/ap/x_snoop.c | ||||||
| +++ b/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; |  		return -1; | ||||||
|  	} |  	} | ||||||
|   |   | ||||||
| @@ -29,13 +29,20 @@ | |||||||
|  		wpa_printf(MSG_DEBUG, |  		wpa_printf(MSG_DEBUG, | ||||||
|  			   "x_snoop: Failed to enable proxyarp on the bridge port"); |  			   "x_snoop: Failed to enable proxyarp on the bridge port"); | ||||||
|  		return -1; |  		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 |  #ifdef CONFIG_IPV6 | ||||||
| -	if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) { | -	if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) { | ||||||
| +	if (!conf->snoop_iface[0] && | +	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, |  		wpa_printf(MSG_DEBUG, | ||||||
|  			   "x_snoop: Failed to enable multicast snooping on the bridge"); |  			   "x_snoop: Failed to enable multicast snooping on the bridge"); | ||||||
|  		return -1; |  		return -1; | ||||||
| @@ -44,15 +51,27 @@ | |||||||
|  	struct hostapd_bss_config *conf = hapd->conf; |  	struct hostapd_bss_config *conf = hapd->conf; | ||||||
|  	struct l2_packet_data *l2; |  	struct l2_packet_data *l2; | ||||||
| +	const char *ifname = conf->bridge; | +	const char *ifname = conf->bridge; | ||||||
|   | + | ||||||
| -	l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1); |  | ||||||
| +	if (conf->snoop_iface[0]) | +	if (conf->snoop_iface[0]) | ||||||
| +		ifname = conf->snoop_iface; | +		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); | +	l2 = l2_packet_init(ifname, NULL, ETH_P_ALL, handler, hapd, 1); | ||||||
|  	if (l2 == NULL) { |  	if (l2 == NULL) { | ||||||
|  		wpa_printf(MSG_DEBUG, |  		wpa_printf(MSG_DEBUG, | ||||||
|  			   "x_snoop: Failed to initialize L2 packet processing %s", |  			   "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 | --- a/hostapd/config_file.c | ||||||
| +++ b/hostapd/config_file.c | +++ b/hostapd/config_file.c | ||||||
| @@ -2343,6 +2343,8 @@ static int hostapd_config_fill(struct ho | @@ -2343,6 +2343,8 @@ static int hostapd_config_fill(struct ho | ||||||
| @@ -64,3 +83,55 @@ | |||||||
|  	} else if (os_strcmp(buf, "vlan_bridge") == 0) { |  	} else if (os_strcmp(buf, "vlan_bridge") == 0) { | ||||||
|  		os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge)); |  		os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge)); | ||||||
|  	} else if (os_strcmp(buf, "wds_bridge") == 0) { |  	} 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)) | ||||||
|   | |||||||
| @@ -19,18 +19,6 @@ | |||||||
|   |   | ||||||
|  	enum hostapd_logger_level logger_syslog_level, logger_stdout_level; |  	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 | --- a/src/ap/ap_config.c | ||||||
| +++ b/src/ap/ap_config.c | +++ b/src/ap/ap_config.c | ||||||
| @@ -785,6 +785,7 @@ void hostapd_config_free_bss(struct host | @@ -785,6 +785,7 @@ void hostapd_config_free_bss(struct host | ||||||
|   | |||||||
| @@ -50,42 +50,4 @@ | |||||||
|  	return NL_SKIP; |  	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); |  | ||||||
|   | |||||||
							
								
								
									
										48
									
								
								feeds/wifi-ax/hostapd/patches/999-ft-anonce.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								feeds/wifi-ax/hostapd/patches/999-ft-anonce.patch
									
									
									
									
									
										Normal 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]; | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| --- a/src/ap/ieee802_11.c | --- a/src/ap/ieee802_11.c | ||||||
| +++ b/src/ap/ieee802_11.c | +++ b/src/ap/ieee802_11.c | ||||||
| @@ -57,6 +57,15 @@ | @@ -57,6 +57,17 @@ | ||||||
|  #include "gas_query_ap.h" |  #include "gas_query_ap.h" | ||||||
|   |   | ||||||
|   |   | ||||||
| @@ -8,6 +8,8 @@ | |||||||
| +ewma(int new, int old) | +ewma(int new, int old) | ||||||
| +{ | +{ | ||||||
| +	#define ALPHA	10 | +	#define ALPHA	10 | ||||||
|  | +	if (!old) | ||||||
|  | +		return new; | ||||||
| +	if (new >= 0) | +	if (new >= 0) | ||||||
| +		return old; | +		return old; | ||||||
| +	return ((ALPHA * new) + ((100 - ALPHA) * old)) / 100; | +	return ((ALPHA * new) + ((100 - ALPHA) * old)) / 100; | ||||||
| @@ -61,28 +63,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 | --- a/src/ap/hostapd.h | ||||||
| +++ b/src/ap/hostapd.h | +++ b/src/ap/hostapd.h | ||||||
| @@ -451,6 +451,7 @@ struct hostapd_data { | @@ -451,6 +451,7 @@ struct hostapd_data { | ||||||
|   | |||||||
| @@ -153,7 +153,7 @@ hostapd_bss_ban_client(struct hostapd_data *hapd, u8 *addr, int time) | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	eloop_register_timeout(0, time * 1000, hostapd_bss_del_ban, ban, hapd); | 	eloop_register_timeout(time, 0, hostapd_bss_del_ban, ban, hapd); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int | static int | ||||||
| @@ -305,7 +305,42 @@ hostapd_bss_get_clients(struct ubus_context *ctx, struct ubus_object *obj, | |||||||
| 			blobmsg_add_u32(&b, "rx", sta_driver_data.current_rx_rate * 100); | 			blobmsg_add_u32(&b, "rx", sta_driver_data.current_rx_rate * 100); | ||||||
| 			blobmsg_add_u32(&b, "tx", sta_driver_data.current_tx_rate * 100); | 			blobmsg_add_u32(&b, "tx", sta_driver_data.current_tx_rate * 100); | ||||||
| 			blobmsg_close_table(&b, r); | 			blobmsg_close_table(&b, r); | ||||||
|  | 			blobmsg_add_u32(&b, "retries", sta_driver_data.tx_retry_count); | ||||||
|  | 			blobmsg_add_u32(&b, "failed", sta_driver_data.tx_retry_failed); | ||||||
| 			blobmsg_add_u32(&b, "signal", sta_driver_data.signal); | 			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); | 		hostapd_parse_capab_blobmsg(sta); | ||||||
| @@ -424,6 +459,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); | 			hapd->iface->cac_started ? hapd->iface->dfs_cac_ms / 1000 - now.sec : 0); | ||||||
| 	blobmsg_close_table(&b, dfs_table); | 	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); | 	ubus_send_reply(ctx, req, b.head); | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| @@ -1698,6 +1739,19 @@ void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 * | |||||||
| 	ubus_notify(ctx, &hapd->ubus.obj, type, b.head, -1); | 	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) | void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta) | ||||||
| { | { | ||||||
|   | |||||||
							
								
								
									
										1845
									
								
								feeds/wifi-ax/hostapd/src/src/ap/ubus.c.orig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1845
									
								
								feeds/wifi-ax/hostapd/src/src/ap/ubus.c.orig
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -65,6 +65,7 @@ void hostapd_ubus_free(struct hapd_interfaces *interfaces); | |||||||
| int hostapd_ubus_notify_bss_transition_query( | int hostapd_ubus_notify_bss_transition_query( | ||||||
| 	struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason, | 	struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason, | ||||||
| 	const u8 *candidate_list, u16 candidate_list_len); | 	const u8 *candidate_list, u16 candidate_list_len); | ||||||
|  | void hostapd_ubus_notify_csa(struct hostapd_data *hapd, int freq); | ||||||
|  |  | ||||||
| #else | #else | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,6 +7,8 @@ | |||||||
| #include "beacon.h" | #include "beacon.h" | ||||||
| #include "hw_features.h" | #include "hw_features.h" | ||||||
| #include "ap_drv_ops.h" | #include "ap_drv_ops.h" | ||||||
|  | #include "dfs.h" | ||||||
|  | #include "acs.h" | ||||||
| #include <libubox/uloop.h> | #include <libubox/uloop.h> | ||||||
|  |  | ||||||
| static uc_resource_type_t *global_type, *bss_type, *iface_type; | 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; | 	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 * | static uc_value_t * | ||||||
| uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs) | 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; | 	struct hostapd_config *conf; | ||||||
| 	uc_value_t *file = uc_fn_arg(0); | 	uc_value_t *file = uc_fn_arg(0); | ||||||
| 	uc_value_t *index = uc_fn_arg(1); | 	uc_value_t *index = uc_fn_arg(1); | ||||||
|  | 	uc_value_t *files_only = uc_fn_arg(2); | ||||||
| 	unsigned int i, idx = 0; | 	unsigned int i, idx = 0; | ||||||
| 	int ret = -1; | 	int ret = -1; | ||||||
|  |  | ||||||
| @@ -129,9 +220,28 @@ uc_hostapd_bss_set_config(uc_vm_t *vm, size_t nargs) | |||||||
|  |  | ||||||
| 	iface = hapd->iface; | 	iface = hapd->iface; | ||||||
| 	conf = interfaces->config_read_cb(ucv_string_get(file)); | 	conf = interfaces->config_read_cb(ucv_string_get(file)); | ||||||
| 	if (!conf || idx > conf->num_bss || !conf->bss[idx]) | 	if (!conf) | ||||||
| 		goto out; | 		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_bss_deinit_no_free(hapd); | ||||||
| 	hostapd_drv_stop_ap(hapd); | 	hostapd_drv_stop_ap(hapd); | ||||||
| 	hostapd_free_hapd_data(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]; | 			iface->conf->bss[i] = conf->bss[idx]; | ||||||
| 	hapd->conf = conf->bss[idx]; | 	hapd->conf = conf->bss[idx]; | ||||||
| 	conf->bss[idx] = old_bss; | 	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; | 	ret = 0; | ||||||
|  | free: | ||||||
|  | 	hostapd_config_free(conf); | ||||||
| out: | out: | ||||||
| 	return ucv_int64_new(ret); | 	return ucv_int64_new(ret); | ||||||
| } | } | ||||||
| @@ -178,10 +290,15 @@ uc_hostapd_bss_delete(uc_vm_t *vm, size_t nargs) | |||||||
| 	struct hostapd_iface *iface; | 	struct hostapd_iface *iface; | ||||||
| 	int i, idx; | 	int i, idx; | ||||||
|  |  | ||||||
| 	if (!hapd || hapd == hapd->iface->bss[0]) | 	if (!hapd) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  |  | ||||||
| 	iface = hapd->iface; | 	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++) | 	for (idx = 0; idx < iface->num_bss; idx++) | ||||||
| 		if (iface->bss[idx] == hapd) | 		if (iface->bss[idx] == hapd) | ||||||
| 			break; | 			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++) | 	for (i = idx + 1; i < iface->num_bss; i++) | ||||||
| 		iface->bss[i - 1] = iface->bss[i]; | 		iface->bss[i - 1] = iface->bss[i]; | ||||||
|  |  | ||||||
| 	iface->num_bss--; | 	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_drv_stop_ap(hapd); | ||||||
| 	hostapd_bss_deinit(hapd); | 	hostapd_bss_deinit(hapd); | ||||||
| 	hostapd_remove_iface_bss_conf(iface->conf, hapd->conf); | 	hostapd_remove_iface_bss_conf(iface->conf, hapd->conf); | ||||||
| @@ -266,6 +388,58 @@ out: | |||||||
| 	return ret; | 	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 * | static uc_value_t * | ||||||
| uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs) | uc_hostapd_bss_ctrl(uc_vm_t *vm, size_t nargs) | ||||||
| { | { | ||||||
| @@ -297,12 +471,35 @@ uc_hostapd_iface_stop(uc_vm_t *vm, size_t nargs) | |||||||
| 	struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface"); | 	struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface"); | ||||||
| 	int i; | 	int i; | ||||||
|  |  | ||||||
|  | 	if (!iface) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	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++) { | 	for (i = 0; i < iface->num_bss; i++) { | ||||||
| 		struct hostapd_data *hapd = iface->bss[i]; | 		struct hostapd_data *hapd = iface->bss[i]; | ||||||
|  |  | ||||||
| 		hostapd_drv_stop_ap(hapd); | 		hostapd_drv_stop_ap(hapd); | ||||||
| 		hapd->started = 0; | 		hapd->beacon_set_done = 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	return NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
| static uc_value_t * | static uc_value_t * | ||||||
| @@ -311,67 +508,85 @@ uc_hostapd_iface_start(uc_vm_t *vm, size_t nargs) | |||||||
| 	struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface"); | 	struct hostapd_iface *iface = uc_fn_thisval("hostapd.iface"); | ||||||
| 	uc_value_t *info = uc_fn_arg(0); | 	uc_value_t *info = uc_fn_arg(0); | ||||||
| 	struct hostapd_config *conf; | 	struct hostapd_config *conf; | ||||||
|  | 	bool changed = false; | ||||||
| 	uint64_t intval; | 	uint64_t intval; | ||||||
| 	int i; | 	int i; | ||||||
|  |  | ||||||
| 	if (!iface) | 	if (!iface) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  |  | ||||||
| 	if (!info) | 	if (!info) { | ||||||
|  | 		iface->freq = 0; | ||||||
| 		goto out; | 		goto out; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if (ucv_type(info) != UC_OBJECT) | 	if (ucv_type(info) != UC_OBJECT) | ||||||
| 		return NULL; | 		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; | 	conf = iface->conf; | ||||||
| 	if ((intval = ucv_int64_get(ucv_object_get(info, "op_class", NULL))) &&	!errno) | 	UPDATE_VAL(op_class, "op_class"); | ||||||
| 		conf->op_class = intval; | 	UPDATE_VAL(hw_mode, "hw_mode"); | ||||||
| 	if ((intval = ucv_int64_get(ucv_object_get(info, "hw_mode", NULL))) && !errno) | 	UPDATE_VAL(channel, "channel"); | ||||||
| 		conf->hw_mode = intval; | 	UPDATE_VAL(secondary_channel, "sec_channel"); | ||||||
| 	if ((intval = ucv_int64_get(ucv_object_get(info, "channel", NULL))) && !errno) | 	if (!changed && | ||||||
| 		conf->channel = intval; | 	    (iface->bss[0]->beacon_set_done || | ||||||
| 	if ((intval = ucv_int64_get(ucv_object_get(info, "sec_channel", NULL))) && !errno) | 	     iface->state == HAPD_IFACE_DFS)) | ||||||
| 		conf->secondary_channel = intval; | 		return ucv_boolean_new(true); | ||||||
| #ifdef CONFIG_IEEE80211AC |  | ||||||
| 	if ((intval = ucv_int64_get(ucv_object_get(info, "center_seg0_idx", NULL))) && !errno) { | 	intval = ucv_int64_get(ucv_object_get(info, "center_seg0_idx", NULL)); | ||||||
| 		conf->vht_oper_centr_freq_seg0_idx = intval; | 	if (!errno) | ||||||
| #ifdef CONFIG_IEEE80211AX | 		hostapd_set_oper_centr_freq_seg0_idx(conf, intval); | ||||||
| 		conf->he_oper_centr_freq_seg0_idx = intval; |  | ||||||
| #endif | 	intval = ucv_int64_get(ucv_object_get(info, "center_seg1_idx", NULL)); | ||||||
| #ifdef CONFIG_IEEE80211BE | 	if (!errno) | ||||||
| 		conf->eht_oper_centr_freq_seg0_idx = intval; | 		hostapd_set_oper_centr_freq_seg1_idx(conf, 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 |  | ||||||
| 	} |  | ||||||
| 	intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL)); | 	intval = ucv_int64_get(ucv_object_get(info, "oper_chwidth", NULL)); | ||||||
| 	if (!errno) { | 	if (!errno) | ||||||
| 		conf->vht_oper_chwidth = intval; | 		hostapd_set_oper_chwidth(conf, intval); | ||||||
| #ifdef CONFIG_IEEE80211AX |  | ||||||
| 		conf->he_oper_chwidth = intval; | 	intval = ucv_int64_get(ucv_object_get(info, "frequency", NULL)); | ||||||
| #endif | 	if (!errno) | ||||||
| #ifdef CONFIG_IEEE80211BE | 		iface->freq = intval; | ||||||
| 		conf->eht_oper_chwidth = intval; | 	else | ||||||
| #endif | 		iface->freq = 0; | ||||||
| 	} | 	conf->acs = 0; | ||||||
| #endif |  | ||||||
|  |  | ||||||
| out: | 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); | 		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++) { | 	for (i = 0; i < iface->num_bss; i++) { | ||||||
| 		struct hostapd_data *hapd = iface->bss[i]; | 		struct hostapd_data *hapd = iface->bss[i]; | ||||||
| 		int ret; | 		int ret; | ||||||
|  |  | ||||||
| 		hapd->started = 1; | 		hapd->conf->start_disabled = 0; | ||||||
| 		hostapd_set_freq(hapd, conf->hw_mode, iface->freq, | 		hostapd_set_freq(hapd, conf->hw_mode, iface->freq, | ||||||
| 				 conf->channel, | 				 conf->channel, | ||||||
| 				 conf->enable_edmg, | 				 conf->enable_edmg, | ||||||
| @@ -436,6 +651,55 @@ uc_hostapd_iface_switch_channel(uc_vm_t *vm, size_t nargs) | |||||||
| 	return ucv_boolean_new(!ret); | 	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) | int hostapd_ucode_init(struct hapd_interfaces *ifaces) | ||||||
| { | { | ||||||
| 	static const uc_function_list_t global_fns[] = { | 	static const uc_function_list_t global_fns[] = { | ||||||
| @@ -449,9 +713,11 @@ int hostapd_ucode_init(struct hapd_interfaces *ifaces) | |||||||
| 	static const uc_function_list_t bss_fns[] = { | 	static const uc_function_list_t bss_fns[] = { | ||||||
| 		{ "ctrl", uc_hostapd_bss_ctrl }, | 		{ "ctrl", uc_hostapd_bss_ctrl }, | ||||||
| 		{ "set_config", uc_hostapd_bss_set_config }, | 		{ "set_config", uc_hostapd_bss_set_config }, | ||||||
|  | 		{ "rename", uc_hostapd_bss_rename }, | ||||||
| 		{ "delete", uc_hostapd_bss_delete }, | 		{ "delete", uc_hostapd_bss_delete }, | ||||||
| 	}; | 	}; | ||||||
| 	static const uc_function_list_t iface_fns[] = { | 	static const uc_function_list_t iface_fns[] = { | ||||||
|  | 		{ "set_bss_order", uc_hostapd_iface_set_bss_order }, | ||||||
| 		{ "add_bss", uc_hostapd_iface_add_bss }, | 		{ "add_bss", uc_hostapd_iface_add_bss }, | ||||||
| 		{ "stop", uc_hostapd_iface_stop }, | 		{ "stop", uc_hostapd_iface_stop }, | ||||||
| 		{ "start", uc_hostapd_iface_start }, | 		{ "start", uc_hostapd_iface_start }, | ||||||
|   | |||||||
| @@ -129,7 +129,10 @@ uc_value_t *uc_wpa_freq_info(uc_vm_t *vm, size_t nargs) | |||||||
| 	tmp_channel &= ~((8 << width) - 1); | 	tmp_channel &= ~((8 << width) - 1); | ||||||
| 	center_idx = tmp_channel + center_ofs + (4 << 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; | 	center_idx = (center_idx - channel) * 5 + freq_val; | ||||||
| 	ucv_object_add(ret, "center_freq1", ucv_int64_new(center_idx)); | 	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 *wpa_ucode_registry_remove(uc_value_t *reg, int idx) | ||||||
| { | { | ||||||
| 	uc_value_t *val = wpa_ucode_registry_get(reg, idx); | 	uc_value_t *val = wpa_ucode_registry_get(reg, idx); | ||||||
|  | 	void **dataptr; | ||||||
|  |  | ||||||
| 	if (val) | 	if (!val) | ||||||
| 		ucv_array_set(reg, idx - 1, NULL); | 		return NULL; | ||||||
|  |  | ||||||
|  | 	ucv_array_set(reg, idx - 1, NULL); | ||||||
|  | 	dataptr = ucv_resource_dataptr(val, NULL); | ||||||
|  | 	if (dataptr) | ||||||
|  | 		*dataptr = NULL; | ||||||
|  |  | ||||||
| 	return val; | 	return val; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ | |||||||
| #include "utils/common.h" | #include "utils/common.h" | ||||||
| #include "utils/ucode.h" | #include "utils/ucode.h" | ||||||
| #include "drivers/driver.h" | #include "drivers/driver.h" | ||||||
|  | #include "ap/hostapd.h" | ||||||
| #include "wpa_supplicant_i.h" | #include "wpa_supplicant_i.h" | ||||||
| #include "wps_supplicant.h" | #include "wps_supplicant.h" | ||||||
| #include "bss.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); | 		ie = wpa_bss_get_ie(bss, WLAN_EID_HT_OPERATION); | ||||||
| 		if (ie && ie[1] >= 2) { | 		if (ie && ie[1] >= 2) { | ||||||
| 			const struct ieee80211_ht_operation *ht_oper; | 			const struct ieee80211_ht_operation *ht_oper; | ||||||
|  | 			int sec; | ||||||
|  |  | ||||||
| 			ht_oper = (const void *) (ie + 2); | 			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; | 				sec_chan = 1; | ||||||
| 			else if (ht_oper->ht_param & | 			else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) | ||||||
| 				 HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW) |  | ||||||
| 				sec_chan = -1; | 				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)); | 		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; | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -488,6 +488,7 @@ ${channel:+channel=$channel} | |||||||
| ${channel_list:+chanlist=$channel_list} | ${channel_list:+chanlist=$channel_list} | ||||||
| ${hostapd_noscan:+noscan=1} | ${hostapd_noscan:+noscan=1} | ||||||
| ${tx_burst:+tx_queue_data2_burst=$tx_burst} | ${tx_burst:+tx_queue_data2_burst=$tx_burst} | ||||||
|  | #num_global_macaddr=$num_global_macaddr | ||||||
| $base_cfg | $base_cfg | ||||||
|  |  | ||||||
| EOF | EOF | ||||||
| @@ -528,6 +529,7 @@ mac80211_hostapd_setup_bss() { | |||||||
| 	cat >> /var/run/hostapd-$phy.conf <<EOF | 	cat >> /var/run/hostapd-$phy.conf <<EOF | ||||||
| $hostapd_cfg | $hostapd_cfg | ||||||
| bssid=$macaddr | bssid=$macaddr | ||||||
|  | ${default_macaddr:+#default_macaddr} | ||||||
| ${dtim_period:+dtim_period=$dtim_period} | ${dtim_period:+dtim_period=$dtim_period} | ||||||
| ${max_listen_int:+max_listen_interval=$max_listen_int} | ${max_listen_int:+max_listen_interval=$max_listen_int} | ||||||
| EOF | EOF | ||||||
| @@ -542,57 +544,9 @@ mac80211_get_addr() { | |||||||
|  |  | ||||||
| mac80211_generate_mac() { | mac80211_generate_mac() { | ||||||
| 	local phy="$1" | 	local phy="$1" | ||||||
| 	local multiple_bssid="$2" |  | ||||||
| 	local id="${macidx:-0}" | 	local id="${macidx:-0}" | ||||||
|  |  | ||||||
| 	local ref="$(cat /sys/class/ieee80211/${phy}/macaddress)" | 	wdev_tool "$phy" get_macaddr id=$id num_global=$num_global_macaddr mbssid=$multiple_bssid | ||||||
| 	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 )) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| find_phy() { | find_phy() { | ||||||
| @@ -626,11 +580,14 @@ mac80211_prepare_vif() { | |||||||
| 	set_default powersave 0 | 	set_default powersave 0 | ||||||
| 	json_add_string _ifname "$ifname" | 	json_add_string _ifname "$ifname" | ||||||
|  |  | ||||||
|  | 	default_macaddr= | ||||||
| 	[ -n "$macaddr" ] || { | 	[ -n "$macaddr" ] || { | ||||||
| 		macaddr="$(mac80211_generate_mac $phy $multiple_bssid)" | 		macaddr="$(mac80211_generate_mac $phy)" | ||||||
|  		macidx="$(($macidx + 1))" |  		macidx="$(($macidx + 1))" | ||||||
|  | 		default_macaddr=1 | ||||||
| 	} | 	} | ||||||
| 	json_add_string _macaddr "$macaddr" | 	json_add_string _macaddr "$macaddr" | ||||||
|  | 	json_add_string _default_macaddr "$default_macaddr" | ||||||
| 	json_select .. | 	json_select .. | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -754,7 +711,7 @@ mac80211_setup_adhoc() { | |||||||
|  |  | ||||||
| 	json_add_object "$ifname" | 	json_add_object "$ifname" | ||||||
| 	json_add_string mode adhoc | 	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 ssid "$ssid" | ||||||
| 	json_add_string freq "$freq" | 	json_add_string freq "$freq" | ||||||
| 	json_add_string htmode "$iw_htmode" | 	json_add_string htmode "$iw_htmode" | ||||||
| @@ -780,7 +737,7 @@ mac80211_setup_mesh() { | |||||||
|  |  | ||||||
| 	json_add_object "$ifname" | 	json_add_object "$ifname" | ||||||
| 	json_add_string mode mesh | 	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 ssid "$ssid" | ||||||
| 	json_add_string freq "$freq" | 	json_add_string freq "$freq" | ||||||
| 	json_add_string htmode "$iw_htmode" | 	json_add_string htmode "$iw_htmode" | ||||||
| @@ -831,7 +788,6 @@ wpa_supplicant_init_config() { | |||||||
| wpa_supplicant_add_interface() { | wpa_supplicant_add_interface() { | ||||||
| 	local ifname="$1" | 	local ifname="$1" | ||||||
| 	local mode="$2" | 	local mode="$2" | ||||||
| 	local hostapd_ctrl="$3" |  | ||||||
| 	local prev | 	local prev | ||||||
|  |  | ||||||
| 	_wpa_supplicant_common "$ifname" | 	_wpa_supplicant_common "$ifname" | ||||||
| @@ -843,9 +799,8 @@ wpa_supplicant_add_interface() { | |||||||
| 	json_add_string iface "$ifname" | 	json_add_string iface "$ifname" | ||||||
| 	json_add_string mode "$mode" | 	json_add_string mode "$mode" | ||||||
| 	json_add_string config "$_config" | 	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 "$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" | 	[ -n "$wds" ] && json_add_boolean 4addr "$wds" | ||||||
| 	json_add_boolean powersave "$powersave" | 	json_add_boolean powersave "$powersave" | ||||||
| 	[ "$mode" = "mesh" ] && mac80211_add_mesh_params | 	[ "$mode" = "mesh" ] && mac80211_add_mesh_params | ||||||
| @@ -920,7 +875,7 @@ mac80211_setup_supplicant() { | |||||||
| 		wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan" | 		wpa_supplicant_add_network "$ifname" "$freq" "$htmode" "$noscan" | ||||||
| 	fi | 	fi | ||||||
|  |  | ||||||
| 	wpa_supplicant_add_interface "$ifname" "$mode" "$hostapd_ctrl" | 	wpa_supplicant_add_interface "$ifname" "$mode" | ||||||
|  |  | ||||||
| 	return 0 | 	return 0 | ||||||
| } | } | ||||||
| @@ -932,6 +887,7 @@ mac80211_setup_vif() { | |||||||
| 	json_select config | 	json_select config | ||||||
| 	json_get_var ifname _ifname | 	json_get_var ifname _ifname | ||||||
| 	json_get_var macaddr _macaddr | 	json_get_var macaddr _macaddr | ||||||
|  | 	json_get_var default_macaddr _default_macaddr | ||||||
| 	json_get_vars mode wds powersave | 	json_get_vars mode wds powersave | ||||||
|  |  | ||||||
| 	set_default powersave 0 | 	set_default powersave 0 | ||||||
| @@ -1014,7 +970,7 @@ mac80211_reset_config() { | |||||||
| 	hostapd_conf_file="/var/run/hostapd-$phy.conf" | 	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 hostapd config_set '{ "phy": "'"$phy"'", "config": "", "prev_config": "'"$hostapd_conf_file"'" }' > /dev/null | ||||||
| 	ubus call wpa_supplicant config_set '{ "phy": "'"$phy"'", "config": [] }' > /dev/null | 	ubus call wpa_supplicant config_set '{ "phy": "'"$phy"'", "config": [] }' > /dev/null | ||||||
| 	wdev_tool "$phy" '{}' | 	wdev_tool "$phy" set_config '{}' | ||||||
| } | } | ||||||
|  |  | ||||||
| drv_mac80211_setup() { | drv_mac80211_setup() { | ||||||
| @@ -1116,7 +1072,7 @@ drv_mac80211_setup() { | |||||||
|  |  | ||||||
| 	mac80211_prepare_iw_htmode | 	mac80211_prepare_iw_htmode | ||||||
| 	active_ifnames= | 	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 | 	for_each_interface "ap sta adhoc mesh monitor" mac80211_setup_vif | ||||||
|  |  | ||||||
| 	[ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_set_config "$phy" | 	[ -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" | 	[ -x /usr/sbin/wpa_supplicant ] && wpa_supplicant_start "$phy" | ||||||
|  |  | ||||||
| 	json_set_namespace wdev_uc prev | 	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" | 	json_set_namespace "$prev" | ||||||
|  |  | ||||||
| 	for_each_interface "ap sta adhoc mesh monitor" mac80211_set_vif_txpower | 	for_each_interface "ap sta adhoc mesh monitor" mac80211_set_vif_txpower | ||||||
|   | |||||||
| @@ -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; | ||||||
| @@ -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); | ||||||
|  |   | ||||||
							
								
								
									
										285
									
								
								patches/backports/0060-netif-dynamic-iface.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										285
									
								
								patches/backports/0060-netif-dynamic-iface.patch
									
									
									
									
									
										Normal 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 | ||||||
|  |  | ||||||
							
								
								
									
										607
									
								
								patches/backports/0061-netifd-vlan-fix.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										607
									
								
								patches/backports/0061-netifd-vlan-fix.patch
									
									
									
									
									
										Normal 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 | ||||||
|  |  | ||||||
| @@ -381,9 +381,9 @@ index 65ae662c4d..90d9210410 100644 | |||||||
|  			# Here we make the assumption that if we're in open mode |  			# Here we make the assumption that if we're in open mode | ||||||
|  			# with WPS enabled, we got to be in unconfigured state. |  			# with WPS enabled, we got to be in unconfigured state. | ||||||
|  			wps_not_configured=1 |  			wps_not_configured=1 | ||||||
|  | +			vlan_possible=1 | ||||||
| +			[ "$macfilter" = radius ] && { | +			[ "$macfilter" = radius ] && { | ||||||
| +				append_radius_server | +				append_radius_server | ||||||
| +				vlan_possible=1 |  | ||||||
| +			} | +			} | ||||||
|  		;; |  		;; | ||||||
|  		psk|sae|psk-sae) |  		psk|sae|psk-sae) | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								profiles/cig_wf186h.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								profiles/cig_wf186h.yml
									
									
									
									
									
										Normal 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 | ||||||
|  |  | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user