Compare commits

..

67 Commits

Author SHA1 Message Date
John Crispin
36b5478005 ipq807x: fix dwc3 module dependency
Signed-off-by: John Crispin <john@phrozen.org>
2022-04-06 08:54:20 +02:00
John Crispin
1ad19297c1 ipq807x: factory images for wf196 were generated with a bad page size
Signed-off-by: John Crispin <john@phrozen.org>
2022-04-06 08:53:20 +02:00
John Crispin
f5357f7854 ath11k: add ath11k-fwtest support
Signed-off-by: John Crispin <john@phrozen.org>
2022-04-05 17:21:55 +02:00
Johann Hoffmann
8a3140b89b Add dummy workflow to test workflow modifications in PR branch
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-04-05 15:13:54 +02:00
John Crispin
16e0724ace ramips: fix actiontec web7200 dual boot
Signed-off-by: John Crispin <john@phrozen.org>
2022-04-04 16:09:55 +02:00
wenij
17ff9eecf5 ipq807x: cybertan eww622 usb xchi driver not work
Signed-off-by: wenij <wenij.chang@cybertan.com.tw>
2022-04-04 10:54:46 +02:00
wenij
4b870f978c ipq807x: Cybertan EWW622-A1 get mac address from nand devinfo partition.
Signed-off-by: wenij <wenij.chang@cybertan.com.tw>
2022-04-04 10:53:10 +02:00
John Crispin
8b83365961 ucentral-schema: update to latest HEAD
7015feb improve wifi reload

Signed-off-by: John Crispin <john@phrozen.org>
2022-04-04 06:54:06 +02:00
John Crispin
c6ebb5537a ucentral-schema: update to latest HEAD
e12bc03 revert hostapd restart hack as the root cause of the channel issue was found

Signed-off-by: John Crispin <john@phrozen.org>
2022-04-01 14:15:50 +02:00
John Crispin
6ebe189d71 ramips: fix uboot-env-tools mtd offset
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-31 13:41:16 +02:00
John Crispin
98b56551d5 mac80211: automatically restart wifi if bringup failed
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-31 10:58:50 +02:00
John Crispin
606e27e256 wifi: fix channel select when using ACS
there were several small issues that caused ACS to leave the radio in a bad state
during sanity runs.

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-31 10:58:45 +02:00
John Crispin
94fe14b9f9 ucentral-schema: update to latest HEAD
4cff999 add a 5s delay on config re-apply to give wifi time to restart

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-30 16:46:43 +02:00
John Crispin
58388f84b6 ipq40xx: add status led support on udaya board
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-29 13:44:54 +02:00
John Crispin
79ea04af49 ipq807x: re-add accidentially deleted config-default
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-29 13:22:38 +02:00
John Crispin
396e2bd06c ucentral-client: cleanup health parameter
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-29 07:29:12 +02:00
John Crispin
1a484c7f39 protobuf: drop legacy out of tree package
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-28 15:12:04 +02:00
John Crispin
e6b1030991 ucentral-schema: update to latest HEAD
9ac9f7e health: add a 75s delay when applying a new config

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-25 16:08:34 +01:00
John Crispin
6e32e68302 ucentral-client: update to latest HEAD
6cb4485 drop healthcheck from the client and move it to its own service

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-25 16:08:34 +01:00
John Crispin
0f13f7f5cd ipq40xx: add support for udaya a5 id2
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-25 16:08:34 +01:00
John Crispin
2ac4f9ef1d ucentral-schema: update to latest HEAD
fb6db0f force hapd restart upon cfg apply
ee0a8a4 broadband username was not getting applied correctly

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-24 15:59:34 +01:00
wenij
f1a75c25f9 ipq807x: Cybertan EWW622-A1 LED fixes
Signed-off-by: wenij <wenij.chang@cybertan.com.tw>
2022-03-24 15:59:34 +01:00
John Crispin
ff8d70753d ucentral-event: update to latest HEAD
24b7fb3 use async invoke when sending events

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-23 12:09:25 +01:00
John Crispin
caea6baecd certificates: create ubivolume with LEBs instead of MiB
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-23 11:51:32 +01:00
John Crispin
2e914c9b35 ipq807x: use CIG mac address hack on wf196
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-23 11:50:34 +01:00
Jianhui Zhao
da65d7e06f ipq807x: add initial support for GL.iNet AXT1800
Hardware:
* SoC: Qcom IPQ6000
* RAM: DDR3L 512MB
* Flash: 128MB Nand
* Ethernet: 3x GbE
* WLAN: 2x2 2.4GHz 600Mbps + 2x2 5GHz 1200Mbps (builtin + builtin)
* LEDS: 1x white, 1x blue
* Buttons: 1x switch, 1x reset
* USB: 1x 3.0(Type-A)
* SD: 1x microSD
* PWM Fan
* Power: 12VDC, 2A
* UART (4-pin, 2.54 mm pitch) pad on PCB
* JTAG (8-pin, 2.54 mm pitch) pad on PCB

Installation: upgrade "openwrt-ipq807x-glinet_ax1800-squashfs-sysupgrade.tar" directly.

Signed-off-by: Jianhui Zhao <jianhui.zhao@gl-inet.com>
2022-03-22 08:19:50 +01:00
Sohail Ahmad
d18eef480c ipq40xx: add Support for Indio's UM-325AC AP
Changes made in OpenWrt supported targets to Include Indio's UM-325AC AP which is an indoor WiFi5 AP based on ipq4019 chipset.

Signed-off-by: Sohail Ahmad <sohail@indionetworks.com>
2022-03-22 08:04:40 +01:00
John Crispin
f3532c66e5 ucentral-client: update to latest HEAD
63eddd2 send the original size when using compress_64

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-21 09:44:32 +01:00
Felix Fietkau
9678b1d6a5 ipq807x: backport clsact support
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2022-03-21 09:00:35 +01:00
John Crispin
379a4e2382 ucentral-schema: update to latest HEAD
fb537b9 enhance healthcheck to provide verbose error messages
2b65900 sysinfo: add helper tool to monitor memory consumption per service/instance

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-21 08:44:43 +01:00
John Crispin
edb33cd560 ucentral-schema: update to latest HEAD
5865d5a fix detection of pci radios

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-17 16:11:55 +01:00
John Crispin
2ff425ddeb ucentral-schema: update to latest HEAD
6dbd602 fix gre bridges
611af3d fix vxlan bridges

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-17 10:22:28 +01:00
John Crispin
7d016ac27f ucentral-schema: update to latest HEAD
d97a35c do not allow roaming for none, psk and wpa

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-15 18:49:51 +01:00
John Crispin
9790377dec ath11k-wifi: update cig wf196 BDF files
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-15 17:25:25 +01:00
John Crispin
597c547101 ipq807x: fix vmalloc on wf196
the built in wifi failed to start

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-15 16:24:33 +01:00
John Crispin
73b2645027 ucentral-schema: update to latest HEAD
9dfff17 fix include paths of the new wifi module

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-15 10:37:02 +01:00
John Crispin
8d58387d15 ucentral-schema: update to latest HEAD
ef7649f fix channel 140
302c5bf drop dependency on ucentral-wifi

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-14 17:19:07 +01:00
John Crispin
54dac4d348 ucode: update to latest HEAD
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-14 17:17:59 +01:00
John Crispin
a0880ed0f1 edgecore: disable dual boot on eap10x/ecw5211
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-11 16:28:41 +01:00
John Crispin
ed6d683980 ramips: add bmtv2 and nbnm support
this fixes the nand issue on the actiontec web7200

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-11 14:57:54 +01:00
John Crispin
4c72c6a35a ucentral-wifi: update to latest HEAD
aa9c3ee set the AP bssid inside the assoc list

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-11 07:59:34 +01:00
Sven Eckelmann
125d56866e batman-adv: Merge bugfixes from 2022.0
* allow netlink usage in unprivileged containers
* mcast: don't send link-local multicast to mcast routers

Origin: upstream, https://git.openwrt.org/?p=feed/routing.git;a=commit;h=9e2383e9b42087d5a3892366bed8b6bb4f868fe3
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2022-03-10 15:10:05 +01:00
Hendrik Borghorst
a70a767ec0 batman-adv: Prevent use from libc headers to not build with BIG_ENDIAN
Commit 97d35a552ec5b6ddf7923dd2f9a8eb973526acea of musl introduced the
macros __LITTLE_ENDIAN and __BIG_ENDIAN in alltypes.h. These are pulled
into the compilation of batman-adv. This has the side effect that the
function is_multicast_ether_addr of etherdevice.h in Linux kernel is
compiled as the big endian version and so fails to work properly on
little endian devices.

This commits prevents pulling in header files of musl libc similar to
OpenWRT commit 9ac47ee46918c45b91f4e4d1fa76b1e26b9d57fe

Origin: upstream, https://git.openwrt.org/?p=feed/routing.git;a=commit;h=47436b04fd32cf3b6e6b46c25cb9c1fff3a995fd
Signed-off-by: Hendrik Borghorst <hendrikborghorst@gmail.com>
(cherry picked from commit 523821c1959cb288b55b7fcc8761c83f6ff48c4d)
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2022-03-10 15:10:05 +01:00
Sven Eckelmann
b8a6764207 batman-adv: Merge bugfixes from 2021.4
* fix error handling during interface initialization

Origin: upstream, https://git.openwrt.org/?p=feed/routing.git;a=commit;h=6d10a01dfa68eb5e25b84b33e33aefd312f46f4d
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2022-03-10 15:10:05 +01:00
Sven Eckelmann
98c9fcfd5d batman-adv: Refresh patches with quilt
The test builds are now requiring quilt refreshed patches instead of git
patches. Otherwise the build check will not even try to build something.

Origin: upstream, https://git.openwrt.org/?p=feed/routing.git;a=commit;h=e294a224640e03791a101a9302dbf72b06efab80
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2022-03-10 15:10:05 +01:00
Sven Eckelmann
eac5504fec batman-adv: Merge bugfixes from 2021.2
* Avoid WARN_ON timing related checks

Origin: upstream, https://git.openwrt.org/?p=feed/routing.git;a=commit;h=519ef4ad29a8e53c1763df1553d386e3abf6206d
Signed-off-by: Sven Eckelmann <sven@narfation.org>
2022-03-10 15:10:05 +01:00
Piotr Dymacz
c2c75b67eb ipq807x: add initial support for YunCore AX840
This adds initial support for the YunCore AX840, an IPQ6010 based
802.11ax ceiling AP.

Specifications:

- Qualcomm IPQ6010
- 1 GB of RAM (DDR3)
- 8 MB of serial flash (SPI NOR)
- 256 MB of parallel flash (NAND)
- 2x2 2.4 GHz WiFi (IPQ6010)
- 2x2 5 GHz WiFi (IPQ6010)
- 2x IPEX/U.FL antenna connectors
- 4x 3 dBi dual-band antennas
- 2x 1 Gbps Ethernet (QCA8075) with 802.3at PoE input support
- 1x RGB LED
- 1x push-button (reset)
- DC jack for main power input (12 V)
- UART (4-pin, 2.54 mm pitch) header on PCB

Flash instruction under stock QSDK image:

  sysupgrade -n openwrt-ipq807x-yuncore_ax840-squashfs-nand-factory.bin

Flash instruction under U-Boot:

  tftpb 0x44000000 openwrt-ipq807x-yuncore_ax840-squashfs-nand-factory.ubi
  flash rootfs
  reset

Signed-off-by: Piotr Dymacz <pepe2k@gmail.com>
2022-03-10 14:50:37 +01:00
John Crispin
ef3eacefa7 ath11k-wifi: update WF188n BDF
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-10 08:21:58 +01:00
John Crispin
ef7481596a qosify: update to latest HEAD
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-10 08:18:47 +01:00
Paul Spooren
6f4e00aa46 README: fix linksys_ea8300 example
The profile is no longer called just `ea8300`.

Signed-off-by: Paul Spooren <mail@aparcar.org>
2022-03-10 07:59:59 +01:00
Jianhui Zhao
be65578a7f profile: add gl-ax1800 support
Because we have an another similar device named gl-axt1800,
so we put the common functions in a dtsi file. And we'll
submit a PR for gl-axt1800 soon.

Hardware:
* SoC: Qcom IPQ6000
* RAM: DDR3L 512MB
* Flash: 128MB Nand
* Ethernet: 5x GbE
* WLAN: 2x2 2.4GHz 600Mbps + 2x2 5GHz 1200Mbps (builtin + builtin)
* LEDS: 1x white, 1x blue
* Buttons: 1x switch, 1x reset
* USB: 1x 3.0(Type-A)
* Power: 12VDC, 1.5A

Installation:
* from qsdk to openwifi:
upgrade "openwrt-ipq807x-glinet_ax1800-squashfs-nand-factory.bin" via web ui
without keep config.
* upgrade "openwrt-ipq807x-glinet_ax1800-squashfs-sysupgrade.tar" if you are already in openwifi.

Signed-off-by: Jianhui Zhao <jianhui.zhao@gl-inet.com>
2022-03-10 07:59:21 +01:00
John Crispin
20d4bd0c7d ucentral-schema: fix online-check
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-10 07:52:13 +01:00
John Crispin
531f4eb811 ucentral-schema: update to latest HEAD
4532c47 fix downstream bridges with no eth ports
04edaef ntp: open firewall port if ntpd is enabled
bf11105 fix led-active restart
c95667a a failed apply should return the error code 2
72e225e capabilities: add label_macaddr to capabilities

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-10 07:52:13 +01:00
John Crispin
3b0dae7189 ucentral-schema: update to latest HEAD
72e225e capabilities: add label_macaddr to capabilities
f09f2b2 state: improve link metric, add ssid location
5586b93 unit: improve password generation
959a40d system: add sysinfo / resource consumption reporting
cdfb209 state: fix link state reporting

Fixes: WIFI-7210
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-03 17:12:31 +01:00
John Crispin
79395593ba ipq807x: add support for label_macaddr
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-03 17:09:21 +01:00
John Crispin
61248b98e0 ucentral-schema: set executable bit for wifi_max_user.uc
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-02 16:02:18 +01:00
Felix Fietkau
72b5abb72a ath10k: enable threaded napi support
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2022-03-02 15:45:08 +01:00
Felix Fietkau
673a029a02 ipq807x: enable threaded napi on ethernet
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2022-03-02 15:45:08 +01:00
Felix Fietkau
7efb85180f ipq807x: backport threaded napi support
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2022-03-02 15:45:08 +01:00
Felix Fietkau
f95eadaa8f ipq807x: backport kbuild fix to avoid spurious rebuilds
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2022-03-02 15:45:08 +01:00
Felix Fietkau
6f6b40a94f toolchain/gcc: fix building gcc 5.5 on newer systems
Signed-off-by: Felix Fietkau <nbd@nbd.name>
2022-03-02 15:45:08 +01:00
John Crispin
d84982f161 ath11k: fix WDS when encap offload is enabled
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-02 15:45:08 +01:00
John Crispin
4b07afe59f ucentral-schema: update to latest HEAD
19fcc8d update schemareader
bef2a8f state: add the upstream dhcp servers ip to the state message

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-02 15:12:50 +01:00
John Crispin
5d53d138b0 maverick: add the last 3 bytes of the serial to the Maverick ssid
Fixes: WIFI-7202
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-02 15:12:21 +01:00
John Crispin
e40631b8cd ucentral-schema: update to latest HEAD
ba41897 radio: enable 'allow-dfs' by default

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-01 17:36:54 +01:00
John Crispin
22135129bd treewide: fix pkg hashes
Signed-off-by: John Crispin <john@phrozen.org>
2022-03-01 17:36:52 +01:00
John Crispin
de4b3c4edc ucentral-wifi: update to latest HEAD
40d0eb9 use the real usec value for tx/rx duration

Signed-off-by: John Crispin <john@phrozen.org>
2022-03-01 17:36:48 +01:00
121 changed files with 16601 additions and 3228 deletions

View File

@@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
target: ['actiontec_web7200', 'cig_wf188n', 'cig_wf194c', 'cig_wf194c4', 'cig_wf196', 'cig_wf160d', 'cig_wf808', 'cybertan_eww622-a1', 'edgecore_eap101', 'edgecore_eap102', 'edgecore_eap104', 'edgecore_ecs4100-12ph', 'edgecore_ecw5211', 'edgecore_ecw5410', 'edgecore_oap100', 'edgecore_ssw2ac2600', 'edgecore_spw2ac1200', 'edgecore_spw2ac1200-lan-poe', 'hfcl_ion4', 'hfcl_ion4xe', 'hfcl_ion4xi', 'indio_um-305ac', 'linksys_ea6350-v4', 'linksys_e8450-ubi', 'linksys_ea8300', 'tp-link_ec420-g1', 'tplink_ex227', 'tplink_ex228', 'tplink_ex447', 'wallys_dr40x9', 'wallys_dr6018', 'wallys_dr6018_v4' ]
target: ['actiontec_web7200', 'cig_wf188n', 'cig_wf194c', 'cig_wf194c4', 'cig_wf196', 'cig_wf160d', 'cig_wf808', 'cybertan_eww622-a1', 'edgecore_eap101', 'edgecore_eap102', 'edgecore_eap104', 'edgecore_ecs4100-12ph', 'edgecore_ecw5211', 'edgecore_ecw5410', 'edgecore_oap100', 'edgecore_ssw2ac2600', 'edgecore_spw2ac1200', 'edgecore_spw2ac1200-lan-poe', 'hfcl_ion4', 'hfcl_ion4xe', 'hfcl_ion4xi', 'indio_um-305ac', 'linksys_ea6350-v4', 'linksys_e8450-ubi', 'linksys_ea8300', 'tp-link_ec420-g1', 'tplink_ex227', 'tplink_ex228', 'tplink_ex447', 'udaya_a5-id2', 'wallys_dr40x9', 'wallys_dr6018', 'wallys_dr6018_v4' ]
steps:
- uses: actions/checkout@v2

10
.github/workflows/x64_vm-build-test.yml vendored Normal file
View File

@@ -0,0 +1,10 @@
name: Test x64_vm build and AMI creation
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo 'Test x64_vm build and AMI creation'

View File

@@ -12,7 +12,7 @@ First we need to clone and setup our tree. This will result in an openwrt/.
Next we need to select the profile and base package selection. This setup will install the feeds, packages and generate the .config file.
```
cd openwrt
./scripts/gen_config.py ea8300
./scripts/gen_config.py linksys_ea8300
```
Finally we can build the tree.
```

View File

@@ -39,6 +39,10 @@ hfcl,ion4xe)
ucidef_set_led_wlan "wlan5g" "WLAN5G" "blue:wifi5" "phy0tpt"
ucidef_set_led_wlan "wlan2g" "WLAN2G" "blue:wifi2" "phy1tpt"
;;
glinet,ax1800|\
glinet,axt1800)
ucidef_set_led_netdev "wan" "WAN" "blue:wan" "eth0" "tx rx link"
;;
esac
board_config_flush

View File

@@ -32,11 +32,13 @@ qcom_setup_interfaces()
cig,wf194c4|\
edgecore,eap106|\
qcom,ipq5018-mp03.3|\
yuncore,ax840|\
sercomm,wallaby)
ucidef_set_interface_lan "eth0"
ucidef_set_interface_wan "eth1"
;;
edgecore,eap101)
edgecore,eap101|\
glinet,axt1800)
ucidef_set_interface_lan "eth1 eth2"
ucidef_set_interface_wan "eth0"
;;
@@ -52,7 +54,8 @@ qcom_setup_interfaces()
ucidef_set_interface_lan "eth0 eth1 eth2 eth3"
ucidef_set_interface_wan "eth4"
;;
wallys,dr6018-v4)
wallys,dr6018-v4|\
glinet,ax1800)
ucidef_set_interface_lan "eth1 eth2 eth3 eth4"
ucidef_set_interface_wan "eth0"
;;
@@ -73,7 +76,8 @@ qcom_setup_macs()
case $board in
cig,wf194c|\
cig,wf194c4)
cig,wf194c4|\
cig,wf196)
mac=$(grep BaseMacAddress= /dev/mtd14 | cut -dx -f2)
wan_mac=$(macaddr_canonicalize $mac)
lan_mac=$(macaddr_add "$wan_mac" 1)
@@ -81,6 +85,15 @@ qcom_setup_macs()
ucidef_set_network_device_mac eth1 $wan_mac
ucidef_set_label_macaddr $wan_mac
;;
cybertan,eww622-a1)
mac=$(grep -i -m 1 mac_addr_base= /dev/`cat /proc/mtd | grep devinfo | cut -d: -f1` | cut -d= -f2)
[ -z "$mac"] && mac="00:11:22:33:44:55"
wan_mac=$(macaddr_canonicalize $mac)
lan_mac=$(macaddr_add "$wan_mac" 1)
ucidef_set_network_device_mac eth0 $wan_mac
ucidef_set_network_device_mac eth1 $lan_mac
ucidef_set_label_macaddr $wan_mac
;;
*)
wan_mac=$(cat /sys/class/net/eth0/address)
lan_mac=$(macaddr_add "$wan_mac" 1)
@@ -88,6 +101,7 @@ qcom_setup_macs()
esac
[ -n "$lan_mac" ] && ucidef_set_interface_macaddr "lan" $lan_mac
[ -n "$wan_mac" ] && ucidef_set_interface_macaddr "wan" $wan_mac
[ -n "$wan_mac" ] && ucidef_set_label_macaddr "$wan_mac"
}
board_config_update

View File

@@ -81,6 +81,7 @@ case "$FIRMWARE" in
qcom,ipq807x-hk14|\
tplink,ex227|\
tplink,ex447|\
yuncore,ax840|\
sercomm,wallaby)
caldata_extract "0:ART" 0x1000 0x20000
;;
@@ -96,7 +97,8 @@ case "$FIRMWARE" in
wallys,dr6018|\
wallys,dr6018-v4|\
qcom,ipq6018-cp01|\
xiaomi,ax1800)
xiaomi,ax1800|\
glinet,ax1800)
caldata_extract "0:ART" 0x1000 0x20000
;;
esac

View File

@@ -6,7 +6,11 @@ boot() {
case "$(board_name)" in
edgecore,eap101|\
edgecore,eap102)
fw_setenv bootcount 0
avail=$(fw_printenv -n upgrade_available)
[ ${avail} -eq 0 ] || {
fw_setenv bootcount 0
fw_setenv upgrade_available 0
}
;;
esac
}

View File

@@ -26,6 +26,8 @@ platform_check_image() {
cig,wf194c4|\
cig,wf196|\
cybertan,eww622-a1|\
glinet,ax1800|\
glinet,axt1800|\
wallys,dr6018|\
wallys,dr6018-v4|\
edgecore,eap101|\
@@ -36,6 +38,7 @@ platform_check_image() {
hfcl,ion4xe|\
tplink,ex227|\
tplink,ex447|\
yuncore,ax840|\
qcom,ipq6018-cp01|\
qcom,ipq807x-hk01|\
qcom,ipq807x-hk14|\
@@ -62,6 +65,8 @@ platform_do_upgrade() {
cig,wf196|\
cybertan,eww622-a1|\
edgecore,eap104|\
glinet,ax1800|\
glinet,axt1800|\
hfcl,ion4xi|\
hfcl,ion4xe|\
qcom,ipq6018-cp01|\
@@ -70,6 +75,7 @@ platform_do_upgrade() {
qcom,ipq5018-mp03.3|\
wallys,dr6018|\
wallys,dr6018-v4|\
yuncore,ax840|\
tplink,ex447|\
tplink,ex227)
nand_upgrade_tar "$1"

View File

@@ -0,0 +1,18 @@
/*
* Copyright (c) 2019, 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-ipq6018-gl-ax1800.dts"
#include "qcom-ipq6018.dtsi"

View File

@@ -0,0 +1,18 @@
/*
* Copyright (c) 2019, 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-ipq6018-gl-axt1800.dts"
#include "qcom-ipq6018.dtsi"

View File

@@ -0,0 +1,18 @@
/*
* Copyright (c) 2019, 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-ipq6018-yuncore-ax840.dts"
#include "qcom-ipq6018.dtsi"

View File

@@ -32,6 +32,10 @@
serial1 = &blsp1_uart2;
ethernet0 = "/soc/dp1";
ethernet1 = "/soc/dp2";
led-boot = &led_sys;
led-failsafe = &led_sys;
led-running = &led_sys;
led-upgrade = &led_sys;
};
chosen {
@@ -708,32 +712,20 @@
pinctrl-0 = <&leds_pins>;
pinctrl-names = "default";
led@1 {
led_sys: led@1 {
label = "sys:blue";
gpios = <&tlmm 1 GPIO_ACTIVE_HIGH>; /* GPIO_1 */
/* default-state="on"; */
linux,default-trigger = "timer";
active-delay = <700>;
inactive-delay = <700>;
default-state="on";
};
led@35 {
label = "sys:green";
gpios = <&tlmm 35 GPIO_ACTIVE_HIGH>; /* GPIO_35 */
default-state="off";
/* linux,default-trigger = "timer";
active-delay = <700>;
inactive-delay = <700>;
default-state="on"; */
};
led@31 {
label = "sys:red";
gpios = <&tlmm 31 GPIO_ACTIVE_HIGH>; /* GPIO_31 */
default-state="off";
/* linux,default-trigger = "timer";
active-delay = <700>;
inactive-delay = <700>;
default-state="on"; */
};
};
};

View File

@@ -0,0 +1,78 @@
/dts-v1/;
/*
* Copyright (c) 2019, 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-ipq6018-gl-ax1800.dtsi"
/ {
model = "GL Technologies, Inc. AX1800";
compatible = "glinet,ax1800", "qcom,ipq6018-cp03", "qcom,ipq6018";
aliases {
ethernet3 = "/soc/dp4";
ethernet4 = "/soc/dp5";
};
};
&mdio0 {
phy3: ethernet-phy@3 {
reg = <3>;
};
phy4: ethernet-phy@4 {
reg = <4>;
};
};
&ess0 {
switch_lan_bmp = <0x3c>; /* lan port bitmap */
qcom,port_phyinfo {
port@3 {
port_id = <4>;
phy_address = <3>;
};
port@4 {
port_id = <5>;
phy_address = <4>;
};
};
};
&soc {
dp4 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <4>;
reg = <0x3a001600 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
qcom,link-poll = <1>;
qcom,phy-mdio-addr = <3>;
phy-mode = "sgmii";
};
dp5 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <5>;
reg = <0x3a001800 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
qcom,link-poll = <1>;
qcom,phy-mdio-addr = <4>;
phy-mode = "sgmii";
};
};

View File

@@ -0,0 +1,364 @@
/*
* Copyright (c) 2019, 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-ipq6018.dtsi"
#include <dt-bindings/input/input.h>
/ {
#address-cells = <0x2>;
#size-cells = <0x2>;
interrupt-parent = <&intc>;
qcom,msm-id = <0x1A5 0x0>;
aliases {
ethernet0 = "/soc/dp1";
ethernet1 = "/soc/dp2";
ethernet2 = "/soc/dp3";
led-boot = &led_run;
led-failsafe = &led_run;
led-running = &led_run;
led-upgrade = &led_run;
};
chosen {
bootargs = "console=ttyMSM0,115200,n8 rw init=/init";
bootargs-append = " swiotlb=1 coherent_pool=2M";
};
};
&tlmm {
uart_pins: uart_pins {
mux {
pins = "gpio44", "gpio45";
function = "blsp2_uart";
drive-strength = <8>;
bias-pull-down;
};
};
qpic_pins: qpic_pins {
data_0 {
pins = "gpio15";
function = "qpic_pad0";
drive-strength = <8>;
bias-pull-down;
};
data_1 {
pins = "gpio12";
function = "qpic_pad1";
drive-strength = <8>;
bias-pull-down;
};
data_2 {
pins = "gpio13";
function = "qpic_pad2";
drive-strength = <8>;
bias-pull-down;
};
data_3 {
pins = "gpio14";
function = "qpic_pad3";
drive-strength = <8>;
bias-pull-down;
};
data_4 {
pins = "gpio5";
function = "qpic_pad4";
drive-strength = <8>;
bias-pull-down;
};
data_5 {
pins = "gpio6";
function = "qpic_pad5";
drive-strength = <8>;
bias-pull-down;
};
data_6 {
pins = "gpio7";
function = "qpic_pad6";
drive-strength = <8>;
bias-pull-down;
};
data_7 {
pins = "gpio8";
function = "qpic_pad7";
drive-strength = <8>;
bias-pull-down;
};
qpic_pad {
pins = "gpio1", "gpio3", "gpio4",
"gpio10", "gpio11", "gpio17";
function = "qpic_pad";
drive-strength = <8>;
bias-pull-down;
};
};
button_pins: button_pins {
switch_button {
pins = "gpio9";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};
reset_button {
pins = "gpio18";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};
};
mdio_pins: mdio_pinmux {
mux_0 {
pins = "gpio64";
function = "mdc";
drive-strength = <8>;
bias-pull-up;
};
mux_1 {
pins = "gpio65";
function = "mdio";
drive-strength = <8>;
bias-pull-up;
};
mux_2 {
pins = "gpio74";
function = "gpio";
bias-pull-up;
};
};
leds_pins: leds_pins {
white {
pins = "gpio35";
function = "gpio";
drive-strength = <8>;
bias-pull-down;
};
blue {
pins = "gpio37";
function = "gpio";
drive-strength = <8>;
bias-pull-down;
};
};
usb_pins: usb_pins {
usb_pwr {
pins = "gpio0";
function = "gpio";
bias-pull-up;
output-high;
};
};
};
&soc {
mdio0: mdio@90000 {
pinctrl-0 = <&mdio_pins>;
pinctrl-names = "default";
phy-reset-gpio = <&tlmm 74 GPIO_ACTIVE_HIGH>;
status = "ok";
phy0: ethernet-phy@0 {
reg = <0>;
};
phy1: ethernet-phy@1 {
reg = <1>;
};
phy2: ethernet-phy@2 {
reg = <2>;
};
};
ess0: ess-switch@3a000000 {
switch_cpu_bmp = <0x1>; /* cpu port bitmap */
switch_lan_bmp = <0x0c>; /* lan port bitmap */
switch_wan_bmp = <0x02>; /* wan port bitmap */
switch_inner_bmp = <0xc0>; /*inner port bitmap*/
switch_mac_mode = <0x0>; /* mac mode for uniphy instance0*/
switch_mac_mode1 = <0xff>; /* mac mode for uniphy instance1*/
switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/
qcom,port_phyinfo {
port@0 {
port_id = <1>;
phy_address = <0>;
};
port@1 {
port_id = <2>;
phy_address = <1>;
};
port@2 {
port_id = <3>;
phy_address = <2>;
};
};
};
dp1 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <1>;
reg = <0x3a001000 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
qcom,link-poll = <1>;
qcom,phy-mdio-addr = <0>;
phy-mode = "sgmii";
};
dp2 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <2>;
reg = <0x3a001200 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
qcom,link-poll = <1>;
qcom,phy-mdio-addr = <1>;
phy-mode = "sgmii";
};
dp3 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <3>;
reg = <0x3a001400 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
qcom,link-poll = <1>;
qcom,phy-mdio-addr = <2>;
phy-mode = "sgmii";
};
leds {
compatible = "gpio-leds";
pinctrl-0 = <&leds_pins>;
pinctrl-names = "default";
led_run: led@35 {
label = "white:sys";
gpios = <&tlmm 35 GPIO_ACTIVE_HIGH>;
default-state = "on";
};
led@37 {
label = "blue:wan";
gpios = <&tlmm 37 GPIO_ACTIVE_HIGH>;
default-state = "on";
};
};
gpio_keys {
compatible = "gpio-keys";
pinctrl-0 = <&button_pins>;
pinctrl-names = "default";
switch {
label = "switch";
linux,code = <KEY_WPS_BUTTON>;
gpios = <&tlmm 9 GPIO_ACTIVE_LOW>;
linux,input-type = <1>;
debounce-interval = <60>;
};
reset {
label = "reset";
linux,code = <KEY_RESTART>;
gpios = <&tlmm 18 GPIO_ACTIVE_LOW>;
linux,input-type = <1>;
debounce-interval = <60>;
};
};
};
&blsp1_uart3 {
pinctrl-0 = <&uart_pins>;
pinctrl-names = "default";
status = "ok";
};
&qpic_bam {
status = "ok";
};
&nand {
pinctrl-0 = <&qpic_pins>;
pinctrl-names = "default";
status = "ok";
};
&ssphy_0 {
status = "ok";
};
&qusb_phy_0 {
status = "ok";
};
&usb3 {
pinctrl-0 = <&usb_pins>;
pinctrl-names = "default";
status = "ok";
};
&nss_crypto {
status = "ok";
};
&q6_region {
reg = <0x0 0x4ab00000 0x0 0x05500000>;
};
&CPU0 {
operating-points = <
/* kHz uV (fixed) */
864000 1100000
1056000 1100000
1200000 1100000
>;
clock-latency = <200000>;
};
&CPU1 {
operating-points = <
/* kHz uV (fixed) */
864000 1100000
1056000 1100000
1200000 1100000
>;
clock-latency = <200000>;
};
&CPU2 {
operating-points = <
/* kHz uV (fixed) */
864000 1100000
1056000 1100000
1200000 1100000
>;
clock-latency = <200000>;
};
&CPU3 {
operating-points = <
/* kHz uV (fixed) */
864000 1100000
1056000 1100000
1200000 1100000
>;
clock-latency = <200000>;
};

View File

@@ -0,0 +1,94 @@
/dts-v1/;
/*
* Copyright (c) 2019, 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-ipq6018-gl-ax1800.dtsi"
/ {
model = "GL Technologies, Inc. AXT1800";
compatible = "glinet,axt1800", "qcom,ipq6018-cp03", "qcom,ipq6018";
aliases {
sdhc0 = &sdhc_2;
};
};
&tlmm {
sd_pins: sd_pins {
sd {
pins = "gpio62";
function = "sd_card";
bias-pull-up;
};
ldo {
pins = "gpio66";
function = "gpio";
bias-pull-up;
};
};
pwm_pins: pwm_pinmux {
pwm {
pins = "gpio30";
function = "pwm13";
drive-strength = <8>;
};
};
fan_pins: fan_pins {
pwr {
pins = "gpio29";
function = "gpio";
bias-pull-up;
output-high;
};
speed {
pins = "gpio31";
function = "gpio";
drive-strength = <8>;
bias-pull-down;
};
};
};
&soc {
pwm:pwm {
#pwm-cells = <2>;
pinctrl-0 = <&pwm_pins>;
pinctrl-names = "default";
used-pwm-indices = <0>, <1>, <0>, <0>;
status = "ok";
};
pwm-fan {
compatible = "pwm-fan";
pinctrl-0 = <&fan_pins>;
pinctrl-names = "default";
cooling-min-state = <0>;
cooling-max-state = <3>;
#cooling-cells = <2>;
pwms = <&pwm 1 255>;
cooling-levels = <0 150 200 255>;
};
};
&sdhc_2 {
pinctrl-0 = <&sd_pins>;
pinctrl-names = "default";
cd-gpios = <&tlmm 62 1>;
sd-ldo-gpios = <&tlmm 66 1>;
status = "ok";
};

View File

@@ -0,0 +1,343 @@
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
/dts-v1/;
#include "qcom-ipq6018.dtsi"
#include "qcom-ipq6018-rpm-regulator.dtsi"
#include "qcom-ipq6018-cpr-regulator.dtsi"
#include "qcom-ipq6018-cp-cpu.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/gpio/gpio.h>
/ {
model = "YunCore AX840";
compatible = "yuncore,ax840", "qcom,ipq6018-cp03", "qcom,ipq6018";
#address-cells = <0x2>;
#size-cells = <0x2>;
interrupt-parent = <&intc>;
aliases {
/* Aliases as required by u-boot to patch MAC addresses */
ethernet0 = "/soc/dp2";
ethernet1 = "/soc/dp1";
serial0 = &blsp1_uart3;
serial1 = &blsp1_uart2;
led-boot = &led_system;
led-failsafe = &led_system;
led-running = &led_system;
led-upgrade = &led_system;
};
chosen {
bootargs = "console=ttyMSM0,115200,n8 rw init=/init";
bootargs-append = " swiotlb=1 coherent_pool=2M";
};
reserved-memory {
tzapp:tzapp@49B00000 { /* TZAPPS */
no-map;
reg = <0x0 0x49B00000 0x0 0x00600000>;
};
};
};
&tlmm {
uart_pins: uart_pins {
mux {
pins = "gpio44", "gpio45";
function = "blsp2_uart";
drive-strength = <8>;
bias-pull-down;
};
};
spi_0_pins: spi_0_pins {
mux {
pins = "gpio38", "gpio39", "gpio40", "gpio41";
function = "blsp0_spi";
drive-strength = <8>;
bias-pull-down;
};
};
qpic_pins: qpic_pins {
data_0 {
pins = "gpio15";
function = "qpic_pad0";
drive-strength = <8>;
bias-pull-down;
};
data_1 {
pins = "gpio12";
function = "qpic_pad1";
drive-strength = <8>;
bias-pull-down;
};
data_2 {
pins = "gpio13";
function = "qpic_pad2";
drive-strength = <8>;
bias-pull-down;
};
data_3 {
pins = "gpio14";
function = "qpic_pad3";
drive-strength = <8>;
bias-pull-down;
};
data_4 {
pins = "gpio5";
function = "qpic_pad4";
drive-strength = <8>;
bias-pull-down;
};
data_5 {
pins = "gpio6";
function = "qpic_pad5";
drive-strength = <8>;
bias-pull-down;
};
data_6 {
pins = "gpio7";
function = "qpic_pad6";
drive-strength = <8>;
bias-pull-down;
};
data_7 {
pins = "gpio8";
function = "qpic_pad7";
drive-strength = <8>;
bias-pull-down;
};
qpic_pad {
pins = "gpio1", "gpio3", "gpio4",
"gpio10", "gpio11", "gpio17";
function = "qpic_pad";
drive-strength = <8>;
bias-pull-down;
};
};
button_pins: button_pins {
rst_button {
pins = "gpio19";
function = "gpio";
drive-strength = <8>;
bias-pull-up;
};
};
mdio_pins: mdio_pinmux {
mux_0 {
pins = "gpio64";
function = "mdc";
drive-strength = <8>;
bias-pull-up;
};
mux_1 {
pins = "gpio65";
function = "mdio";
drive-strength = <8>;
bias-pull-up;
};
mux_2 {
pins = "gpio75";
function = "gpio";
bias-pull-up;
};
};
leds_pins: leds_pins {
led_blue {
pins = "gpio35";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
led_green {
pins = "gpio37";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
led_red {
pins = "gpio32";
function = "gpio";
drive-strength = <2>;
bias-pull-down;
};
};
};
&soc {
mdio: mdio@90000 {
status = "ok";
pinctrl-0 = <&mdio_pins>;
pinctrl-names = "default";
phy-reset-gpio = <&tlmm 75 0>;
ethernet-phy@0 {
reg = <0x03>;
};
ethernet-phy@1 {
reg = <0x04>;
};
};
ess-switch@3a000000 {
switch_cpu_bmp = <0x01>; /* cpu port bitmap */
switch_lan_bmp = <0x10>; /* lan port bitmap */
switch_wan_bmp = <0x20>; /* wan port bitmap */
switch_inner_bmp = <0x80>; /*inner port bitmap*/
switch_mac_mode = <0x00>; /* mac mode for uniphy instance0*/
switch_mac_mode1 = <0xff>; /* mac mode for uniphy instance1*/
switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/
qcom,port_phyinfo {
port@3 {
port_id = <0x04>;
phy_address = <0x03>;
};
port@4 {
port_id = <0x05>;
phy_address = <0x04>;
};
};
};
dp1 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <0x05>;
reg = <0x3a001800 0x200>;
qcom,mactype = <0x00>;
local-mac-address = [00 00 00 00 00 00];
qcom,link-poll = <0x01>;
qcom,phy-mdio-addr = <0x04>;
phy-mode = "sgmii";
};
dp2 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <0x04>;
reg = <0x3a001600 0x200>;
qcom,mactype = <0x00>;
local-mac-address = [00 00 00 00 00 00];
qcom,link-poll = <0x01>;
qcom,phy-mdio-addr = <0x03>;
phy-mode = "sgmii";
};
gpio_keys {
compatible = "gpio-keys";
pinctrl-0 = <&button_pins>;
pinctrl-names = "default";
reset {
label = "reset";
linux,code = <KEY_RESTART>;
gpios = <&tlmm 19 GPIO_ACTIVE_LOW>;
linux,input-type = <1>;
debounce-interval = <60>;
};
};
leds {
compatible = "gpio-leds";
pinctrl-0 = <&leds_pins>;
pinctrl-names = "default";
led_system: system {
label = "ax860:green:system";
gpio = <&tlmm 37 GPIO_ACTIVE_HIGH>;
};
wlan2g {
label = "ax860:blue:wlan2g";
gpio = <&tlmm 35 GPIO_ACTIVE_HIGH>;
};
wlan5g {
label = "ax860:red:wlan5g";
gpio = <&tlmm 32 GPIO_ACTIVE_HIGH>;
};
};
};
&blsp1_uart3 {
pinctrl-0 = <&uart_pins>;
pinctrl-names = "default";
status = "ok";
};
&spi_0 {
pinctrl-0 = <&spi_0_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;
};
};
&qpic_bam {
status = "ok";
};
&nand {
pinctrl-0 = <&qpic_pins>;
pinctrl-names = "default";
status = "ok";
};
&nss_crypto {
status = "ok";
};
&cpu0_opp_table {
compatible = "operating-points-v2";
opp-shared;
opp03 {
opp-hz = /bits/ 64 <1200000000>;
opp-microvolt = <3>;
clock-latency-ns = <200000>;
};
/delete-node/ opp04;
/delete-node/ opp05;
/delete-node/ opp06;
};
&qseecom {
mem-start = <0x49B00000>;
mem-size = <0x600000>;
status = "ok";
};

View File

@@ -51,7 +51,7 @@
#ifdef __IPQ_MEM_PROFILE_256_MB__
bootargs-append = " swiotlb=1";
#else
bootargs-append = " swiotlb=1 coherent_pool=2M";
bootargs-append = " swiotlb=1 coherent_pool=2M vmalloc=600M";
#endif
};

View File

@@ -72,3 +72,30 @@ define Device/qcom_cp01_c1
DEVICE_PACKAGES := ath11k-wifi-qcom-ipq6018
endef
TARGET_DEVICES += qcom_cp01_c1
define Device/glinet_ax1800
DEVICE_TITLE := GL-iNet AX1800
DEVICE_DTS := qcom-ipq6018-gl-ax1800
SUPPORTED_DEVICES := glinet,ax1800
DEVICE_DTS_CONFIG := config@cp03-c1
DEVICE_PACKAGES := ath11k-wifi-gl-ax1800 -kmod-usb-dwc3-of-simple kmod-usb-dwc3-qcom kmod-usb3
endef
TARGET_DEVICES += glinet_ax1800
define Device/glinet_axt1800
DEVICE_TITLE := GL-iNet AXT1800
DEVICE_DTS := qcom-ipq6018-gl-axt1800
SUPPORTED_DEVICES := glinet,axt1800
DEVICE_DTS_CONFIG := config@cp03-c1
DEVICE_PACKAGES := ath11k-wifi-gl-ax1800 -kmod-usb-dwc3-of-simple kmod-usb-dwc3-qcom kmod-usb3
endef
TARGET_DEVICES += glinet_axt1800
define Device/yuncore_ax840
DEVICE_TITLE := YunCore AX840
DEVICE_DTS := qcom-ipq6018-yuncore-ax840
DEVICE_DTS_CONFIG := config@cp03-c1
SUPPORTED_DEVICES := yuncore,ax840
DEVICE_PACKAGES := ath11k-wifi-yuncore-ax840 uboot-env
endef
TARGET_DEVICES += yuncore_ax840

View File

@@ -41,6 +41,8 @@ define Device/cig_wf196
DEVICE_DTS := qcom-ipq807x-wf196
DEVICE_DTS_CONFIG=config@hk14
SUPPORTED_DEVICES := cig,wf196
BLOCKSIZE := 256k
PAGESIZE := 4096
DEVICE_PACKAGES := ath11k-wifi-cig-wf196 aq-fw-download uboot-envtools kmod-usb3 kmod-usb2 \
ath11k-firmware-qcn9000 ath11k-wifi-cig-wf196_6g
endef

View File

@@ -111,3 +111,22 @@ define KernelPackage/diag-char/description
endef
$(eval $(call KernelPackage,diag-char))
define KernelPackage/usb-dwc3-qcom
TITLE:=DWC3 Qualcomm USB driver
DEPENDS:=@(!LINUX_4_14) @TARGET_ipq807x +kmod-usb-dwc3
KCONFIG:= CONFIG_USB_DWC3_QCOM
FILES:= $(LINUX_DIR)/drivers/usb/dwc3/dwc3-qcom.ko \
$(LINUX_DIR)/drivers/usb/dwc3/dbm.ko
AUTOLOAD:=$(call AutoLoad,53,dwc3-qcom dbm,1)
$(call AddDepends/usb)
endef
define KernelPackage/usb-dwc3-qcom/description
Some Qualcomm SoCs use DesignWare Core IP for USB2/3 functionality.
This driver also handles Qscratch wrapper which is needed for
peripheral mode support.
endef
$(eval $(call KernelPackage,usb-dwc3-qcom))

View File

@@ -0,0 +1,25 @@
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -96,10 +96,10 @@ obj-dirs := $(addprefix $(obj)/,$(obj-di
# Note: Files that end up in two or more modules are compiled without the
# KBUILD_MODNAME definition. The reason is that any made-up name would
# differ in different configs.
-name-fix = $(subst $(comma),_,$(subst -,_,$1))
-basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+name-fix = $(squote)$(quote)$(subst $(comma),_,$(subst -,_,$1))$(quote)$(squote)
+basename_flags = -DKBUILD_BASENAME=$(call name-fix,$(basetarget))
modname_flags = $(if $(filter 1,$(words $(modname))),\
- -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+ -DKBUILD_MODNAME=$(call name-fix,$(modname)))
orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \
$(ccflags-y) $(CFLAGS_$(basetarget).o)
@@ -155,7 +155,7 @@ endif
c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
$(__c_flags) $(modkern_cflags) \
- -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
+ $(basename_flags) $(modname_flags)
a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \
$(__a_flags) $(modkern_aflags)

View File

@@ -0,0 +1,88 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Mon, 8 Feb 2021 11:34:08 -0800
Subject: [PATCH] net: extract napi poll functionality to __napi_poll()
This commit introduces a new function __napi_poll() which does the main
logic of the existing napi_poll() function, and will be called by other
functions in later commits.
This idea and implementation is done by Felix Fietkau <nbd@nbd.name> and
is proposed as part of the patch to move napi work to work_queue
context.
This commit by itself is a code restructure.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Wei Wang <weiwan@google.com>
Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6322,15 +6322,10 @@ void netif_napi_del(struct napi_struct *
}
EXPORT_SYMBOL(netif_napi_del);
-static int napi_poll(struct napi_struct *n, struct list_head *repoll)
+static int __napi_poll(struct napi_struct *n, bool *repoll)
{
- void *have;
int work, weight;
- list_del_init(&n->poll_list);
-
- have = netpoll_poll_lock(n);
-
weight = n->weight;
/* This NAPI_STATE_SCHED test is for avoiding a race
@@ -6348,7 +6343,7 @@ static int napi_poll(struct napi_struct
WARN_ON_ONCE(work > weight);
if (likely(work < weight))
- goto out_unlock;
+ return work;
/* Drivers must not modify the NAPI state if they
* consume the entire weight. In such cases this code
@@ -6357,7 +6352,7 @@ static int napi_poll(struct napi_struct
*/
if (unlikely(napi_disable_pending(n))) {
napi_complete(n);
- goto out_unlock;
+ return work;
}
if (n->gro_bitmask) {
@@ -6375,12 +6370,29 @@ static int napi_poll(struct napi_struct
if (unlikely(!list_empty(&n->poll_list))) {
pr_warn_once("%s: Budget exhausted after napi rescheduled\n",
n->dev ? n->dev->name : "backlog");
- goto out_unlock;
+ return work;
}
- list_add_tail(&n->poll_list, repoll);
+ *repoll = true;
+
+ return work;
+}
+
+static int napi_poll(struct napi_struct *n, struct list_head *repoll)
+{
+ bool do_repoll = false;
+ void *have;
+ int work;
+
+ list_del_init(&n->poll_list);
+
+ have = netpoll_poll_lock(n);
+
+ work = __napi_poll(n, &do_repoll);
+
+ if (do_repoll)
+ list_add_tail(&n->poll_list, repoll);
-out_unlock:
netpoll_poll_unlock(have);
return work;

View File

@@ -0,0 +1,245 @@
From: Wei Wang <weiwan@google.com>
Date: Mon, 8 Feb 2021 11:34:09 -0800
Subject: [PATCH] net: implement threaded-able napi poll loop support
This patch allows running each napi poll loop inside its own
kernel thread.
The kthread is created during netif_napi_add() if dev->threaded
is set. And threaded mode is enabled in napi_enable(). We will
provide a way to set dev->threaded and enable threaded mode
without a device up/down in the following patch.
Once that threaded mode is enabled and the kthread is
started, napi_schedule() will wake-up such thread instead
of scheduling the softirq.
The threaded poll loop behaves quite likely the net_rx_action,
but it does not have to manipulate local irqs and uses
an explicit scheduling point based on netdev_budget.
Co-developed-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Co-developed-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Co-developed-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Wei Wang <weiwan@google.com>
Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -319,6 +319,7 @@ struct napi_struct {
struct list_head dev_list;
struct hlist_node napi_hash_node;
unsigned int napi_id;
+ struct task_struct *thread;
};
enum {
@@ -326,6 +327,7 @@ enum {
NAPI_STATE_DISABLE, /* Disable pending */
NAPI_STATE_NPSVC, /* Netpoll - don't dequeue from poll_list */
NAPI_STATE_HASHED, /* In NAPI hash */
+ NAPI_STATE_THREADED, /* The poll is performed inside its own thread*/
};
enum gro_result {
@@ -501,13 +503,7 @@ void napi_disable(struct napi_struct *n)
* Resume NAPI from being scheduled on this context.
* Must be paired with napi_disable.
*/
-static inline void napi_enable(struct napi_struct *n)
-{
- BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state));
- smp_mb__before_atomic();
- clear_bit(NAPI_STATE_SCHED, &n->state);
- clear_bit(NAPI_STATE_NPSVC, &n->state);
-}
+void napi_enable(struct napi_struct *n);
/**
* napi_synchronize - wait until NAPI is not running
@@ -1573,6 +1569,8 @@ enum netdev_priv_flags_ext {
* switch driver and used to set the phys state of the
* switch port.
*
+ * @threaded: napi threaded mode is enabled
+ *
* FIXME: cleanup struct net_device such that network protocol info
* moves out.
*/
@@ -1852,6 +1850,7 @@ struct net_device {
struct phy_device *phydev;
struct lock_class_key *qdisc_tx_busylock;
bool proto_down;
+ unsigned threaded:1;
};
#define to_net_dev(d) container_of(d, struct net_device, dev)
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -94,6 +94,7 @@
#include <linux/ethtool.h>
#include <linux/notifier.h>
#include <linux/skbuff.h>
+#include <linux/kthread.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <linux/rtnetlink.h>
@@ -1304,6 +1305,27 @@ void netdev_notify_peers(struct net_devi
}
EXPORT_SYMBOL(netdev_notify_peers);
+static int napi_threaded_poll(void *data);
+
+static int napi_kthread_create(struct napi_struct *n)
+{
+ int err = 0;
+
+ /* Create and wake up the kthread once to put it in
+ * TASK_INTERRUPTIBLE mode to avoid the blocked task
+ * warning and work with loadavg.
+ */
+ n->thread = kthread_run(napi_threaded_poll, n, "napi/%s-%d",
+ n->dev->name, n->napi_id);
+ if (IS_ERR(n->thread)) {
+ err = PTR_ERR(n->thread);
+ pr_err("kthread_run failed with err %d\n", err);
+ n->thread = NULL;
+ }
+
+ return err;
+}
+
static int __dev_open(struct net_device *dev)
{
const struct net_device_ops *ops = dev->netdev_ops;
@@ -3248,6 +3270,21 @@ int weight_p __read_mostly = 64;
static inline void ____napi_schedule(struct softnet_data *sd,
struct napi_struct *napi)
{
+ struct task_struct *thread;
+
+ if (test_bit(NAPI_STATE_THREADED, &napi->state)) {
+ /* Paired with smp_mb__before_atomic() in
+ * napi_enable(). Use READ_ONCE() to guarantee
+ * a complete read on napi->thread. Only call
+ * wake_up_process() when it's not NULL.
+ */
+ thread = READ_ONCE(napi->thread);
+ if (thread) {
+ wake_up_process(thread);
+ return;
+ }
+ }
+
list_add_tail(&napi->poll_list, &sd->poll_list);
__raise_softirq_irqoff(NET_RX_SOFTIRQ);
}
@@ -4828,9 +4865,33 @@ void netif_napi_add(struct net_device *d
napi->poll_owner = -1;
#endif
set_bit(NAPI_STATE_SCHED, &napi->state);
+ /* Create kthread for this napi if dev->threaded is set.
+ * Clear dev->threaded if kthread creation failed so that
+ * threaded mode will not be enabled in napi_enable().
+ */
+ if (dev->threaded && napi_kthread_create(napi))
+ dev->threaded = 0;
}
EXPORT_SYMBOL(netif_napi_add);
+/**
+ * napi_enable - enable NAPI scheduling
+ * @n: NAPI context
+ *
+ * Resume NAPI from being scheduled on this context.
+ * Must be paired with napi_disable.
+ */
+void napi_enable(struct napi_struct *n)
+{
+ BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state));
+ smp_mb__before_atomic();
+ clear_bit(NAPI_STATE_SCHED, &n->state);
+ clear_bit(NAPI_STATE_NPSVC, &n->state);
+ if (n->dev->threaded && n->thread)
+ set_bit(NAPI_STATE_THREADED, &n->state);
+}
+EXPORT_SYMBOL(napi_enable);
+
void napi_disable(struct napi_struct *n)
{
might_sleep();
@@ -4844,6 +4905,7 @@ void napi_disable(struct napi_struct *n)
hrtimer_cancel(&n->timer);
clear_bit(NAPI_STATE_DISABLE, &n->state);
+ clear_bit(NAPI_STATE_THREADED, &n->state);
}
EXPORT_SYMBOL(napi_disable);
@@ -4855,6 +4917,11 @@ void netif_napi_del(struct napi_struct *
kfree_skb_list(napi->gro_list);
napi->gro_list = NULL;
napi->gro_count = 0;
+
+ if (napi->thread) {
+ kthread_stop(napi->thread);
+ napi->thread = NULL;
+ }
}
EXPORT_SYMBOL(netif_napi_del);
@@ -4940,6 +5007,50 @@ static int napi_poll(struct napi_struct
return work;
}
+static int napi_thread_wait(struct napi_struct *napi)
+{
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ while (!kthread_should_stop() && !napi_disable_pending(napi)) {
+ if (test_bit(NAPI_STATE_SCHED, &napi->state)) {
+ WARN_ON(!list_empty(&napi->poll_list));
+ __set_current_state(TASK_RUNNING);
+ return 0;
+ }
+
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ __set_current_state(TASK_RUNNING);
+ return -1;
+}
+
+static int napi_threaded_poll(void *data)
+{
+ struct napi_struct *napi = data;
+ void *have;
+
+ while (!napi_thread_wait(napi)) {
+ for (;;) {
+ bool repoll = false;
+
+ local_bh_disable();
+
+ have = netpoll_poll_lock(napi);
+ __napi_poll(napi, &repoll);
+ netpoll_poll_unlock(have);
+
+ local_bh_enable();
+
+ if (!repoll)
+ break;
+
+ cond_resched();
+ }
+ }
+ return 0;
+}
+
static void net_rx_action(struct softirq_action *h)
{
struct softnet_data *sd = this_cpu_ptr(&softnet_data);

View File

@@ -0,0 +1,156 @@
From: Wei Wang <weiwan@google.com>
Date: Mon, 8 Feb 2021 11:34:10 -0800
Subject: [PATCH] net: add sysfs attribute to control napi threaded mode
This patch adds a new sysfs attribute to the network device class.
Said attribute provides a per-device control to enable/disable the
threaded mode for all the napi instances of the given network device,
without the need for a device up/down.
User sets it to 1 or 0 to enable or disable threaded mode.
Note: when switching between threaded and the current softirq based mode
for a napi instance, it will not immediately take effect if the napi is
currently being polled. The mode switch will happen for the next time
napi_schedule() is called.
Co-developed-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Co-developed-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Co-developed-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Wei Wang <weiwan@google.com>
Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -496,6 +496,8 @@ void napi_hash_del(struct napi_struct *n
*/
void napi_disable(struct napi_struct *n);
+int dev_set_threaded(struct net_device *dev, bool threaded);
+
/**
* napi_enable - enable NAPI scheduling
* @n: napi context
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3274,8 +3274,9 @@ static inline void ____napi_schedule(str
if (test_bit(NAPI_STATE_THREADED, &napi->state)) {
/* Paired with smp_mb__before_atomic() in
- * napi_enable(). Use READ_ONCE() to guarantee
- * a complete read on napi->thread. Only call
+ * napi_enable()/dev_set_threaded().
+ * Use READ_ONCE() to guarantee a complete
+ * read on napi->thread. Only call
* wake_up_process() when it's not NULL.
*/
thread = READ_ONCE(napi->thread);
@@ -4844,6 +4845,49 @@ static enum hrtimer_restart napi_watchdo
return HRTIMER_NORESTART;
}
+int dev_set_threaded(struct net_device *dev, bool threaded)
+{
+ struct napi_struct *napi;
+ int err = 0;
+
+ if (dev->threaded == threaded)
+ return 0;
+
+ if (threaded) {
+ list_for_each_entry(napi, &dev->napi_list, dev_list) {
+ if (!napi->thread) {
+ err = napi_kthread_create(napi);
+ if (err) {
+ threaded = false;
+ break;
+ }
+ }
+ }
+ }
+
+ dev->threaded = threaded;
+
+ /* Make sure kthread is created before THREADED bit
+ * is set.
+ */
+ smp_mb__before_atomic();
+
+ /* Setting/unsetting threaded mode on a napi might not immediately
+ * take effect, if the current napi instance is actively being
+ * polled. In this case, the switch between threaded mode and
+ * softirq mode will happen in the next round of napi_schedule().
+ * This should not cause hiccups/stalls to the live traffic.
+ */
+ list_for_each_entry(napi, &dev->napi_list, dev_list) {
+ if (threaded)
+ set_bit(NAPI_STATE_THREADED, &napi->state);
+ else
+ clear_bit(NAPI_STATE_THREADED, &napi->state);
+ }
+
+ return err;
+}
+
void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
int (*poll)(struct napi_struct *, int), int weight)
{
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -486,6 +486,45 @@ static ssize_t phys_switch_id_show(struc
}
static DEVICE_ATTR_RO(phys_switch_id);
+static ssize_t threaded_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ ssize_t ret = -EINVAL;
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ if (dev_isalive(netdev))
+ ret = sprintf(buf, fmt_dec, netdev->threaded);
+
+ rtnl_unlock();
+ return ret;
+}
+
+static int modify_napi_threaded(struct net_device *dev, unsigned long val)
+{
+ int ret;
+
+ if (list_empty(&dev->napi_list))
+ return -EOPNOTSUPP;
+
+ if (val != 0 && val != 1)
+ return -EOPNOTSUPP;
+
+ ret = dev_set_threaded(dev, val);
+
+ return ret;
+}
+
+static ssize_t threaded_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return netdev_store(dev, attr, buf, len, modify_napi_threaded);
+}
+static DEVICE_ATTR_RW(threaded);
+
static struct attribute *net_class_attrs[] = {
&dev_attr_netdev_group.attr,
&dev_attr_type.attr,
@@ -514,6 +553,7 @@ static struct attribute *net_class_attrs
&dev_attr_phys_port_name.attr,
&dev_attr_phys_switch_id.attr,
&dev_attr_proto_down.attr,
+ &dev_attr_threaded.attr,
NULL,
};
ATTRIBUTE_GROUPS(net_class);

View File

@@ -0,0 +1,118 @@
From: Wei Wang <weiwan@google.com>
Date: Mon, 1 Mar 2021 17:21:13 -0800
Subject: [PATCH] net: fix race between napi kthread mode and busy poll
Currently, napi_thread_wait() checks for NAPI_STATE_SCHED bit to
determine if the kthread owns this napi and could call napi->poll() on
it. However, if socket busy poll is enabled, it is possible that the
busy poll thread grabs this SCHED bit (after the previous napi->poll()
invokes napi_complete_done() and clears SCHED bit) and tries to poll
on the same napi. napi_disable() could grab the SCHED bit as well.
This patch tries to fix this race by adding a new bit
NAPI_STATE_SCHED_THREADED in napi->state. This bit gets set in
____napi_schedule() if the threaded mode is enabled, and gets cleared
in napi_complete_done(), and we only poll the napi in kthread if this
bit is set. This helps distinguish the ownership of the napi between
kthread and other scenarios and fixes the race issue.
Fixes: 29863d41bb6e ("net: implement threaded-able napi poll loop support")
Reported-by: Martin Zaharinov <micron10@gmail.com>
Suggested-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Wei Wang <weiwan@google.com>
Cc: Alexander Duyck <alexanderduyck@fb.com>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -328,6 +328,7 @@ enum {
NAPI_STATE_NPSVC, /* Netpoll - don't dequeue from poll_list */
NAPI_STATE_HASHED, /* In NAPI hash */
NAPI_STATE_THREADED, /* The poll is performed inside its own thread*/
+ NAPI_STATE_SCHED_THREADED, /* Napi is currently scheduled in threaded mode */
};
enum gro_result {
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3281,6 +3281,8 @@ static inline void ____napi_schedule(str
*/
thread = READ_ONCE(napi->thread);
if (thread) {
+ if (thread->state != TASK_INTERRUPTIBLE)
+ set_bit(NAPI_STATE_SCHED_THREADED, &napi->state);
wake_up_process(thread);
return;
}
@@ -4745,12 +4747,14 @@ void __napi_complete(struct napi_struct
list_del_init(&n->poll_list);
smp_mb__before_atomic();
clear_bit(NAPI_STATE_SCHED, &n->state);
+ clear_bit(NAPI_STATE_SCHED_THREADED, &n->state);
}
EXPORT_SYMBOL(__napi_complete);
void napi_complete_done(struct napi_struct *n, int work_done)
{
unsigned long flags;
+ unsigned long val, new;
/*
* don't let napi dequeue from the cpu poll list
@@ -4771,14 +4775,19 @@ void napi_complete_done(struct napi_stru
else
napi_gro_flush(n, false);
}
- if (likely(list_empty(&n->poll_list))) {
- WARN_ON_ONCE(!test_and_clear_bit(NAPI_STATE_SCHED, &n->state));
- } else {
- /* If n->poll_list is not empty, we need to mask irqs */
- local_irq_save(flags);
- __napi_complete(n);
- local_irq_restore(flags);
- }
+
+ /* If n->poll_list is not empty, we need to mask irqs */
+ local_irq_save(flags);
+ list_del_init(&n->poll_list);
+ local_irq_restore(flags);
+
+ do {
+ val = READ_ONCE(n->state);
+
+ WARN_ON_ONCE(!(val & BIT(NAPI_STATE_SCHED)));
+ new = val & ~(BIT(NAPI_STATE_SCHED) |
+ BIT(NAPI_STATE_SCHED_THREADED));
+ } while (cmpxchg(&n->state, val, new) != val);
}
EXPORT_SYMBOL(napi_complete_done);
@@ -5053,16 +5062,25 @@ static int napi_poll(struct napi_struct
static int napi_thread_wait(struct napi_struct *napi)
{
+ bool woken = false;
+
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop() && !napi_disable_pending(napi)) {
- if (test_bit(NAPI_STATE_SCHED, &napi->state)) {
+ /* Testing SCHED_THREADED bit here to make sure the current
+ * kthread owns this napi and could poll on this napi.
+ * Testing SCHED bit is not enough because SCHED bit might be
+ * set by some other busy poll thread or by napi_disable().
+ */
+ if (test_bit(NAPI_STATE_SCHED_THREADED, &napi->state) || woken) {
WARN_ON(!list_empty(&napi->poll_list));
__set_current_state(TASK_RUNNING);
return 0;
}
schedule();
+ /* woken being true indicates this thread owns this napi. */
+ woken = true;
set_current_state(TASK_INTERRUPTIBLE);
}
__set_current_state(TASK_RUNNING);

View File

@@ -0,0 +1,53 @@
From: Paolo Abeni <pabeni@redhat.com>
Date: Fri, 9 Apr 2021 17:24:17 +0200
Subject: [PATCH] net: fix hangup on napi_disable for threaded napi
napi_disable() is subject to an hangup, when the threaded
mode is enabled and the napi is under heavy traffic.
If the relevant napi has been scheduled and the napi_disable()
kicks in before the next napi_threaded_wait() completes - so
that the latter quits due to the napi_disable_pending() condition,
the existing code leaves the NAPI_STATE_SCHED bit set and the
napi_disable() loop waiting for such bit will hang.
This patch addresses the issue by dropping the NAPI_STATE_DISABLE
bit test in napi_thread_wait(). The later napi_threaded_poll()
iteration will take care of clearing the NAPI_STATE_SCHED.
This also addresses a related problem reported by Jakub:
before this patch a napi_disable()/napi_enable() pair killed
the napi thread, effectively disabling the threaded mode.
On the patched kernel napi_disable() simply stops scheduling
the relevant thread.
v1 -> v2:
- let the main napi_thread_poll() loop clear the SCHED bit
Reported-by: Jakub Kicinski <kuba@kernel.org>
Fixes: 29863d41bb6e ("net: implement threaded-able napi poll loop support")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/883923fa22745a9589e8610962b7dc59df09fb1f.1617981844.git.pabeni@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5066,7 +5066,7 @@ static int napi_thread_wait(struct napi_
set_current_state(TASK_INTERRUPTIBLE);
- while (!kthread_should_stop() && !napi_disable_pending(napi)) {
+ while (!kthread_should_stop()) {
/* Testing SCHED_THREADED bit here to make sure the current
* kthread owns this napi and could poll on this napi.
* Testing SCHED bit is not enough because SCHED bit might be
@@ -5084,6 +5084,7 @@ static int napi_thread_wait(struct napi_
set_current_state(TASK_INTERRUPTIBLE);
}
__set_current_state(TASK_RUNNING);
+
return -1;
}

View File

@@ -0,0 +1,439 @@
From: Daniel Borkmann <daniel@iogearbox.net>
Date: Thu, 7 Jan 2016 22:29:47 +0100
Subject: [PATCH] net, sched: add clsact qdisc
This work adds a generalization of the ingress qdisc as a qdisc holding
only classifiers. The clsact qdisc works on ingress, but also on egress.
In both cases, it's execution happens without taking the qdisc lock, and
the main difference for the egress part compared to prior version of [1]
is that this can be applied with _any_ underlying real egress qdisc (also
classless ones).
Besides solving the use-case of [1], that is, allowing for more programmability
on assigning skb->priority for the mqprio case that is supported by most
popular 10G+ NICs, it also opens up a lot more flexibility for other tc
applications. The main work on classification can already be done at clsact
egress time if the use-case allows and state stored for later retrieval
f.e. again in skb->priority with major/minors (which is checked by most
classful qdiscs before consulting tc_classify()) and/or in other skb fields
like skb->tc_index for some light-weight post-processing to get to the
eventual classid in case of a classful qdisc. Another use case is that
the clsact egress part allows to have a central egress counterpart to
the ingress classifiers, so that classifiers can easily share state (e.g.
in cls_bpf via eBPF maps) for ingress and egress.
Currently, default setups like mq + pfifo_fast would require for this to
use, for example, prio qdisc instead (to get a tc_classify() run) and to
duplicate the egress classifier for each queue. With clsact, it allows
for leaving the setup as is, it can additionally assign skb->priority to
put the skb in one of pfifo_fast's bands and it can share state with maps.
Moreover, we can access the skb's dst entry (f.e. to retrieve tclassid)
w/o the need to perform a skb_dst_force() to hold on to it any longer. In
lwt case, we can also use this facility to setup dst metadata via cls_bpf
(bpf_skb_set_tunnel_key()) without needing a real egress qdisc just for
that (case of IFF_NO_QUEUE devices, for example).
The realization can be done without any changes to the scheduler core
framework. All it takes is that we have two a-priori defined minors/child
classes, where we can mux between ingress and egress classifier list
(dev->ingress_cl_list and dev->egress_cl_list, latter stored close to
dev->_tx to avoid extra cacheline miss for moderate loads). The egress
part is a bit similar modelled to handle_ing() and patched to a noop in
case the functionality is not used. Both handlers are now called
sch_handle_ingress() and sch_handle_egress(), code sharing among the two
doesn't seem practical as there are various minor differences in both
paths, so that making them conditional in a single handler would rather
slow things down.
Full compatibility to ingress qdisc is provided as well. Since both
piggyback on TC_H_CLSACT, only one of them (ingress/clsact) can exist
per netdevice, and thus ingress qdisc specific behaviour can be retained
for user space. This means, either a user does 'tc qdisc add dev foo ingress'
and configures ingress qdisc as usual, or the 'tc qdisc add dev foo clsact'
alternative, where both, ingress and egress classifier can be configured
as in the below example. ingress qdisc supports attaching classifier to any
minor number whereas clsact has two fixed minors for muxing between the
lists, therefore to not break user space setups, they are better done as
two separate qdiscs.
I decided to extend the sch_ingress module with clsact functionality so
that commonly used code can be reused, the module is being aliased with
sch_clsact so that it can be auto-loaded properly. Alternative would have been
to add a flag when initializing ingress to alter its behaviour plus aliasing
to a different name (as it's more than just ingress). However, the first would
end up, based on the flag, choosing the new/old behaviour by calling different
function implementations to handle each anyway, the latter would require to
register ingress qdisc once again under different alias. So, this really begs
to provide a minimal, cleaner approach to have Qdisc_ops and Qdisc_class_ops
by its own that share callbacks used by both.
Example, adding qdisc:
# tc qdisc add dev foo clsact
# tc qdisc show dev foo
qdisc mq 0: root
qdisc pfifo_fast 0: parent :1 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: parent :2 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: parent :3 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: parent :4 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc clsact ffff: parent ffff:fff1
Adding filters (deleting, etc works analogous by specifying ingress/egress):
# tc filter add dev foo ingress bpf da obj bar.o sec ingress
# tc filter add dev foo egress bpf da obj bar.o sec egress
# tc filter show dev foo ingress
filter protocol all pref 49152 bpf
filter protocol all pref 49152 bpf handle 0x1 bar.o:[ingress] direct-action
# tc filter show dev foo egress
filter protocol all pref 49152 bpf
filter protocol all pref 49152 bpf handle 0x1 bar.o:[egress] direct-action
A 'tc filter show dev foo' or 'tc filter show dev foo parent ffff:' will
show an empty list for clsact. Either using the parent names (ingress/egress)
or specifying the full major/minor will then show the related filter lists.
Prior work on a mqprio prequeue() facility [1] was done mainly by John Fastabend.
[1] http://patchwork.ozlabs.org/patch/512949/
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1770,7 +1770,9 @@ struct net_device {
#ifdef CONFIG_XPS
struct xps_dev_maps __rcu *xps_maps;
#endif
-
+#ifdef CONFIG_NET_CLS_ACT
+ struct tcf_proto __rcu *egress_cl_list;
+#endif
#ifdef CONFIG_NET_SWITCHDEV
u32 offload_fwd_mark;
#endif
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -84,6 +84,11 @@ void net_inc_ingress_queue(void);
void net_dec_ingress_queue(void);
#endif
+#ifdef CONFIG_NET_EGRESS
+void net_inc_egress_queue(void);
+void net_dec_egress_queue(void);
+#endif
+
extern void rtnetlink_init(void);
extern void __rtnl_unlock(void);
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -72,6 +72,10 @@ struct tc_estimator {
#define TC_H_UNSPEC (0U)
#define TC_H_ROOT (0xFFFFFFFFU)
#define TC_H_INGRESS (0xFFFFFFF1U)
+#define TC_H_CLSACT TC_H_INGRESS
+
+#define TC_H_MIN_INGRESS 0xFFF2U
+#define TC_H_MIN_EGRESS 0xFFF3U
/* Need to corrospond to iproute2 tc/tc_core.h "enum link_layer" */
enum tc_link_layer {
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1697,6 +1697,22 @@ void net_dec_ingress_queue(void)
EXPORT_SYMBOL_GPL(net_dec_ingress_queue);
#endif
+#ifdef CONFIG_NET_EGRESS
+static struct static_key egress_needed __read_mostly;
+
+void net_inc_egress_queue(void)
+{
+ static_key_slow_inc(&egress_needed);
+}
+EXPORT_SYMBOL_GPL(net_inc_egress_queue);
+
+void net_dec_egress_queue(void)
+{
+ static_key_slow_dec(&egress_needed);
+}
+EXPORT_SYMBOL_GPL(net_dec_egress_queue);
+#endif
+
static struct static_key netstamp_needed __read_mostly;
#ifdef HAVE_JUMP_LABEL
static atomic_t netstamp_needed_deferred;
@@ -2936,7 +2952,6 @@ static inline int __dev_xmit_skb(struct
bool contended;
int rc;
- qdisc_pkt_len_init(skb);
qdisc_calculate_pkt_len(skb, q);
/*
* Heuristic to force contended enqueues to serialize on a
@@ -3028,6 +3043,49 @@ int dev_loopback_xmit(struct net *net, s
}
EXPORT_SYMBOL(dev_loopback_xmit);
+#ifdef CONFIG_NET_EGRESS
+static struct sk_buff *
+sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)
+{
+ struct tcf_proto *cl = rcu_dereference_bh(dev->egress_cl_list);
+ struct tcf_result cl_res;
+
+ if (!cl)
+ return skb;
+
+ /* skb->tc_verd and qdisc_skb_cb(skb)->pkt_len were already set
+ * earlier by the caller.
+ */
+ qdisc_bstats_cpu_update(cl->q, skb);
+
+ switch (tc_classify(skb, cl, &cl_res, false)) {
+ case TC_ACT_OK:
+ case TC_ACT_RECLASSIFY:
+ skb->tc_index = TC_H_MIN(cl_res.classid);
+ break;
+ case TC_ACT_SHOT:
+ qdisc_qstats_cpu_drop(cl->q);
+ *ret = NET_XMIT_DROP;
+ goto drop;
+ case TC_ACT_STOLEN:
+ case TC_ACT_QUEUED:
+ *ret = NET_XMIT_SUCCESS;
+drop:
+ kfree_skb(skb);
+ return NULL;
+ case TC_ACT_REDIRECT:
+ /* No need to push/pop skb's mac_header here on egress! */
+ skb_do_redirect(skb);
+ *ret = NET_XMIT_SUCCESS;
+ return NULL;
+ default:
+ break;
+ }
+
+ return skb;
+}
+#endif /* CONFIG_NET_EGRESS */
+
static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
{
#ifdef CONFIG_XPS
@@ -3152,6 +3210,17 @@ static int __dev_queue_xmit(struct sk_bu
skb_update_prio(skb);
+ qdisc_pkt_len_init(skb);
+#ifdef CONFIG_NET_CLS_ACT
+ skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS);
+# ifdef CONFIG_NET_EGRESS
+ if (static_key_false(&egress_needed)) {
+ skb = sch_handle_egress(skb, &rc, dev);
+ if (!skb)
+ goto out;
+ }
+# endif
+#endif
/* If device/qdisc don't need skb->dst, release it right now while
* its hot in this cpu cache.
*/
@@ -3173,9 +3242,6 @@ static int __dev_queue_xmit(struct sk_bu
txq = netdev_pick_tx(dev, skb, accel_priv);
q = rcu_dereference_bh(txq->qdisc);
-#ifdef CONFIG_NET_CLS_ACT
- skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS);
-#endif
trace_net_dev_queue(skb);
if (q->enqueue) {
rc = __dev_xmit_skb(skb, q, dev, txq);
@@ -3750,9 +3816,9 @@ int (*br_fdb_test_addr_hook)(struct net_
EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook);
#endif
-static inline struct sk_buff *handle_ing(struct sk_buff *skb,
- struct packet_type **pt_prev,
- int *ret, struct net_device *orig_dev)
+static inline struct sk_buff *
+sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,
+ struct net_device *orig_dev)
{
#ifdef CONFIG_NET_CLS_ACT
struct tcf_proto *cl = rcu_dereference_bh(skb->dev->ingress_cl_list);
@@ -3974,7 +4040,7 @@ another_round:
skip_taps:
#ifdef CONFIG_NET_INGRESS
if (static_key_false(&ingress_needed)) {
- skb = handle_ing(skb, &pt_prev, &ret, orig_dev);
+ skb = sch_handle_ingress(skb, &pt_prev, &ret, orig_dev);
if (!skb)
goto out;
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -54,6 +54,9 @@ config COMPAT_NETLINK_MESSAGES
config NET_INGRESS
bool
+config NET_EGRESS
+ bool
+
menu "Networking options"
source "net/packet/Kconfig"
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -291,7 +291,7 @@ static int cls_bpf_prog_from_efd(struct
prog->bpf_name = name;
prog->filter = fp;
- if (fp->dst_needed)
+ if (fp->dst_needed && !(tp->q->flags & TCQ_F_INGRESS))
netif_keep_dst(qdisc_dev(tp->q));
return 0;
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -342,15 +342,21 @@ config NET_SCH_PIE
If unsure, say N.
config NET_SCH_INGRESS
- tristate "Ingress Qdisc"
+ tristate "Ingress/classifier-action Qdisc"
depends on NET_CLS_ACT
select NET_INGRESS
+ select NET_EGRESS
---help---
- Say Y here if you want to use classifiers for incoming packets.
+ Say Y here if you want to use classifiers for incoming and/or outgoing
+ packets. This qdisc doesn't do anything else besides running classifiers,
+ which can also have actions attached to them. In case of outgoing packets,
+ classifiers that this qdisc holds are executed in the transmit path
+ before real enqueuing to an egress qdisc happens.
+
If unsure, say Y.
- To compile this code as a module, choose M here: the
- module will be called sch_ingress.
+ To compile this code as a module, choose M here: the module will be
+ called sch_ingress with alias of sch_clsact.
config NET_SCH_PLUG
tristate "Plug network traffic until release (PLUG)"
--- a/net/sched/sch_ingress.c
+++ b/net/sched/sch_ingress.c
@@ -1,4 +1,5 @@
-/* net/sched/sch_ingress.c - Ingress qdisc
+/* net/sched/sch_ingress.c - Ingress and clsact qdisc
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -98,17 +99,100 @@ static struct Qdisc_ops ingress_qdisc_op
.owner = THIS_MODULE,
};
+static unsigned long clsact_get(struct Qdisc *sch, u32 classid)
+{
+ switch (TC_H_MIN(classid)) {
+ case TC_H_MIN(TC_H_MIN_INGRESS):
+ case TC_H_MIN(TC_H_MIN_EGRESS):
+ return TC_H_MIN(classid);
+ default:
+ return 0;
+ }
+}
+
+static unsigned long clsact_bind_filter(struct Qdisc *sch,
+ unsigned long parent, u32 classid)
+{
+ return clsact_get(sch, classid);
+}
+
+static struct tcf_proto __rcu **clsact_find_tcf(struct Qdisc *sch,
+ unsigned long cl)
+{
+ struct net_device *dev = qdisc_dev(sch);
+
+ switch (cl) {
+ case TC_H_MIN(TC_H_MIN_INGRESS):
+ return &dev->ingress_cl_list;
+ case TC_H_MIN(TC_H_MIN_EGRESS):
+ return &dev->egress_cl_list;
+ default:
+ return NULL;
+ }
+}
+
+static int clsact_init(struct Qdisc *sch, struct nlattr *opt)
+{
+ net_inc_ingress_queue();
+ net_inc_egress_queue();
+
+ sch->flags |= TCQ_F_CPUSTATS;
+
+ return 0;
+}
+
+static void clsact_destroy(struct Qdisc *sch)
+{
+ struct net_device *dev = qdisc_dev(sch);
+
+ tcf_destroy_chain(&dev->ingress_cl_list);
+ tcf_destroy_chain(&dev->egress_cl_list);
+
+ net_dec_ingress_queue();
+ net_dec_egress_queue();
+}
+
+static const struct Qdisc_class_ops clsact_class_ops = {
+ .leaf = ingress_leaf,
+ .get = clsact_get,
+ .put = ingress_put,
+ .walk = ingress_walk,
+ .tcf_chain = clsact_find_tcf,
+ .bind_tcf = clsact_bind_filter,
+ .unbind_tcf = ingress_put,
+};
+
+static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
+ .cl_ops = &clsact_class_ops,
+ .id = "clsact",
+ .init = clsact_init,
+ .destroy = clsact_destroy,
+ .dump = ingress_dump,
+ .owner = THIS_MODULE,
+};
+
static int __init ingress_module_init(void)
{
- return register_qdisc(&ingress_qdisc_ops);
+ int ret;
+
+ ret = register_qdisc(&ingress_qdisc_ops);
+ if (!ret) {
+ ret = register_qdisc(&clsact_qdisc_ops);
+ if (ret)
+ unregister_qdisc(&ingress_qdisc_ops);
+ }
+
+ return ret;
}
static void __exit ingress_module_exit(void)
{
unregister_qdisc(&ingress_qdisc_ops);
+ unregister_qdisc(&clsact_qdisc_ops);
}
module_init(ingress_module_init);
module_exit(ingress_module_exit);
+MODULE_ALIAS("sch_clsact");
MODULE_LICENSE("GPL");

View File

@@ -13,6 +13,7 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/dtaht/sch_cake.git
PKG_MIRROR_HASH:=8bb4fa43368be5b5839a350419701b0bb3881b1641e037affea42630d75e56e6
PKG_SOURCE_DATE:=2021-07-09
PKG_SOURCE_VERSION:=d9e1398cc9091e9e7c7a740361e4617b75c24427
#PKG_MIRROR_HASH:=5bf06a804824db36ae393fc174aeec7b12633176e05a765c0931b39df5bd34df

View File

@@ -1,67 +0,0 @@
#
# Copyright (C) 2011 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=libprotobuf-c
PKG_VERSION:=1.3.1
PKG_RELEASE:=2
PKG_SOURCE:=protobuf-c-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/protobuf-c/protobuf-c/releases/download/v$(PKG_VERSION)
PKG_HASH:=51472d3a191d6d7b425e32b612e477c06f73fe23e07f6a6a839b11808e9d2267
PKG_BUILD_DIR:=$(BUILD_DIR)/protobuf-c-$(PKG_VERSION)
HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/protobuf-c-$(PKG_VERSION)
PKG_MAINTAINER:=Rosen Penev <rosenp@gmail.com>
PKG_LICENSE:=BSD-2c
PKG_BUILD_DEPENDS:=protobuf-c/host
HOST_BUILD_DEPENDS:=protobuf/host
PKG_INSTALL:=1
PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/host-build.mk
define Package/libprotobuf-c
TITLE:=Protocol Buffers library
SECTION:=libs
CATEGORY:=Libraries
URL:=https://github.com/protobuf-c/protobuf-c
endef
define Package/libprotobuf-c/description
Runtime library to use Google Protocol Buffers from C applications.
Protocol Buffers are a way of encoding structured data in an efficient yet
extensible format. Google uses Protocol Buffers for almost all of its
internal RPC protocols and file formats.
endef
CONFIGURE_ARGS += \
--enable-shared \
--enable-static \
--disable-protoc
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/include/
$(CP) $(PKG_INSTALL_DIR)/usr/include/* $(1)/usr/include/
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libprotobuf-c.{a,la,so*} $(1)/usr/lib/
$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/* $(1)/usr/lib/pkgconfig/
endef
define Package/libprotobuf-c/install
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libprotobuf-c.so.* $(1)/usr/lib/
endef
$(eval $(call BuildPackage,libprotobuf-c))
$(eval $(call HostBuild))

View File

@@ -1,13 +0,0 @@
Index: protobuf-c-1.3.1/t/generated-code2/cxx-generate-packed-data.cc
===================================================================
--- protobuf-c-1.3.1.orig/t/generated-code2/cxx-generate-packed-data.cc
+++ protobuf-c-1.3.1/t/generated-code2/cxx-generate-packed-data.cc
@@ -998,7 +998,7 @@ static void dump_test_packed_repeated_en
static void dump_test_unknown_fields (void)
{
EmptyMess mess;
- const google::protobuf::Message::Reflection *reflection = mess.GetReflection();
+ const google::protobuf::Reflection *reflection = mess.GetReflection();
google::protobuf::UnknownFieldSet *fs = reflection->MutableUnknownFields(&mess);
#if GOOGLE_PROTOBUF_VERSION >= 2001000

View File

@@ -1,110 +0,0 @@
#
# Copyright (C) 2007-2015 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=protobuf
PKG_VERSION:=3.7.1
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-cpp-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/google/protobuf/releases/download/v$(PKG_VERSION)
PKG_HASH:=97f6cdaa0724d5a8cd3375d5f5cf4bd253d5ad5291154f533ed0d94a9d501ef3
PKG_LICENSE:=BSD-3-Clause
PKG_LICENSE_FILES:=LICENSE
PKG_CPE_ID:=cpe:/a:google:protobuf
PKG_BUILD_DEPENDS:=protobuf/host
PKG_BUILD_PARALLEL:=1
PKG_INSTALL:=1
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/host-build.mk
define Package/protobuf/Default
SECTION:=libs
CATEGORY:=Libraries
TITLE:=A structured data encoding library
URL:=https://github.com/google/protobuf
DEPENDS:=+zlib +libpthread +libatomic +libstdcpp
MAINTAINER:=Ken Keys <kkeys@caida.org>
endef
define Package/protobuf
$(call Package/protobuf/Default)
DEPENDS+=+protobuf-lite
endef
define Package/protobuf-lite
$(call Package/protobuf/Default)
endef
define Package/protobuf/description/Default
Protocol Buffers are a way of encoding structured data in an efficient
yet extensible format. Google uses Protocol Buffers for almost all
of its internal RPC protocols and file formats.
endef
define Package/protobuf/description
$(call Package/protobuf/description/Default)
This package provides the libprotoc, libprotobuf, and libprotobuf-lite
libraries. For a much smaller protobuf package, see "protobuf-lite".
endef
define Package/protobuf-lite/description
$(call Package/protobuf/description/Default)
This package provides the libprotobuf-lite library.
endef
EXTRA_CPPFLAGS+=-std=c++11
CONFIGURE_ARGS += --with-protoc=$(STAGING_DIR_HOSTPKG)/bin/protoc
define Build/InstallDev
$(INSTALL_DIR) \
$(1)/usr/lib \
$(1)/usr/include
$(CP) \
$(PKG_INSTALL_DIR)/usr/include/* \
$(1)/usr/include/
$(CP) \
$(PKG_INSTALL_DIR)/usr/lib/* \
$(1)/usr/lib/
endef
define Package/protobuf-lite/install
$(INSTALL_DIR) \
$(1)/usr/lib
$(CP) \
$(PKG_INSTALL_DIR)/usr/lib/libprotobuf-lite.so* \
$(1)/usr/lib/
endef
define Package/protobuf/install
$(INSTALL_DIR) \
$(1)/usr/lib
$(CP) \
$(PKG_INSTALL_DIR)/usr/lib/libprotoc.so* \
$(1)/usr/lib/
$(CP) \
$(PKG_INSTALL_DIR)/usr/lib/libprotobuf.so* \
$(1)/usr/lib/
endef
$(eval $(call BuildPackage,protobuf))
$(eval $(call BuildPackage,protobuf-lite))
$(eval $(call HostBuild))

View File

@@ -6,6 +6,7 @@ PKG_SOURCE_PROTO:=git
PKG_BRANCH:=master
PKG_RELEASE:=2
PKG_SOURCE_URL:=https://source.codeaurora.org/quic/qsdk/oss/lklm/nss-clients/
PKG_MIRROR_HASH:=802bf8b2dac8da0549e108b873afd982d127370c07d6574ece71f902eafe7698
PKG_VERSION:=153998d70fdba508a59a28c13a606032cbf32686
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz

View File

@@ -0,0 +1,11 @@
--- a/nss_hal/nss_hal.c
+++ b/nss_hal/nss_hal.c
@@ -306,6 +306,8 @@ int nss_hal_probe(struct platform_device
* Initialize the dummy netdevice.
*/
init_dummy_netdev(&nss_ctx->napi_ndev);
+ strcpy(nss_ctx->napi_ndev.name, "nss");
+ nss_ctx->napi_ndev.threaded = 1;
for (i = 0; i < npd->num_irq; i++) {
err = nss_hal_register_irq(nss_ctx, npd, &nss_ctx->napi_ndev, i);

View File

@@ -8,7 +8,7 @@ generate_certificate_volume() {
ubinfo /dev/ubi0 -N certificates > /dev/null
[ $? -eq 0 ] || {
ubirsvol /dev/ubi0 -N rootfs_data -s 20MiB
ubimkvol /dev/ubi0 -N certificates -s 2MiB
ubimkvol /dev/ubi0 -N certificates -S 20
}
}

View File

@@ -16,12 +16,14 @@ wifi config
. /lib/functions.sh
SUFFIX=$(uci get system.@system[0].hostname | tail -c 7 | tr a-f A-F | tr -d '\n')
radio_enable() {
uci set wireless.$1.disabled=0
}
ssid_set() {
uci set wireless.$1.ssid='Maverick'
uci set wireless.$1.ssid=Maverick-${SUFFIX}
}
delete_forwarding() {

View File

@@ -4,6 +4,7 @@ PKG_NAME:=dynamic-vlan
PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/blogic/dynamic-vlan.git
PKG_MIRROR_HASH:=448890cdf182bd1b47edffca242e607594d0d17f6f5017a6fd021aab79f3c351
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2021-06-04
PKG_SOURCE_VERSION:=55d78d3e7215b601084980d922349bcfdcf9cf20

View File

@@ -7,6 +7,7 @@ PKG_LICENSE:=GPL-2.0
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_SOURCE_URL=https://github.com/blogic/ieee8021x.git
PKG_MIRROR_HASH:=7e14e320714b4759f5c393f90165a69d133633612b57d408b3ab6535710bf53c
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2021-04-12
PKG_SOURCE_VERSION:=c1f36559dc0ed2deeac0531a3d5854f1955ae928

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2008-2012 OpenWrt.org
# Copyright (C) 2021 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
@@ -9,26 +9,31 @@ include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=qosify
PKG_RELEASE:=1
PKG_SOURCE_URL=$(PROJECT_GIT)/project/qosify.git
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2022-03-06
PKG_SOURCE_VERSION:=f13b67c9a786567df240a8f3f608e2724ddaadba
PKG_MIRROR_HASH:=3d8629e711e46a6be79a46a6394165fd1761687f24b8ed954dc4f16f177cd90f
PKG_RELEASE:=$(AUTORELEASE)
PKG_LICENSE:=GPL-2.0
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_BUILD_DEPENDS:=bpf-headers
PKG_FLAGS:=nonshared
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
include $(INCLUDE_DIR)/bpf.mk
include $(INCLUDE_DIR)/nls.mk
define Package/qosify
SECTION:=kernel
CATEGORY:=Kernel modules
SUBMENU:=Network Support
TITLE:=QoS classifier eBPF module
DEPENDS:=+libbpf +libubox +libubus +kmod-sched-cake +tc-full
PKGFLAGS+=nonshared
SECTION:=utils
CATEGORY:=Base system
TITLE:=A simple QoS solution based eBPF + CAKE
DEPENDS:=+libbpf +libubox +libubus +kmod-sched-cake +kmod-sched-bpf +kmod-ifb +tc-full $(BPF_DEPENDS)
endef
BPF_DOC = $(wildcard $(patsubst %,$(BPF_HEADERS_DIR)/scripts/%.py,bpf_doc bpf_helpers_doc))
define Build/Compile
$(call CompileBPF,$(PKG_BUILD_DIR)/qosify-bpf.c)
$(Build/Compile/Default)
@@ -36,17 +41,28 @@ endef
define Package/qosify/conffiles
/etc/config/qosify
/etc/qosify-defaults.conf
/etc/qosify/00-defaults.conf
endef
define Package/qosify/install
$(INSTALL_DIR) $(1)/lib/bpf $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/config $(1)/etc/hotplug.d/net
$(INSTALL_DIR) \
$(1)/lib/bpf \
$(1)/usr/sbin \
$(1)/etc/init.d \
$(1)/etc/config \
$(1)/etc/qosify \
$(1)/etc/hotplug.d/net \
$(1)/etc/hotplug.d/iface
$(INSTALL_DATA) $(PKG_BUILD_DIR)/qosify-bpf.o $(1)/lib/bpf
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/qosify $(1)/usr/sbin/
$(INSTALL_BIN) \
$(PKG_INSTALL_DIR)/usr/bin/qosify \
./files/qosify-status \
$(1)/usr/sbin/
$(INSTALL_BIN) ./files/qosify.init $(1)/etc/init.d/qosify
$(INSTALL_DATA) ./files/qosify-defaults.conf $(1)/etc/qosify-defaults.conf
$(INSTALL_DATA) ./files/qosify-defaults.conf $(1)/etc/qosify/00-defaults.conf
$(INSTALL_DATA) ./files/qosify.conf $(1)/etc/config/qosify
$(INSTALL_DATA) ./files/qosify.hotplug $(1)/etc/hotplug.d/net/10-qosify
$(INSTALL_DATA) ./files/qosify.hotplug $(1)/etc/hotplug.d/iface/10-qosify
endef
$(eval $(call BuildPackage,qosify))

View File

@@ -1,17 +1,17 @@
# DNS
tcp:53 CS5
tcp:5353 CS5
udp:53 CS5
udp:5353 CS5
tcp:53 voice
tcp:5353 voice
udp:53 voice
udp:5353 voice
# NTP
udp:123 CS6
udp:123 voice
# SSH
tcp:22 +CS4
tcp:22 +video
# HTTP/QUIC
tcp:80 +CS3
tcp:443 +CS3
udp:80 +CS3
udp:443 +CS3
tcp:80 +besteffort
tcp:443 +besteffort
udp:80 +besteffort
udp:443 +besteffort

View File

@@ -0,0 +1,70 @@
#!/bin/sh
. /usr/share/libubox/jshn.sh
dev_status() {
tc -s qdisc sh dev "$1" root
echo
}
common_status() {
json_get_vars ifname ingress egress
[ -n "$ifname" ] || return
[ "$egress" -gt 0 ] && {
echo "egress status:"
dev_status "$ifname"
}
[ "$ingress" -gt 0 ] && {
echo "ingress status:"
dev_status "$(printf %.16s "ifb-$ifname")"
}
}
is_active() {
json_get_vars active
[ "${active:-0}" -gt 0 ]
}
device_status() {
local name="$2"
json_select "$name"
if is_active; then
status="active"
else
status="not found"
fi
echo "===== device $name: $status ====="
is_active && common_status
json_select ..
}
interface_status() {
local name="$2"
json_select "$name"
if is_active; then
status="active"
elif ubus -S -t 0 wait_for "network.interface.$name"; then
status="down"
else
status="not found"
fi
echo "===== interface $name: $status ====="
is_active && common_status
json_select ..
}
json_load "$(ubus call qosify status)"
json_for_each_item device_status devices
json_for_each_item interface_status interfaces

View File

@@ -1,24 +1,42 @@
config defaults
list defaults /etc/qosify-defaults.conf
option dscp_prio CS5
option dscp_icmp CS6
option dscp_bulk CS0
option dscp_default_udp CS4
option bulk_trigger_timeout 5
option bulk_trigger_pps 100
list defaults /etc/qosify/*.conf
option dscp_prio video
option dscp_icmp +besteffort
option dscp_default_udp besteffort
option prio_max_avg_pkt_len 500
config class besteffort
option ingress CS0
option egress CS0
config class bulk
option ingress LE
option egress LE
config class video
option ingress AF41
option egress AF41
config class voice
option ingress CS6
option egress CS6
option bulk_trigger_pps 100
option bulk_trigger_timeout 5
option dscp_bulk CS0
config interface wan
option name wan
option disabled 1
option bandwidth_up 100mbit
option bandwidth_down 100mbit
option overhead_type none
# defaults:
option ingress 1
option egress 1
option mode diffserv4
option nat 1
option host_isolate 1
option autorate_ingress 1
option autorate_ingress 0
option ingress_options ""
option egress_options ""
option options ""

View File

@@ -1,5 +1,5 @@
#!/bin/sh /etc/rc.common
# Copyright (c) 2014 OpenWrt.org
# Copyright (c) 2021 OpenWrt.org
START=19
@@ -15,6 +15,16 @@ add_option() {
[ -n "$val" ] && json_add_$type "$name" "$val"
}
add_flow_config() {
local cfg="$1"
add_option string dscp_prio
add_option string dscp_bulk
add_option int bulk_trigger_timeout
add_option int bulk_trigger_pps
add_option int prio_max_avg_pkt_len
}
add_defaults() {
cfg="$1"
@@ -27,15 +37,11 @@ add_defaults() {
done
json_close_array
add_flow_config "$cfg"
add_option int timeout
add_option string dscp_prio
add_option string dscp_bulk
add_option string dscp_icmp
add_option string dscp_default_udp
add_option string dscp_default_tcp
add_option int bulk_trigger_timeout
add_option int bulk_trigger_pps
add_option int prio_max_avg_pkt_len
}
add_interface() {
@@ -57,19 +63,74 @@ add_interface() {
bw_down="${bw_down:-$bw}"
[ -n "$bw_down" ] && json_add_string bandwidth_down "$bw_down"
add_option string bandwidth
add_option string bandwidth
add_option boolean ingress
add_option boolean egress
add_option string mode
add_option boolean host_isolate
add_option boolean nat
add_option boolean host_isolate
add_option boolean autorate_ingress
add_option string ingress_options
add_option string egress_options
add_option string options
config_get user_options "$cfg" options
config_get otype "$cfg" overhead_type
options=
case "$otype" in
none);;
manual)
config_get overhead "$cfg" overhead
[ -n "$overhead" ] && append options "overhead $overhead"
config_get encap "$cfg" overhead_encap
[ -n "$encap" ] && append options "$encap"
;;
conservative|\
pppoa-vcmux|\
pppoa-llc|\
pppoe-vcmux|\
pppoe-llcsnap|\
bridged-vcmux|\
bridged-llcsnap|\
ipoa-vcmux|\
ipoa-llcsnap|\
pppoe-ptm|\
bridged-ptm|\
docsis|\
ethernet)
append options "$otype"
;;
esac
config_get mpu "$cfg" overhead_mpu
[ -n "$mpu" ] && append options "mpu $mpu"
config_get ovlan "$cfg" overhead_vlan
[ "${ovlan:-0}" -ge 2 ] && append options "ether-vlan"
[ "${ovlan:-0}" -ge 1 ] && append options "ether-vlan"
[ -n "$user_options" ] && append options "$user_options"
[ -n "$options" ] && json_add_string options "$options"
json_close_object
}
add_class() {
local cfg="$1"
config_get value "$cfg" value
config_get ingress "$cfg" ingress
config_get egress "$cfg" egress
json_add_object "$cfg"
json_add_string ingress "${ingress:-$value}"
json_add_string egress "${egress:-$value}"
add_flow_config "$cfg"
json_close_object
}
reload_service() {
json_init
@@ -81,6 +142,11 @@ reload_service() {
config_foreach add_interface interface
json_close_object
json_add_object classes
config_foreach add_class class
config_foreach add_class alias
json_close_object
json_add_object devices
config_foreach add_interface device
json_close_object

View File

@@ -1,15 +0,0 @@
cmake_minimum_required(VERSION 3.10)
PROJECT(qosify C)
ADD_DEFINITIONS(-Os -Wall -Wno-unknown-warning-option -Wno-array-bounds -Wno-format-truncation -Werror --std=gnu99)
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
find_library(bpf NAMES bpf)
ADD_EXECUTABLE(qosify main.c loader.c map.c ubus.c interface.c)
TARGET_LINK_LIBRARIES(qosify ${bpf} ubox ubus)
INSTALL(TARGETS qosify
RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR}
)

View File

@@ -1,112 +0,0 @@
QoSify is simple daemon for setting up and managing CAKE along with a custom
eBPF based classifier that sets DSCP fields of packets.
It supports the following features:
- simple TCP/UDP port based mapping
- IP address based mapping
- priority boosting based on average packet size
- bulk flow detection based on number of packets per second
- dynamically add IP entries with timeout
- dns regex entries and ubus api for providing dns lookup results
It can be configured via ubus call qosify config.
This call supports the following parameters:
- "reset": BOOL
Reset the config to defaults instead of only updating supplied values
- "files": ARRAY of STRING
List of files with port/IP/host mappings
- "timeout": INT32
Default timeout for dynamically added entries
- "dscp_default_udp": STRING
Default DSCP value for UDP packets
- "dscp_default_tcp": STRING
Default DSCP value for TCP packets
- "dscp_prio": STRING
DSCP value for priority-marked packets
- "dscp_bulk": STRING
DSCP value for bulk-marked packets
- "dscp_icmp": STRING
DSCP value for ICMP packets
- "bulk_trigger_pps": INT32
Number of packets per second to trigger bulk flow detection
- "bulk_trigger_timeout": INT32
Time below bulk_trigger_pps threshold until a bulk flow mark is removed
- "prio_max_avg_pkt_len": INT32
Maximum average packet length for marking a flow as priority
- "interfaces": TABLE of TABLE
netifd interfaces to enable QoS on
- "devices": TABLE of TABLE
netdevs to enable QoS on
interface/device properties:
- "bandwidth_up": STRING
Uplink bandwidth (same format as tc)
- "bandwidth_down": STRING
Downlink bandwidth (same format as tc)
- "ingress": BOOL
Enable ingress shaping
- "egress": BOOL
Enable egress shaping
- "mode": STRING
CAKE diffserv mode
- "nat": BOOL
Enable CAKE NAT host detection via conntrack
- "host_isolate": BOOL
Enable CAKE host isolation
- "autorate_ingress": BOOL
Enable CAKE automatic rate estimation for ingress
- "ingress_options": STRING
CAKE ingress options
- "egress_options": STRING
CAKE egress options
- "options": STRING
CAKE options for ingress + egress
Mapping file syntax:
Each line has two whitespace separated fields, match and dscp
match is one of:
- tcp:<port>[-<endport>]
TCP single port, or range from <port> to <endport>
- udp:<port>[-<endport>]
UDP single port, or range from <port> to <endport>
- <ipaddr>
IPv4 address, e.g. 1.1.1.1
- <ipv6addr>
IPv6 address, e.g. ff01::1
- dns:<regex>
POSIX.2 extended regular expression for matching hostnames
Only works, if dns lookups are passed to qosify via the add_dns_host ubus call.
dscp can be a raw value, or a codepoint like CS0
Adding a + in front of the value tells qosify to only override the DSCP value if it is zero
Planned features:
- Integration with dnsmasq to support hostname pattern based DSCP marking
- Support for LAN host based priority

View File

@@ -1,563 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <unistd.h>
#include <errno.h>
#include <libubox/vlist.h>
#include <libubox/avl-cmp.h>
#include <libubox/uloop.h>
#include "qosify.h"
static void interface_update_cb(struct vlist_tree *tree,
struct vlist_node *node_new,
struct vlist_node *node_old);
static VLIST_TREE(devices, avl_strcmp, interface_update_cb, true, false);
static VLIST_TREE(interfaces, avl_strcmp, interface_update_cb, true, false);
static int socket_fd;
#define APPEND(_buf, _ofs, _format, ...) _ofs += snprintf(_buf + _ofs, sizeof(_buf) - _ofs, _format, ##__VA_ARGS__)
struct qosify_iface_config {
struct blob_attr *data;
bool ingress;
bool egress;
bool nat;
bool host_isolate;
bool autorate_ingress;
const char *bandwidth_up;
const char *bandwidth_down;
const char *mode;
const char *common_opts;
const char *ingress_opts;
const char *egress_opts;
};
struct qosify_iface {
struct vlist_node node;
char ifname[IFNAMSIZ];
bool active;
bool device;
struct blob_attr *config_data;
struct qosify_iface_config config;
};
enum {
IFACE_ATTR_BW_UP,
IFACE_ATTR_BW_DOWN,
IFACE_ATTR_INGRESS,
IFACE_ATTR_EGRESS,
IFACE_ATTR_MODE,
IFACE_ATTR_NAT,
IFACE_ATTR_HOST_ISOLATE,
IFACE_ATTR_AUTORATE_IN,
IFACE_ATTR_INGRESS_OPTS,
IFACE_ATTR_EGRESS_OPTS,
IFACE_ATTR_OPTS,
__IFACE_ATTR_MAX
};
static inline const char *qosify_iface_name(struct qosify_iface *iface)
{
return iface->node.avl.key;
}
static void
iface_config_parse(struct blob_attr *attr, struct blob_attr **tb)
{
static const struct blobmsg_policy policy[__IFACE_ATTR_MAX] = {
[IFACE_ATTR_BW_UP] = { "bandwidth_up", BLOBMSG_TYPE_STRING },
[IFACE_ATTR_BW_DOWN] = { "bandwidth_down", BLOBMSG_TYPE_STRING },
[IFACE_ATTR_INGRESS] = { "ingress", BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_EGRESS] = { "egress", BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_MODE] = { "mode", BLOBMSG_TYPE_STRING },
[IFACE_ATTR_NAT] = { "nat", BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_HOST_ISOLATE] = { "host_isolate", BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_AUTORATE_IN] = { "autorate_ingress", BLOBMSG_TYPE_BOOL },
[IFACE_ATTR_INGRESS_OPTS] = { "ingress_options", BLOBMSG_TYPE_STRING },
[IFACE_ATTR_EGRESS_OPTS] = { "egress_options", BLOBMSG_TYPE_STRING },
[IFACE_ATTR_OPTS] = { "options", BLOBMSG_TYPE_STRING },
};
blobmsg_parse(policy, __IFACE_ATTR_MAX, tb, blobmsg_data(attr), blobmsg_len(attr));
}
static bool
iface_config_equal(struct qosify_iface *if1, struct qosify_iface *if2)
{
struct blob_attr *tb1[__IFACE_ATTR_MAX], *tb2[__IFACE_ATTR_MAX];
int i;
iface_config_parse(if1->config_data, tb1);
iface_config_parse(if2->config_data, tb2);
for (i = 0; i < __IFACE_ATTR_MAX; i++) {
if (!!tb1[i] != !!tb2[i])
return false;
if (!tb1[i])
continue;
if (blob_raw_len(tb1[i]) != blob_raw_len(tb2[i]))
return false;
if (memcmp(tb1[i], tb2[i], blob_raw_len(tb1[i])) != 0)
return false;
}
return true;
}
static const char *check_str(struct blob_attr *attr)
{
const char *str = blobmsg_get_string(attr);
if (strchr(str, '\''))
return NULL;
return str;
}
static void
iface_config_set(struct qosify_iface *iface, struct blob_attr *attr)
{
struct qosify_iface_config *cfg = &iface->config;
struct blob_attr *tb[__IFACE_ATTR_MAX];
struct blob_attr *cur;
iface_config_parse(attr, tb);
memset(cfg, 0, sizeof(*cfg));
/* defaults */
cfg->mode = "diffserv4";
cfg->ingress = true;
cfg->egress = true;
cfg->host_isolate = true;
cfg->autorate_ingress = true;
cfg->nat = !iface->device;
if ((cur = tb[IFACE_ATTR_BW_UP]) != NULL)
cfg->bandwidth_up = check_str(cur);
if ((cur = tb[IFACE_ATTR_BW_DOWN]) != NULL)
cfg->bandwidth_down = check_str(cur);
if ((cur = tb[IFACE_ATTR_MODE]) != NULL)
cfg->mode = check_str(cur);
if ((cur = tb[IFACE_ATTR_OPTS]) != NULL)
cfg->common_opts = check_str(cur);
if ((cur = tb[IFACE_ATTR_EGRESS_OPTS]) != NULL)
cfg->egress_opts = check_str(cur);
if ((cur = tb[IFACE_ATTR_INGRESS_OPTS]) != NULL)
cfg->ingress_opts = check_str(cur);
if ((cur = tb[IFACE_ATTR_INGRESS]) != NULL)
cfg->ingress = blobmsg_get_bool(cur);
if ((cur = tb[IFACE_ATTR_EGRESS]) != NULL)
cfg->egress = blobmsg_get_bool(cur);
if ((cur = tb[IFACE_ATTR_NAT]) != NULL)
cfg->nat = blobmsg_get_bool(cur);
if ((cur = tb[IFACE_ATTR_HOST_ISOLATE]) != NULL)
cfg->host_isolate = blobmsg_get_bool(cur);
if ((cur = tb[IFACE_ATTR_AUTORATE_IN]) != NULL)
cfg->autorate_ingress = blobmsg_get_bool(cur);
}
static const char *
interface_ifb_name(struct qosify_iface *iface)
{
static char ifname[IFNAMSIZ + 1] = "ifb-";
int len = strlen(iface->ifname);
if (len + 4 < IFNAMSIZ) {
snprintf(ifname + 4, IFNAMSIZ - 4, "%s", iface->ifname);
return ifname;
}
ifname[4] = iface->ifname[0];
ifname[5] = iface->ifname[1];
snprintf(ifname + 6, IFNAMSIZ - 6, "%s", iface->ifname + len - (IFNAMSIZ + 6) - 1);
return ifname;
}
static int run_cmd(char *cmd, bool ignore)
{
char *argv[] = { "sh", "-c", cmd, NULL };
bool first = true;
int status = -1;
char buf[512];
int fds[2];
FILE *f;
int pid;
if (pipe(fds))
return -1;
pid = fork();
if (!pid) {
close(fds[0]);
if (fds[1] != STDOUT_FILENO)
dup2(fds[1], STDOUT_FILENO);
if (fds[1] != STDERR_FILENO)
dup2(fds[1], STDERR_FILENO);
if (fds[1] > STDERR_FILENO)
close(fds[1]);
execv("/bin/sh", argv);
exit(1);
}
if (pid < 0)
return -1;
close(fds[1]);
f = fdopen(fds[0], "r");
if (!f) {
close(fds[0]);
goto out;
}
while (fgets(buf, sizeof(buf), f) != NULL) {
if (!strlen(buf))
break;
if (ignore)
continue;
if (first) {
ULOG_WARN("Command: %s\n", cmd);
first = false;
}
ULOG_WARN("%s%s", buf, strchr(buf, '\n') ? "" : "\n");
}
fclose(f);
out:
while (waitpid(pid, &status, 0) < 0)
if (errno != EINTR)
break;
return status;
}
static int
prepare_tc_cmd(char *buf, int len, const char *type, const char *cmd,
const char *dev, const char *extra)
{
return snprintf(buf, len, "tc %s %s dev '%s' %s", type, cmd, dev, extra);
}
static int
cmd_del_qdisc(const char *ifname, const char *type)
{
char buf[64];
prepare_tc_cmd(buf, sizeof(buf), "qdisc", "del", ifname, type);
return run_cmd(buf, true);
}
static int
cmd_add_qdisc(struct qosify_iface *iface, const char *ifname, bool egress, bool eth)
{
struct qosify_iface_config *cfg = &iface->config;
const char *bw = egress ? cfg->bandwidth_up : cfg->bandwidth_down;
const char *dir_opts = egress ? cfg->egress_opts : cfg->ingress_opts;
char buf[512];
int ofs;
cmd_del_qdisc(ifname, "root");
ofs = prepare_tc_cmd(buf, sizeof(buf), "qdisc", "add", ifname, "root handle 1: cake");
if (bw)
APPEND(buf, ofs, " bandwidth %s", bw);
APPEND(buf, ofs, " %s %sgress", cfg->mode, egress ? "e" : "in");
if (cfg->host_isolate)
APPEND(buf, ofs, " %snat dual-%shost",
cfg->nat ? "" : "no",
egress ? "src" : "dst");
else
APPEND(buf, ofs, " flows");
APPEND(buf, ofs, " %s %s",
cfg->common_opts ? cfg->common_opts : "",
dir_opts ? dir_opts : "");
run_cmd(buf, false);
ofs = prepare_tc_cmd(buf, sizeof(buf), "filter", "add", ifname, "parent 1: bpf");
APPEND(buf, ofs, " object-pinned /sys/fs/bpf/qosify_%sgress_%s verbose direct-action",
egress ? "e" : "in",
eth ? "eth" : "ip");
return run_cmd(buf, false);
}
static int
cmd_del_ingress(struct qosify_iface *iface)
{
char buf[256];
cmd_del_qdisc(iface->ifname, "handle ffff: ingress");
snprintf(buf, sizeof(buf), "ip link del '%s'", interface_ifb_name(iface));
return run_cmd(buf, true);
}
static int
cmd_add_ingress(struct qosify_iface *iface, bool eth)
{
const char *ifbdev = interface_ifb_name(iface);
char buf[256];
int ofs;
cmd_del_ingress(iface);
ofs = prepare_tc_cmd(buf, sizeof(buf), "qdisc", "add", iface->ifname, " handle ffff: ingress");
run_cmd(buf, false);
snprintf(buf, sizeof(buf), "ip link add '%s' type ifb", ifbdev);
run_cmd(buf, false);
cmd_add_qdisc(iface, ifbdev, false, eth);
snprintf(buf, sizeof(buf), "ip link set dev '%s' up", ifbdev);
run_cmd(buf, false);
ofs = prepare_tc_cmd(buf, sizeof(buf), "filter", "add", iface->ifname, " parent ffff:");
APPEND(buf, ofs, " protocol all prio 10 u32 match u32 0 0 "
"flowid 1:1 action mirred egress redirect dev '%s'", ifbdev);
return run_cmd(buf, false);
}
static void
interface_start(struct qosify_iface *iface)
{
struct ifreq ifr = {};
bool eth;
if (!iface->ifname[0] || iface->active)
return;
ULOG_INFO("start interface %s\n", iface->ifname);
strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name));
if (ioctl(socket_fd, SIOCGIFHWADDR, &ifr) < 0) {
ULOG_ERR("ioctl(SIOCGIFHWADDR, %s) failed: %s\n", iface->ifname, strerror(errno));
return;
}
eth = ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER;
if (iface->config.egress)
cmd_add_qdisc(iface, iface->ifname, true, eth);
if (iface->config.ingress)
cmd_add_ingress(iface, eth);
iface->active = true;
}
static void
interface_stop(struct qosify_iface *iface)
{
if (!iface->ifname[0] || !iface->active)
return;
ULOG_INFO("stop interface %s\n", iface->ifname);
iface->active = false;
if (iface->config.egress)
cmd_del_qdisc(iface->ifname, "root");
if (iface->config.ingress)
cmd_del_ingress(iface);
}
static void
interface_set_config(struct qosify_iface *iface, struct blob_attr *config)
{
iface->config_data = blob_memdup(config);
iface_config_set(iface, iface->config_data);
interface_start(iface);
}
static void
interface_update_cb(struct vlist_tree *tree,
struct vlist_node *node_new, struct vlist_node *node_old)
{
struct qosify_iface *if_new = NULL, *if_old = NULL;
if (node_new)
if_new = container_of(node_new, struct qosify_iface, node);
if (node_old)
if_old = container_of(node_old, struct qosify_iface, node);
if (if_new && if_old) {
if (!iface_config_equal(if_old, if_new)) {
interface_stop(if_old);
free(if_old->config_data);
interface_set_config(if_old, if_new->config_data);
}
free(if_new);
return;
}
if (if_old) {
interface_stop(if_old);
free(if_old->config_data);
free(if_old);
}
if (if_new)
interface_set_config(if_new, if_new->config_data);
}
static void
interface_create(struct blob_attr *attr, bool device)
{
struct qosify_iface *iface;
const char *name = blobmsg_name(attr);
int name_len = strlen(name);
char *name_buf;
if (strchr(name, '\''))
return;
if (name_len >= IFNAMSIZ)
return;
if (blobmsg_type(attr) != BLOBMSG_TYPE_TABLE)
return;
iface = calloc_a(sizeof(*iface), &name_buf, name_len + 1);
strcpy(name_buf, blobmsg_name(attr));
iface->config_data = attr;
iface->device = device;
vlist_add(device ? &devices : &interfaces, &iface->node, name_buf);
}
void qosify_iface_config_update(struct blob_attr *ifaces, struct blob_attr *devs)
{
struct blob_attr *cur;
int rem;
vlist_update(&devices);
blobmsg_for_each_attr(cur, devs, rem)
interface_create(cur, true);
vlist_flush(&devices);
vlist_update(&interfaces);
blobmsg_for_each_attr(cur, ifaces, rem)
interface_create(cur, false);
vlist_flush(&interfaces);
}
static void
qosify_iface_check_device(struct qosify_iface *iface)
{
const char *name = qosify_iface_name(iface);
int ifindex;
ifindex = if_nametoindex(name);
if (!ifindex) {
interface_stop(iface);
iface->ifname[0] = 0;
} else {
snprintf(iface->ifname, sizeof(iface->ifname), "%s", name);
interface_start(iface);
}
}
static void
qosify_iface_check_interface(struct qosify_iface *iface)
{
const char *name = qosify_iface_name(iface);
char ifname[IFNAMSIZ];
if (qosify_ubus_check_interface(name, ifname, sizeof(ifname)) == 0) {
snprintf(iface->ifname, sizeof(iface->ifname), "%s", ifname);
interface_start(iface);
} else {
interface_stop(iface);
iface->ifname[0] = 0;
}
}
static void qos_iface_check_cb(struct uloop_timeout *t)
{
struct qosify_iface *iface;
vlist_for_each_element(&devices, iface, node)
qosify_iface_check_device(iface);
vlist_for_each_element(&interfaces, iface, node)
qosify_iface_check_interface(iface);
}
void qosify_iface_check(void)
{
static struct uloop_timeout timer = {
.cb = qos_iface_check_cb,
};
uloop_timeout_set(&timer, 10);
}
void qosify_iface_status(struct blob_buf *b)
{
struct qosify_iface *iface;
void *c, *i;
c = blobmsg_open_table(b, "devices");
vlist_for_each_element(&devices, iface, node) {
i = blobmsg_open_table(b, qosify_iface_name(iface));
blobmsg_add_u8(b, "active", iface->active);
blobmsg_close_table(b, i);
}
blobmsg_close_table(b, c);
c = blobmsg_open_table(b, "interfaces");
vlist_for_each_element(&interfaces, iface, node) {
i = blobmsg_open_table(b, qosify_iface_name(iface));
blobmsg_add_u8(b, "active", iface->active);
if (iface->ifname)
blobmsg_add_string(b, "ifname", iface->ifname);
blobmsg_close_table(b, i);
}
blobmsg_close_table(b, c);
}
int qosify_iface_init(void)
{
socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (socket < 0)
return -1;
return 0;
}
void qosify_iface_stop(void)
{
struct qosify_iface *iface;
vlist_for_each_element(&interfaces, iface, node)
interface_stop(iface);
vlist_for_each_element(&devices, iface, node)
interface_stop(iface);
}

View File

@@ -1,121 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#include <sys/resource.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <glob.h>
#include <unistd.h>
#include "qosify.h"
static int qosify_bpf_pr(enum libbpf_print_level level, const char *format,
va_list args)
{
return vfprintf(stderr, format, args);
}
static void qosify_init_env(void)
{
struct rlimit limit = {
.rlim_cur = RLIM_INFINITY,
.rlim_max = RLIM_INFINITY,
};
setrlimit(RLIMIT_MEMLOCK, &limit);
}
static void qosify_fill_rodata(struct bpf_object *obj, uint32_t flags)
{
struct bpf_map *map = NULL;
while ((map = bpf_map__next(map, obj)) != NULL) {
if (!strstr(bpf_map__name(map), ".rodata"))
continue;
bpf_map__set_initial_value(map, &flags, sizeof(flags));
}
}
static int
qosify_create_program(const char *suffix, uint32_t flags)
{
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
.pin_root_path = CLASSIFY_DATA_PATH,
);
struct bpf_program *prog;
struct bpf_object *obj;
char path[256];
int err;
snprintf(path, sizeof(path), CLASSIFY_PIN_PATH "_" "%s", suffix);
obj = bpf_object__open_file(CLASSIFY_PROG_PATH, &opts);
err = libbpf_get_error(obj);
if (err) {
perror("bpf_object__open_file");
return -1;
}
prog = bpf_object__find_program_by_title(obj, "classifier");
if (!prog) {
fprintf(stderr, "Can't find classifier prog\n");
return -1;
}
bpf_program__set_type(prog, BPF_PROG_TYPE_SCHED_CLS);
qosify_fill_rodata(obj, flags);
err = bpf_object__load(obj);
if (err) {
perror("bpf_object__load");
return -1;
}
libbpf_set_print(NULL);
unlink(path);
err = bpf_program__pin(prog, path);
if (err) {
fprintf(stderr, "Failed to pin program to %s: %s\n",
path, strerror(-err));
}
bpf_object__close(obj);
return 0;
}
int qosify_loader_init(void)
{
static const struct {
const char *suffix;
uint32_t flags;
} progs[] = {
{ "egress_eth", 0 },
{ "egress_ip", QOSIFY_IP_ONLY },
{ "ingress_eth", QOSIFY_INGRESS },
{ "ingress_ip", QOSIFY_INGRESS | QOSIFY_IP_ONLY },
};
glob_t g;
int i;
if (glob(CLASSIFY_DATA_PATH "/*", 0, NULL, &g) == 0) {
for (i = 0; i < g.gl_pathc; i++)
unlink(g.gl_pathv[i]);
}
libbpf_set_print(qosify_bpf_pr);
qosify_init_env();
for (i = 0; i < ARRAY_SIZE(progs); i++) {
if (qosify_create_program(progs[i].suffix, progs[i].flags))
return -1;
}
return 0;
}

View File

@@ -1,72 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <libubox/uloop.h>
#include "qosify.h"
static int usage(const char *progname)
{
fprintf(stderr, "Usage: %s [options]\n"
"Options:\n"
" -l <file> Load defaults from <file>\n"
" -o only load program/maps without running as daemon\n"
"\n", progname);
return 1;
}
int main(int argc, char **argv)
{
const char *load_file = NULL;
bool oneshot = false;
int ch;
while ((ch = getopt(argc, argv, "fl:o")) != -1) {
switch (ch) {
case 'f':
break;
case 'l':
load_file = optarg;
break;
case 'o':
oneshot = true;
break;
default:
return usage(argv[0]);
}
}
if (qosify_loader_init())
return 2;
if (qosify_map_init())
return 2;
if (qosify_map_load_file(load_file))
return 2;
if (oneshot)
return 0;
ulog_open(ULOG_SYSLOG, LOG_DAEMON, "qosify");
uloop_init();
if (qosify_ubus_init() ||
qosify_iface_init())
return 2;
uloop_run();
qosify_ubus_stop();
qosify_iface_stop();
uloop_done();
return 0;
}

View File

@@ -1,735 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
#include <libubox/uloop.h>
#include "qosify.h"
static int qosify_map_entry_cmp(const void *k1, const void *k2, void *ptr);
static int qosify_map_fds[__CL_MAP_MAX];
static AVL_TREE(map_data, qosify_map_entry_cmp, false, NULL);
static LIST_HEAD(map_files);
static uint32_t next_timeout;
static uint8_t qosify_dscp_default[2] = { 0xff, 0xff };
int qosify_map_timeout;
int qosify_active_timeout;
struct qosify_config config;
struct qosify_map_file {
struct list_head list;
char filename[];
};
static const struct {
const char *name;
const char *type_name;
} qosify_map_info[] = {
[CL_MAP_TCP_PORTS] = { "tcp_ports", "tcp_port" },
[CL_MAP_UDP_PORTS] = { "udp_ports", "udp_port" },
[CL_MAP_IPV4_ADDR] = { "ipv4_map", "ipv4_addr" },
[CL_MAP_IPV6_ADDR] = { "ipv6_map", "ipv6_addr" },
[CL_MAP_CONFIG] = { "config", "config" },
[CL_MAP_DNS] = { "dns", "dns" },
};
static const struct {
const char name[5];
uint8_t val;
} codepoints[] = {
{ "CS0", 0 },
{ "CS1", 8 },
{ "CS2", 16 },
{ "CS3", 24 },
{ "CS4", 32 },
{ "CS5", 40 },
{ "CS6", 48 },
{ "CS7", 56 },
{ "AF11", 10 },
{ "AF12", 12 },
{ "AF13", 14 },
{ "AF21", 18 },
{ "AF22", 20 },
{ "AF22", 22 },
{ "AF31", 26 },
{ "AF32", 28 },
{ "AF33", 30 },
{ "AF41", 34 },
{ "AF42", 36 },
{ "AF43", 38 },
{ "EF", 46 },
{ "VA", 44 },
{ "LE", 1 },
{ "DF", 0 },
};
static void qosify_map_timer_cb(struct uloop_timeout *t)
{
qosify_map_gc();
}
static struct uloop_timeout qosify_map_timer = {
.cb = qosify_map_timer_cb,
};
static uint32_t qosify_gettime(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec;
}
static const char *
qosify_map_path(enum qosify_map_id id)
{
static char path[128];
const char *name;
if (id >= ARRAY_SIZE(qosify_map_info))
return NULL;
name = qosify_map_info[id].name;
if (!name)
return NULL;
snprintf(path, sizeof(path), "%s/%s", CLASSIFY_DATA_PATH, name);
return path;
}
static int qosify_map_get_fd(enum qosify_map_id id)
{
const char *path = qosify_map_path(id);
int fd;
if (!path)
return -1;
fd = bpf_obj_get(path);
if (fd < 0)
fprintf(stderr, "Failed to open map %s: %s\n", path, strerror(errno));
return fd;
}
static void qosify_map_clear_list(enum qosify_map_id id)
{
int fd = qosify_map_fds[id];
__u32 key[4] = {};
while (bpf_map_get_next_key(fd, &key, &key) != -1)
bpf_map_delete_elem(fd, &key);
}
static void __qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val)
{
struct qosify_map_data data = {
.id = id,
};
int fd = qosify_map_fds[id];
int i;
val |= QOSIFY_DSCP_DEFAULT_FLAG;
for (i = 0; i < (1 << 16); i++) {
data.addr.port = htons(i);
if (avl_find(&map_data, &data))
continue;
bpf_map_update_elem(fd, &data.addr, &val, BPF_ANY);
}
}
void qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val)
{
bool udp;
if (id == CL_MAP_TCP_PORTS)
udp = false;
else if (id == CL_MAP_UDP_PORTS)
udp = true;
else
return;
if (qosify_dscp_default[udp] == val)
return;
qosify_dscp_default[udp] = val;
__qosify_map_set_dscp_default(id, val);
}
int qosify_map_init(void)
{
int i;
for (i = 0; i < CL_MAP_DNS; i++) {
qosify_map_fds[i] = qosify_map_get_fd(i);
if (qosify_map_fds[i] < 0)
return -1;
}
qosify_map_clear_list(CL_MAP_IPV4_ADDR);
qosify_map_clear_list(CL_MAP_IPV6_ADDR);
qosify_map_reset_config();
return 0;
}
static char *str_skip(char *str, bool space)
{
while (*str && isspace(*str) == space)
str++;
return str;
}
static int
qosify_map_codepoint(const char *val)
{
int i;
for (i = 0; i < ARRAY_SIZE(codepoints); i++)
if (!strcmp(codepoints[i].name, val))
return codepoints[i].val;
return 0xff;
}
static int qosify_map_entry_cmp(const void *k1, const void *k2, void *ptr)
{
const struct qosify_map_data *d1 = k1;
const struct qosify_map_data *d2 = k2;
if (d1->id != d2->id)
return d2->id - d1->id;
if (d1->id == CL_MAP_DNS)
return strcmp(d1->addr.dns.pattern, d2->addr.dns.pattern);
return memcmp(&d1->addr, &d2->addr, sizeof(d1->addr));
}
static struct qosify_map_entry *
__qosify_map_alloc_entry(struct qosify_map_data *data)
{
struct qosify_map_entry *e;
char *pattern;
if (data->id < CL_MAP_DNS) {
e = calloc(1, sizeof(*e));
memcpy(&e->data.addr, &data->addr, sizeof(e->data.addr));
return e;
}
e = calloc_a(sizeof(*e), &pattern, strlen(data->addr.dns.pattern) + 1);
strcpy(pattern, data->addr.dns.pattern);
e->data.addr.dns.pattern = pattern;
if (regcomp(&e->data.addr.dns.regex, pattern,
REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
free(e);
return NULL;
}
return e;
}
static void __qosify_map_set_entry(struct qosify_map_data *data)
{
int fd = qosify_map_fds[data->id];
struct qosify_map_entry *e;
bool file = data->file;
int32_t delta = 0;
bool add = data->dscp != 0xff;
uint8_t prev_dscp = 0xff;
e = avl_find_element(&map_data, data, e, avl);
if (!e) {
if (!add)
return;
e = __qosify_map_alloc_entry(data);
if (!e)
return;
e->avl.key = &e->data;
e->data.id = data->id;
avl_insert(&map_data, &e->avl);
} else {
prev_dscp = e->data.dscp;
}
if (file)
e->data.file = add;
else
e->data.user = add;
if (add) {
if (file)
e->data.file_dscp = data->dscp;
if (!e->data.user || !file)
e->data.dscp = data->dscp;
} else if (e->data.file && !file) {
e->data.dscp = e->data.file_dscp;
}
if (e->data.dscp != prev_dscp && data->id < CL_MAP_DNS) {
struct qosify_ip_map_val val = {
.dscp = e->data.dscp,
.seen = 1,
};
bpf_map_update_elem(fd, &data->addr, &val, BPF_ANY);
}
if (add) {
if (qosify_map_timeout == ~0 || file) {
e->timeout = ~0;
return;
}
e->timeout = qosify_gettime() + qosify_map_timeout;
delta = e->timeout - next_timeout;
if (next_timeout && delta >= 0)
return;
}
uloop_timeout_set(&qosify_map_timer, 1);
}
static int
qosify_map_set_port(struct qosify_map_data *data, const char *str)
{
unsigned long start_port, end_port;
char *err;
int i;
start_port = end_port = strtoul(str, &err, 0);
if (err && *err) {
if (*err == '-')
end_port = strtoul(err + 1, &err, 0);
if (*err)
return -1;
}
if (!start_port || end_port < start_port ||
end_port >= 65535)
return -1;
for (i = start_port; i <= end_port; i++) {
data->addr.port = htons(i);
__qosify_map_set_entry(data);
}
return 0;
}
static int
qosify_map_fill_ip(struct qosify_map_data *data, const char *str)
{
int af;
if (data->id == CL_MAP_IPV6_ADDR)
af = AF_INET6;
else
af = AF_INET;
if (inet_pton(af, str, &data->addr) != 1)
return -1;
return 0;
}
int qosify_map_set_entry(enum qosify_map_id id, bool file, const char *str, uint8_t dscp)
{
struct qosify_map_data data = {
.id = id,
.file = file,
.dscp = dscp,
};
switch (id) {
case CL_MAP_DNS:
data.addr.dns.pattern = str;
break;
case CL_MAP_TCP_PORTS:
case CL_MAP_UDP_PORTS:
return qosify_map_set_port(&data, str);
case CL_MAP_IPV4_ADDR:
case CL_MAP_IPV6_ADDR:
if (qosify_map_fill_ip(&data, str))
return -1;
break;
default:
return -1;
}
__qosify_map_set_entry(&data);
return 0;
}
int qosify_map_dscp_value(const char *val)
{
unsigned long dscp;
char *err;
bool fallback = false;
if (*val == '+') {
fallback = true;
val++;
}
dscp = strtoul(val, &err, 0);
if (err && *err)
dscp = qosify_map_codepoint(val);
if (dscp >= 64)
return -1;
return dscp + (fallback << 6);
}
static void
qosify_map_dscp_codepoint_str(char *dest, int len, uint8_t dscp)
{
int i;
if (dscp & QOSIFY_DSCP_FALLBACK_FLAG) {
*(dest++) = '+';
len--;
dscp &= ~QOSIFY_DSCP_FALLBACK_FLAG;
}
for (i = 0; i < ARRAY_SIZE(codepoints); i++) {
if (codepoints[i].val != dscp)
continue;
snprintf(dest, len, "%s", codepoints[i].name);
return;
}
snprintf(dest, len, "0x%x", dscp);
}
static void
qosify_map_parse_line(char *str)
{
const char *key, *value;
int dscp;
str = str_skip(str, true);
key = str;
str = str_skip(str, false);
if (!*str)
return;
*(str++) = 0;
str = str_skip(str, true);
value = str;
dscp = qosify_map_dscp_value(value);
if (dscp < 0)
return;
if (!strncmp(key, "dns:", 4))
qosify_map_set_entry(CL_MAP_DNS, true, key + 4, dscp);
if (!strncmp(key, "tcp:", 4))
qosify_map_set_entry(CL_MAP_TCP_PORTS, true, key + 4, dscp);
else if (!strncmp(key, "udp:", 4))
qosify_map_set_entry(CL_MAP_UDP_PORTS, true, key + 4, dscp);
else if (strchr(key, ':'))
qosify_map_set_entry(CL_MAP_IPV6_ADDR, true, key, dscp);
else if (strchr(key, '.'))
qosify_map_set_entry(CL_MAP_IPV4_ADDR, true, key, dscp);
}
static int __qosify_map_load_file(const char *file)
{
char line[1024];
char *cur;
FILE *f;
if (!file)
return 0;
f = fopen(file, "r");
if (!f) {
fprintf(stderr, "Can't open data file %s\n", file);
return -1;
}
while (fgets(line, sizeof(line), f)) {
cur = strchr(line, '#');
if (cur)
*cur = 0;
cur = line + strlen(line);
if (cur == line)
continue;
while (cur > line && isspace(cur[-1]))
cur--;
*cur = 0;
qosify_map_parse_line(line);
}
fclose(f);
return 0;
}
int qosify_map_load_file(const char *file)
{
struct qosify_map_file *f;
if (!file)
return 0;
f = calloc(1, sizeof(*f) + strlen(file) + 1);
strcpy(f->filename, file);
list_add_tail(&f->list, &map_files);
return __qosify_map_load_file(file);
}
static void qosify_map_reset_file_entries(void)
{
struct qosify_map_entry *e;
avl_for_each_element(&map_data, e, avl)
e->data.file = false;
}
void qosify_map_clear_files(void)
{
struct qosify_map_file *f, *tmp;
qosify_map_reset_file_entries();
list_for_each_entry_safe(f, tmp, &map_files, list) {
list_del(&f->list);
free(f);
}
}
void qosify_map_reset_config(void)
{
qosify_map_clear_files();
qosify_map_set_dscp_default(CL_MAP_TCP_PORTS, 0);
qosify_map_set_dscp_default(CL_MAP_UDP_PORTS, 0);
qosify_map_timeout = 3600;
qosify_active_timeout = 300;
memset(&config, 0, sizeof(config));
config.dscp_prio = 0xff;
config.dscp_bulk = 0xff;
config.dscp_icmp = 0xff;
}
void qosify_map_reload(void)
{
struct qosify_map_file *f;
qosify_map_reset_file_entries();
list_for_each_entry(f, &map_files, list)
__qosify_map_load_file(f->filename);
qosify_map_gc();
}
static void qosify_map_free_entry(struct qosify_map_entry *e)
{
int fd = qosify_map_fds[e->data.id];
avl_delete(&map_data, &e->avl);
if (e->data.id < CL_MAP_DNS)
bpf_map_delete_elem(fd, &e->data.addr);
free(e);
}
static bool
qosify_map_entry_refresh_timeout(struct qosify_map_entry *e)
{
struct qosify_ip_map_val val;
int fd = qosify_map_fds[e->data.id];
if (e->data.id != CL_MAP_IPV4_ADDR &&
e->data.id != CL_MAP_IPV6_ADDR)
return false;
if (bpf_map_lookup_elem(fd, &e->data.addr, &val))
return false;
if (!val.seen)
return false;
e->timeout = qosify_gettime() + qosify_active_timeout;
val.seen = 0;
bpf_map_update_elem(fd, &e->data.addr, &val, BPF_ANY);
return true;
}
void qosify_map_gc(void)
{
struct qosify_map_entry *e, *tmp;
int32_t timeout = 0;
uint32_t cur_time = qosify_gettime();
next_timeout = 0;
avl_for_each_element_safe(&map_data, e, avl, tmp) {
int32_t cur_timeout;
if (e->data.user && e->timeout != ~0) {
cur_timeout = e->timeout - cur_time;
if (cur_timeout <= 0 &&
qosify_map_entry_refresh_timeout(e))
cur_timeout = e->timeout - cur_time;
if (cur_timeout <= 0) {
e->data.user = false;
e->data.dscp = e->data.file_dscp;
} else if (!timeout || cur_timeout < timeout) {
timeout = cur_timeout;
next_timeout = e->timeout;
}
}
if (e->data.file || e->data.user)
continue;
qosify_map_free_entry(e);
}
if (!timeout)
return;
uloop_timeout_set(&qosify_map_timer, timeout * 1000);
}
int qosify_map_add_dns_host(const char *host, const char *addr, const char *type, int ttl)
{
struct qosify_map_data data = {
.id = CL_MAP_DNS,
.addr.dns.pattern = "",
};
struct qosify_map_entry *e;
int prev_timeout = qosify_map_timeout;
e = avl_find_ge_element(&map_data, &data, e, avl);
if (!e)
return 0;
memset(&data, 0, sizeof(data));
data.user = true;
if (!strcmp(type, "A"))
data.id = CL_MAP_IPV4_ADDR;
else if (!strcmp(type, "AAAA"))
data.id = CL_MAP_IPV6_ADDR;
else
return 0;
if (qosify_map_fill_ip(&data, addr))
return -1;
avl_for_element_to_last(&map_data, e, e, avl) {
regex_t *regex = &e->data.addr.dns.regex;
if (e->data.id != CL_MAP_DNS)
return 0;
if (regexec(regex, host, 0, NULL, 0) != 0)
continue;
if (ttl)
qosify_map_timeout = ttl;
data.dscp = e->data.dscp;
__qosify_map_set_entry(&data);
qosify_map_timeout = prev_timeout;
}
return 0;
}
void qosify_map_dump(struct blob_buf *b)
{
struct qosify_map_entry *e;
uint32_t cur_time = qosify_gettime();
int buf_len = INET6_ADDRSTRLEN + 1;
char *buf;
void *a;
int af;
a = blobmsg_open_array(b, "entries");
avl_for_each_element(&map_data, e, avl) {
void *c;
if (!e->data.file && !e->data.user)
continue;
c = blobmsg_open_table(b, NULL);
if (e->data.user && e->timeout != ~0) {
int32_t cur_timeout = e->timeout - cur_time;
if (cur_timeout < 0)
cur_timeout = 0;
blobmsg_add_u32(b, "timeout", cur_timeout);
}
blobmsg_add_u8(b, "file", e->data.file);
blobmsg_add_u8(b, "user", e->data.user);
buf = blobmsg_alloc_string_buffer(b, "dscp", buf_len);
qosify_map_dscp_codepoint_str(buf, buf_len, e->data.dscp);
blobmsg_add_string_buffer(b);
blobmsg_add_string(b, "type", qosify_map_info[e->data.id].type_name);
switch (e->data.id) {
case CL_MAP_TCP_PORTS:
case CL_MAP_UDP_PORTS:
blobmsg_printf(b, "addr", "%d", ntohs(e->data.addr.port));
break;
case CL_MAP_IPV4_ADDR:
case CL_MAP_IPV6_ADDR:
buf = blobmsg_alloc_string_buffer(b, "addr", buf_len);
af = e->data.id == CL_MAP_IPV6_ADDR ? AF_INET6 : AF_INET;
inet_ntop(af, &e->data.addr, buf, buf_len);
blobmsg_add_string_buffer(b);
break;
case CL_MAP_DNS:
blobmsg_add_string(b, "addr", e->data.addr.dns.pattern);
break;
default:
*buf = 0;
break;
}
blobmsg_close_table(b, c);
}
blobmsg_close_array(b, a);
}
void qosify_map_update_config(void)
{
int fd = qosify_map_fds[CL_MAP_CONFIG];
uint32_t key = 0;
bpf_map_update_elem(fd, &key, &config, BPF_ANY);
}

View File

@@ -1,464 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#define KBUILD_MODNAME "foo"
#include <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/if_packet.h>
#include <uapi/linux/ip.h>
#include <uapi/linux/ipv6.h>
#include <uapi/linux/in.h>
#include <uapi/linux/tcp.h>
#include <uapi/linux/udp.h>
#include <uapi/linux/filter.h>
#include <uapi/linux/pkt_cls.h>
#include <linux/ip.h>
#include <net/ipv6.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
#include "qosify-bpf.h"
#define INET_ECN_MASK 3
#define FLOW_CHECK_INTERVAL ((u32)((1000000000ULL) >> 24))
#define FLOW_TIMEOUT ((u32)((30ULL * 1000000000ULL) >> 24))
#define FLOW_BULK_TIMEOUT 5
#define EWMA_SHIFT 12
const volatile static uint32_t module_flags = 0;
struct flow_bucket {
__u32 last_update;
__u32 pkt_len_avg;
__u16 pkt_count;
__u8 dscp;
__u8 bulk_timeout;
};
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(pinning, 1);
__type(key, __u32);
__type(value, struct qosify_config);
__uint(max_entries, 1);
} config SEC(".maps");
typedef struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(pinning, 1);
__type(key, __u32);
__type(value, __u8);
__uint(max_entries, 1 << 16);
} port_array_t;
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__uint(pinning, 1);
__type(key, __u32);
__uint(value_size, sizeof(struct flow_bucket));
__uint(max_entries, QOSIFY_FLOW_BUCKETS);
} flow_map SEC(".maps");
port_array_t tcp_ports SEC(".maps");
port_array_t udp_ports SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(pinning, 1);
__uint(key_size, sizeof(struct in_addr));
__type(value, struct qosify_ip_map_val);
__uint(max_entries, 100000);
__uint(map_flags, BPF_F_NO_PREALLOC);
} ipv4_map SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(pinning, 1);
__uint(key_size, sizeof(struct in6_addr));
__type(value, struct qosify_ip_map_val);
__uint(max_entries, 100000);
__uint(map_flags, BPF_F_NO_PREALLOC);
} ipv6_map SEC(".maps");
static struct qosify_config *get_config(void)
{
__u32 key = 0;
return bpf_map_lookup_elem(&config, &key);
}
static __always_inline int proto_is_vlan(__u16 h_proto)
{
return !!(h_proto == bpf_htons(ETH_P_8021Q) ||
h_proto == bpf_htons(ETH_P_8021AD));
}
static __always_inline int proto_is_ip(__u16 h_proto)
{
return !!(h_proto == bpf_htons(ETH_P_IP) ||
h_proto == bpf_htons(ETH_P_IPV6));
}
static __always_inline void *skb_ptr(struct __sk_buff *skb, __u32 offset)
{
void *start = (void *)(unsigned long long)skb->data;
return start + offset;
}
static __always_inline void *skb_end_ptr(struct __sk_buff *skb)
{
return (void *)(unsigned long long)skb->data_end;
}
static __always_inline int skb_check(struct __sk_buff *skb, void *ptr)
{
if (ptr > skb_end_ptr(skb))
return -1;
return 0;
}
static __always_inline __u32 cur_time(void)
{
__u32 val = bpf_ktime_get_ns() >> 24;
if (!val)
val = 1;
return val;
}
static __always_inline __u32 ewma(__u32 *avg, __u32 val)
{
if (*avg)
*avg = (*avg * 3) / 4 + (val << EWMA_SHIFT) / 4;
else
*avg = val << EWMA_SHIFT;
return *avg >> EWMA_SHIFT;
}
static __always_inline void
ipv4_change_dsfield(struct iphdr *iph, __u8 mask, __u8 value, bool force)
{
__u32 check = bpf_ntohs(iph->check);
__u8 dsfield;
if ((iph->tos & mask) && !force)
return;
dsfield = (iph->tos & mask) | value;
if (iph->tos == dsfield)
return;
check += iph->tos;
if ((check + 1) >> 16)
check = (check + 1) & 0xffff;
check -= dsfield;
check += check >> 16;
iph->check = bpf_htons(check);
iph->tos = dsfield;
}
static __always_inline void
ipv6_change_dsfield(struct ipv6hdr *ipv6h, __u8 mask, __u8 value, bool force)
{
__u16 *p = (__u16 *)ipv6h;
__u16 val;
if (((*p >> 4) & mask) && !force)
return;
val = (*p & bpf_htons((((__u16)mask << 4) | 0xf00f))) | bpf_htons((__u16)value << 4);
if (val == *p)
return;
*p = val;
}
static __always_inline int
parse_ethernet(struct __sk_buff *skb, __u32 *offset)
{
struct ethhdr *eth;
__u16 h_proto;
int i;
eth = skb_ptr(skb, *offset);
if (skb_check(skb, eth + 1))
return -1;
h_proto = eth->h_proto;
*offset += sizeof(*eth);
#pragma unroll
for (i = 0; i < 2; i++) {
struct vlan_hdr *vlh = skb_ptr(skb, *offset);
if (!proto_is_vlan(h_proto))
break;
if (skb_check(skb, vlh + 1))
return -1;
h_proto = vlh->h_vlan_encapsulated_proto;
*offset += sizeof(*vlh);
}
return h_proto;
}
static void
parse_l4proto(struct qosify_config *config, struct __sk_buff *skb,
__u32 offset, __u8 proto, __u8 *dscp_out)
{
struct udphdr *udp;
__u32 src, dest, key;
__u8 *value;
udp = skb_ptr(skb, offset);
if (skb_check(skb, &udp->len))
return;
if (config && (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6)) {
*dscp_out = config->dscp_icmp;
return;
}
src = udp->source;
dest = udp->dest;
if (module_flags & QOSIFY_INGRESS)
key = src;
else
key = dest;
if (proto == IPPROTO_TCP) {
value = bpf_map_lookup_elem(&tcp_ports, &key);
} else {
if (proto != IPPROTO_UDP)
key = 0;
value = bpf_map_lookup_elem(&udp_ports, &key);
}
if (!value)
return;
*dscp_out = *value;
}
static void
check_flow(struct qosify_config *config, struct __sk_buff *skb,
uint8_t *dscp)
{
struct flow_bucket flow_data;
struct flow_bucket *flow;
__s32 delta;
__u32 hash;
__u32 time;
if (!(*dscp & QOSIFY_DSCP_DEFAULT_FLAG))
return;
if (!config)
return;
if (!config->bulk_trigger_pps &&
!config->prio_max_avg_pkt_len)
return;
time = cur_time();
hash = bpf_get_hash_recalc(skb);
flow = bpf_map_lookup_elem(&flow_map, &hash);
if (!flow) {
memset(&flow_data, 0, sizeof(flow_data));
bpf_map_update_elem(&flow_map, &hash, &flow_data, BPF_ANY);
flow = bpf_map_lookup_elem(&flow_map, &hash);
if (!flow)
return;
}
if (!flow->last_update)
goto reset;
delta = time - flow->last_update;
if ((u32)delta > FLOW_TIMEOUT)
goto reset;
if (delta >= FLOW_CHECK_INTERVAL) {
if (flow->bulk_timeout) {
flow->bulk_timeout--;
if (!flow->bulk_timeout)
flow->dscp = 0xff;
}
goto clear;
}
if (flow->pkt_count < 0xffff)
flow->pkt_count++;
if (config->bulk_trigger_pps &&
flow->pkt_count > config->bulk_trigger_pps) {
flow->dscp = config->dscp_bulk;
flow->bulk_timeout = config->bulk_trigger_timeout;
}
out:
if (config->prio_max_avg_pkt_len &&
flow->dscp != config->dscp_bulk) {
if (ewma(&flow->pkt_len_avg, skb->len) <
config->prio_max_avg_pkt_len)
flow->dscp = config->dscp_prio;
else
flow->dscp = 0xff;
}
if (flow->dscp != 0xff)
*dscp = flow->dscp;
return;
reset:
flow->dscp = 0xff;
flow->pkt_len_avg = 0;
clear:
flow->pkt_count = 1;
flow->last_update = time;
goto out;
}
static __always_inline void
parse_ipv4(struct __sk_buff *skb, __u32 *offset)
{
struct qosify_config *config;
struct qosify_ip_map_val *ip_val;
const __u32 zero_port = 0;
struct iphdr *iph;
__u8 dscp = 0xff;
__u8 *value;
__u8 ipproto;
int hdr_len;
void *key;
bool force;
config = get_config();
iph = skb_ptr(skb, *offset);
if (skb_check(skb, iph + 1))
return;
hdr_len = iph->ihl * 4;
if (bpf_skb_pull_data(skb, *offset + hdr_len + sizeof(struct udphdr)))
return;
iph = skb_ptr(skb, *offset);
*offset += hdr_len;
if (skb_check(skb, (void *)(iph + 1)))
return;
ipproto = iph->protocol;
parse_l4proto(config, skb, *offset, ipproto, &dscp);
if (module_flags & QOSIFY_INGRESS)
key = &iph->saddr;
else
key = &iph->daddr;
ip_val = bpf_map_lookup_elem(&ipv4_map, key);
if (ip_val) {
if (!ip_val->seen)
ip_val->seen = 1;
dscp = ip_val->dscp;
} else if (dscp == 0xff) {
/* use udp port 0 entry as fallback for non-tcp/udp */
value = bpf_map_lookup_elem(&udp_ports, &zero_port);
if (value)
dscp = *value;
}
check_flow(config, skb, &dscp);
force = !(dscp & QOSIFY_DSCP_FALLBACK_FLAG);
dscp &= GENMASK(5, 0);
ipv4_change_dsfield(iph, INET_ECN_MASK, dscp << 2, force);
}
static __always_inline void
parse_ipv6(struct __sk_buff *skb, __u32 *offset)
{
struct qosify_config *config;
struct qosify_ip_map_val *ip_val;
const __u32 zero_port = 0;
struct ipv6hdr *iph;
__u8 dscp = 0;
__u8 *value;
__u8 ipproto;
void *key;
bool force;
config = get_config();
if (bpf_skb_pull_data(skb, *offset + sizeof(*iph) + sizeof(struct udphdr)))
return;
iph = skb_ptr(skb, *offset);
*offset += sizeof(*iph);
if (skb_check(skb, (void *)(iph + 1)))
return;
ipproto = iph->nexthdr;
if (module_flags & QOSIFY_INGRESS)
key = &iph->saddr;
else
key = &iph->daddr;
parse_l4proto(config, skb, *offset, ipproto, &dscp);
ip_val = bpf_map_lookup_elem(&ipv6_map, key);
if (ip_val) {
if (!ip_val->seen)
ip_val->seen = 1;
dscp = ip_val->dscp;
} else if (dscp == 0xff) {
/* use udp port 0 entry as fallback for non-tcp/udp */
value = bpf_map_lookup_elem(&udp_ports, &zero_port);
if (value)
dscp = *value;
}
check_flow(config, skb, &dscp);
force = !(dscp & QOSIFY_DSCP_FALLBACK_FLAG);
dscp &= GENMASK(5, 0);
ipv6_change_dsfield(iph, INET_ECN_MASK, dscp << 2, force);
}
SEC("classifier")
int classify(struct __sk_buff *skb)
{
__u32 offset = 0;
int type;
if (module_flags & QOSIFY_IP_ONLY)
type = skb->protocol;
else
type = parse_ethernet(skb, &offset);
if (type == bpf_htons(ETH_P_IP))
parse_ipv4(skb, &offset);
else if (type == bpf_htons(ETH_P_IPV6))
parse_ipv6(skb, &offset);
return TC_ACT_OK;
}
char _license[] SEC("license") = "GPL";

View File

@@ -1,39 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#ifndef __BPF_QOSIFY_H
#define __BPF_QOSIFY_H
#ifndef QOSIFY_FLOW_BUCKET_SHIFT
#define QOSIFY_FLOW_BUCKET_SHIFT 13
#endif
#define QOSIFY_FLOW_BUCKETS (1 << QOSIFY_FLOW_BUCKET_SHIFT)
/* rodata per-instance flags */
#define QOSIFY_INGRESS (1 << 0)
#define QOSIFY_IP_ONLY (1 << 1)
#define QOSIFY_DSCP_FALLBACK_FLAG (1 << 6)
#define QOSIFY_DSCP_DEFAULT_FLAG (1 << 7)
/* global config data */
struct qosify_config {
uint8_t dscp_prio;
uint8_t dscp_bulk;
uint8_t dscp_icmp;
uint8_t bulk_trigger_timeout;
uint16_t bulk_trigger_pps;
uint16_t prio_max_avg_pkt_len;
};
struct qosify_ip_map_val {
uint8_t dscp; /* must be first */
uint8_t seen;
};
#endif

View File

@@ -1,95 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#ifndef __QOS_CLASSIFY_H
#define __QOS_CLASSIFY_H
#include <stdbool.h>
#include <regex.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "qosify-bpf.h"
#include <libubox/utils.h>
#include <libubox/avl.h>
#include <libubox/blobmsg.h>
#include <libubox/ulog.h>
#include <netinet/in.h>
#define CLASSIFY_PROG_PATH "/lib/bpf/qosify-bpf.o"
#define CLASSIFY_PIN_PATH "/sys/fs/bpf/qosify"
#define CLASSIFY_DATA_PATH "/sys/fs/bpf/qosify_data"
enum qosify_map_id {
CL_MAP_TCP_PORTS,
CL_MAP_UDP_PORTS,
CL_MAP_IPV4_ADDR,
CL_MAP_IPV6_ADDR,
CL_MAP_CONFIG,
CL_MAP_DNS,
__CL_MAP_MAX,
};
struct qosify_map_data {
enum qosify_map_id id;
bool file : 1;
bool user : 1;
uint8_t dscp;
uint8_t file_dscp;
union {
uint32_t port;
struct in_addr ip;
struct in6_addr ip6;
struct {
const char *pattern;
regex_t regex;
} dns;
} addr;
};
struct qosify_map_entry {
struct avl_node avl;
uint32_t timeout;
struct qosify_map_data data;
};
extern int qosify_map_timeout;
extern int qosify_active_timeout;
extern struct qosify_config config;
int qosify_loader_init(void);
int qosify_map_init(void);
int qosify_map_dscp_value(const char *val);
int qosify_map_load_file(const char *file);
int qosify_map_set_entry(enum qosify_map_id id, bool file, const char *str, uint8_t dscp);
void qosify_map_reload(void);
void qosify_map_clear_files(void);
void qosify_map_gc(void);
void qosify_map_dump(struct blob_buf *b);
void qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val);
void qosify_map_reset_config(void);
void qosify_map_update_config(void);
int qosify_map_add_dns_host(const char *host, const char *addr, const char *type, int ttl);
int qosify_iface_init(void);
void qosify_iface_config_update(struct blob_attr *ifaces, struct blob_attr *devs);
void qosify_iface_check(void);
void qosify_iface_status(struct blob_buf *b);
void qosify_iface_stop(void);
int qosify_ubus_init(void);
void qosify_ubus_stop(void);
int qosify_ubus_check_interface(const char *name, char *ifname, int ifname_len);
#endif

View File

@@ -1,416 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
*/
#include <libubus.h>
#include "qosify.h"
static struct blob_buf b;
static int
qosify_ubus_add_array(struct blob_attr *attr, uint8_t val, enum qosify_map_id id)
{
struct blob_attr *cur;
int rem;
if (blobmsg_check_array(attr, BLOBMSG_TYPE_STRING) < 0)
return UBUS_STATUS_INVALID_ARGUMENT;
blobmsg_for_each_attr(cur, attr, rem)
qosify_map_set_entry(id, false, blobmsg_get_string(cur), val);
return 0;
}
static int
qosify_ubus_set_files(struct blob_attr *attr)
{
struct blob_attr *cur;
int rem;
if (blobmsg_check_array(attr, BLOBMSG_TYPE_STRING) < 0)
return UBUS_STATUS_INVALID_ARGUMENT;
qosify_map_clear_files();
blobmsg_for_each_attr(cur, attr, rem)
qosify_map_load_file(blobmsg_get_string(cur));
qosify_map_gc();
return 0;
}
enum {
CL_ADD_DSCP,
CL_ADD_TIMEOUT,
CL_ADD_IPV4,
CL_ADD_IPV6,
CL_ADD_TCP_PORT,
CL_ADD_UDP_PORT,
CL_ADD_DNS,
__CL_ADD_MAX
};
static const struct blobmsg_policy qosify_add_policy[__CL_ADD_MAX] = {
[CL_ADD_DSCP] = { "dscp", BLOBMSG_TYPE_STRING },
[CL_ADD_TIMEOUT] = { "timeout", BLOBMSG_TYPE_INT32 },
[CL_ADD_IPV4] = { "ipv4", BLOBMSG_TYPE_ARRAY },
[CL_ADD_IPV6] = { "ipv6", BLOBMSG_TYPE_ARRAY },
[CL_ADD_TCP_PORT] = { "tcp_port", BLOBMSG_TYPE_ARRAY },
[CL_ADD_UDP_PORT] = { "udp_port", BLOBMSG_TYPE_ARRAY },
[CL_ADD_DNS] = { "dns", BLOBMSG_TYPE_ARRAY },
};
static int
qosify_ubus_reload(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
qosify_map_reload();
return 0;
}
static int
qosify_ubus_add(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int prev_timemout = qosify_map_timeout;
struct blob_attr *tb[__CL_ADD_MAX];
struct blob_attr *cur;
int dscp = -1;
int ret;
blobmsg_parse(qosify_add_policy, __CL_ADD_MAX, tb,
blobmsg_data(msg), blobmsg_len(msg));
if (!strcmp(method, "add")) {
if ((cur = tb[CL_ADD_DSCP]) != NULL)
dscp = qosify_map_dscp_value(blobmsg_get_string(cur));
else
return UBUS_STATUS_INVALID_ARGUMENT;
if (dscp < 0)
return UBUS_STATUS_INVALID_ARGUMENT;
if ((cur = tb[CL_ADD_TIMEOUT]) != NULL)
qosify_map_timeout = blobmsg_get_u32(cur);
} else {
dscp = 0xff;
}
if ((cur = tb[CL_ADD_IPV4]) != NULL &&
(ret = qosify_ubus_add_array(cur, dscp, CL_MAP_IPV4_ADDR) != 0))
return ret;
if ((cur = tb[CL_ADD_IPV6]) != NULL &&
(ret = qosify_ubus_add_array(cur, dscp, CL_MAP_IPV6_ADDR) != 0))
return ret;
if ((cur = tb[CL_ADD_TCP_PORT]) != NULL &&
(ret = qosify_ubus_add_array(cur, dscp, CL_MAP_TCP_PORTS) != 0))
return ret;
if ((cur = tb[CL_ADD_UDP_PORT]) != NULL &&
(ret = qosify_ubus_add_array(cur, dscp, CL_MAP_UDP_PORTS) != 0))
return ret;
if ((cur = tb[CL_ADD_DNS]) != NULL &&
(ret = qosify_ubus_add_array(cur, dscp, CL_MAP_DNS) != 0))
return ret;
qosify_map_timeout = prev_timemout;
return 0;
}
enum {
CL_CONFIG_RESET,
CL_CONFIG_FILES,
CL_CONFIG_TIMEOUT,
CL_CONFIG_DSCP_UDP,
CL_CONFIG_DSCP_TCP,
CL_CONFIG_DSCP_PRIO,
CL_CONFIG_DSCP_BULK,
CL_CONFIG_DSCP_ICMP,
CL_CONFIG_BULK_TIMEOUT,
CL_CONFIG_BULK_PPS,
CL_CONFIG_PRIO_PKT_LEN,
CL_CONFIG_INTERFACES,
CL_CONFIG_DEVICES,
__CL_CONFIG_MAX
};
static const struct blobmsg_policy qosify_config_policy[__CL_CONFIG_MAX] = {
[CL_CONFIG_RESET] = { "reset", BLOBMSG_TYPE_BOOL },
[CL_CONFIG_FILES] = { "files", BLOBMSG_TYPE_ARRAY },
[CL_CONFIG_TIMEOUT] = { "timeout", BLOBMSG_TYPE_INT32 },
[CL_CONFIG_DSCP_UDP] = { "dscp_default_udp", BLOBMSG_TYPE_STRING },
[CL_CONFIG_DSCP_TCP] = { "dscp_default_tcp", BLOBMSG_TYPE_STRING },
[CL_CONFIG_DSCP_PRIO] = { "dscp_prio", BLOBMSG_TYPE_STRING },
[CL_CONFIG_DSCP_BULK] = { "dscp_bulk", BLOBMSG_TYPE_STRING },
[CL_CONFIG_DSCP_ICMP] = { "dscp_icmp", BLOBMSG_TYPE_STRING },
[CL_CONFIG_BULK_TIMEOUT] = { "bulk_trigger_timeout", BLOBMSG_TYPE_INT32 },
[CL_CONFIG_BULK_PPS] = { "bulk_trigger_pps", BLOBMSG_TYPE_INT32 },
[CL_CONFIG_PRIO_PKT_LEN] = { "prio_max_avg_pkt_len", BLOBMSG_TYPE_INT32 },
[CL_CONFIG_INTERFACES] = { "interfaces", BLOBMSG_TYPE_TABLE },
[CL_CONFIG_DEVICES] = { "devices", BLOBMSG_TYPE_TABLE },
};
static int __set_dscp(uint8_t *dest, struct blob_attr *attr, bool reset)
{
int dscp;
if (reset)
*dest = 0xff;
if (!attr)
return 0;
dscp = qosify_map_dscp_value(blobmsg_get_string(attr));
if (dscp < 0)
return -1;
*dest = dscp;
return 0;
}
static int
qosify_ubus_config(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__CL_CONFIG_MAX];
struct blob_attr *cur;
uint8_t dscp;
bool reset = false;
int ret;
blobmsg_parse(qosify_config_policy, __CL_CONFIG_MAX, tb,
blobmsg_data(msg), blobmsg_len(msg));
if ((cur = tb[CL_CONFIG_RESET]) != NULL)
reset = blobmsg_get_bool(cur);
if (reset)
qosify_map_reset_config();
if ((cur = tb[CL_CONFIG_TIMEOUT]) != NULL)
qosify_map_timeout = blobmsg_get_u32(cur);
if ((cur = tb[CL_CONFIG_FILES]) != NULL &&
(ret = qosify_ubus_set_files(cur) != 0))
return ret;
__set_dscp(&dscp, tb[CL_CONFIG_DSCP_UDP], true);
if (dscp != 0xff)
qosify_map_set_dscp_default(CL_MAP_UDP_PORTS, dscp);
__set_dscp(&dscp, tb[CL_CONFIG_DSCP_TCP], true);
if (dscp != 0xff)
qosify_map_set_dscp_default(CL_MAP_TCP_PORTS, dscp);
__set_dscp(&config.dscp_prio, tb[CL_CONFIG_DSCP_PRIO], reset);
__set_dscp(&config.dscp_bulk, tb[CL_CONFIG_DSCP_BULK], reset);
__set_dscp(&config.dscp_icmp, tb[CL_CONFIG_DSCP_ICMP], reset);
if ((cur = tb[CL_CONFIG_BULK_TIMEOUT]) != NULL)
config.bulk_trigger_timeout = blobmsg_get_u32(cur);
if ((cur = tb[CL_CONFIG_BULK_PPS]) != NULL)
config.bulk_trigger_pps = blobmsg_get_u32(cur);
if ((cur = tb[CL_CONFIG_PRIO_PKT_LEN]) != NULL)
config.prio_max_avg_pkt_len = blobmsg_get_u32(cur);
qosify_map_update_config();
qosify_iface_config_update(tb[CL_CONFIG_INTERFACES], tb[CL_CONFIG_DEVICES]);
qosify_iface_check();
return 0;
}
static int
qosify_ubus_dump(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
blob_buf_init(&b, 0);
qosify_map_dump(&b);
ubus_send_reply(ctx, req, b.head);
blob_buf_free(&b);
return 0;
}
static int
qosify_ubus_status(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
blob_buf_init(&b, 0);
qosify_iface_status(&b);
ubus_send_reply(ctx, req, b.head);
blob_buf_free(&b);
return 0;
}
static int
qosify_ubus_check_devices(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
qosify_iface_check();
return 0;
}
enum {
CL_DNS_HOST_NAME,
CL_DNS_HOST_TYPE,
CL_DNS_HOST_ADDR,
CL_DNS_HOST_TTL,
__CL_DNS_HOST_MAX
};
static const struct blobmsg_policy qosify_dns_policy[__CL_DNS_HOST_MAX] = {
[CL_DNS_HOST_NAME] = { "name", BLOBMSG_TYPE_STRING },
[CL_DNS_HOST_TYPE] = { "type", BLOBMSG_TYPE_STRING },
[CL_DNS_HOST_ADDR] = { "address", BLOBMSG_TYPE_STRING },
[CL_DNS_HOST_TTL] = { "ttl", BLOBMSG_TYPE_INT32 },
};
static int
qosify_ubus_add_dns_host(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__CL_DNS_HOST_MAX];
struct blob_attr *cur;
uint32_t ttl = 0;
blobmsg_parse(qosify_dns_policy, __CL_DNS_HOST_MAX, tb,
blobmsg_data(msg), blobmsg_len(msg));
if (!tb[CL_DNS_HOST_NAME] || !tb[CL_DNS_HOST_TYPE] ||
!tb[CL_DNS_HOST_ADDR])
return UBUS_STATUS_INVALID_ARGUMENT;
if ((cur = tb[CL_DNS_HOST_TTL]) != NULL)
ttl = blobmsg_get_u32(cur);
if (qosify_map_add_dns_host(blobmsg_get_string(tb[CL_DNS_HOST_NAME]),
blobmsg_get_string(tb[CL_DNS_HOST_ADDR]),
blobmsg_get_string(tb[CL_DNS_HOST_TYPE]),
ttl))
return UBUS_STATUS_INVALID_ARGUMENT;
return 0;
}
static const struct ubus_method qosify_methods[] = {
UBUS_METHOD_NOARG("reload", qosify_ubus_reload),
UBUS_METHOD("add", qosify_ubus_add, qosify_add_policy),
UBUS_METHOD_MASK("remove", qosify_ubus_add, qosify_add_policy,
((1 << __CL_ADD_MAX) - 1) & ~(1 << CL_ADD_DSCP)),
UBUS_METHOD("config", qosify_ubus_config, qosify_config_policy),
UBUS_METHOD_NOARG("dump", qosify_ubus_dump),
UBUS_METHOD_NOARG("status", qosify_ubus_status),
UBUS_METHOD("add_dns_host", qosify_ubus_add_dns_host, qosify_dns_policy),
UBUS_METHOD_NOARG("check_devices", qosify_ubus_check_devices),
};
static struct ubus_object_type qosify_object_type =
UBUS_OBJECT_TYPE("qosify", qosify_methods);
static struct ubus_object qosify_object = {
.name = "qosify",
.type = &qosify_object_type,
.methods = qosify_methods,
.n_methods = ARRAY_SIZE(qosify_methods),
};
static void
ubus_connect_handler(struct ubus_context *ctx)
{
ubus_add_object(ctx, &qosify_object);
}
static struct ubus_auto_conn conn;
int qosify_ubus_init(void)
{
conn.cb = ubus_connect_handler;
ubus_auto_connect(&conn);
return 0;
}
void qosify_ubus_stop(void)
{
ubus_auto_shutdown(&conn);
}
struct iface_req {
char *name;
int len;
};
static void
netifd_if_cb(struct ubus_request *req, int type, struct blob_attr *msg)
{
struct iface_req *ifr = req->priv;
enum {
IFS_ATTR_UP,
IFS_ATTR_DEV,
__IFS_ATTR_MAX
};
static const struct blobmsg_policy policy[__IFS_ATTR_MAX] = {
[IFS_ATTR_UP] = { "up", BLOBMSG_TYPE_BOOL },
[IFS_ATTR_DEV] = { "l3_device", BLOBMSG_TYPE_STRING },
};
struct blob_attr *tb[__IFS_ATTR_MAX];
blobmsg_parse(policy, __IFS_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
if (!tb[IFS_ATTR_UP] || !tb[IFS_ATTR_DEV])
return;
if (!blobmsg_get_bool(tb[IFS_ATTR_UP]))
return;
snprintf(ifr->name, ifr->len, "%s", blobmsg_get_string(tb[IFS_ATTR_DEV]));
}
int qosify_ubus_check_interface(const char *name, char *ifname, int ifname_len)
{
struct iface_req req = { ifname, ifname_len };
char *obj_name = "network.interface.";
uint32_t id;
#define PREFIX "network.interface."
obj_name = alloca(sizeof(PREFIX) + strlen(name) + 1);
sprintf(obj_name, PREFIX "%s", name);
#undef PREFIX
ifname[0] = 0;
if (ubus_lookup_id(&conn.ctx, obj_name, &id))
return -1;
ubus_invoke(&conn.ctx, id, "status", b.head, netifd_if_cb, &req, 1000);
if (!ifname[0])
return -1;
return 0;
}

View File

@@ -4,9 +4,10 @@ PKG_NAME:=ucentral-client
PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/blogic/ucentral-client.git
PKG_MIRROR_HASH:=37a1b7393cf5d15dbcd4840d9ffb2b16bf5b43cdd5c0da955c744bfc10211cbc
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2022-01-10
PKG_SOURCE_VERSION:=e3b71c61e1a07bb3b5fa34fe835fd8f6f708caa3
PKG_SOURCE_VERSION:=6cb4485ab49c5ab9244fb55af9fd0e1801f154f4
PKG_LICENSE:=BSD-3-Clause
PKG_MAINTAINER:=John Crispin <john@phrozen.org>

View File

@@ -32,8 +32,6 @@ start_service() {
config_get debug 'config' 'debug' 0
config_get insecure 'config' 'insecure' 0
interval=$(uci get ustats.health.interval)
procd_open_instance
procd_set_param command "$PROG"
[ -n "$serial" ] && procd_append_param command -S $serial
@@ -41,7 +39,6 @@ start_service() {
[ -n "$port" ] && procd_append_param command -P $port
[ "$debug" -eq 0 ] || procd_append_param command -d
[ "$insecure" -eq 0 ] || procd_append_param command -i
[ -z "$interval" ] || procd_append_param command -H $interval
[ -z "$(mount | grep 'tmpfs on / type tmpfs')" ] || procd_append_param command -r
procd_append_param command -f "$(cat /tmp/ucentral.version)"
procd_set_param respawn 3600 5 0

View File

@@ -0,0 +1,29 @@
#!/bin/sh /etc/rc.common
START=99
USE_PROCD=1
PROG=/usr/share/ucentral/health.uc
boot() {
# dummy stub to make sure health does not start before
# a config is applied
true
}
service_triggers() {
procd_add_reload_trigger ustats
}
start_service() {
. /lib/functions.sh
config_load 'ustats'
config_get interval 'health' 'interval' 120
[ "$interval" -eq 0 ] || {
procd_open_instance
procd_set_param command "$PROG"
procd_set_param respawn 1 $interval 0
procd_close_instance
}
}

View File

@@ -20,9 +20,4 @@ start_service() {
procd_set_param respawn 1 $interval 0
procd_close_instance
}
config_get interval 'health' 'interval' 0
[ "$interval" -eq 0 ] || {
ubus call ucentral config '{"health": '$interval' }'
}
}

View File

@@ -4,9 +4,10 @@ PKG_NAME:=ucentral-event
PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/blogic/ucentral-event.git
PKG_MIRROR_HASH:=8cb470d7cc6c458fe748ee6f54e4bf79bec5500735d7b992d83c1aa10f700c6b
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2021-04-13
PKG_SOURCE_VERSION:=7b0d136e8556bb099d7032823139d275448714cb
PKG_SOURCE_VERSION:=24b7fb36e456d99b470c212674b3bf50bac64c74
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=BSD-3-Clause

View File

@@ -4,9 +4,10 @@ PKG_NAME:=ucentral-schema
PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/blogic/ucentral-schema.git
PKG_MIRROR_HASH:=af89f22de096e860cfe5295837507d288d7c919d1cb61d7deca012895ed80321
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2022-01-17
PKG_SOURCE_VERSION:=1c4654498b0fbb36f158d1370d3a283d984e746b
PKG_SOURCE_VERSION:=7015febc04ad70a956b1ad79f2911bbdc24458a5
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=BSD-3-Clause

View File

@@ -6,7 +6,7 @@ USE_PROCD=1
PROG=/usr/bin/ucode
start_service() {
local interval=$(uci get onlinecheck.@config.check_interval)
local interval=$(uci get onlinecheck.@config[-1].check_interval)
procd_open_instance
procd_set_param command "$PROG" -m uci -m fs -i /usr/share/ucentral/onlinecheck.uc
procd_set_param respawn 1 $interval 0

View File

@@ -97,7 +97,7 @@
"online-check": {
"ping-hosts": [
"192.168.178.1",
"uecntral.io"
"ucentral.io"
],
"download-hosts": [
"ucentral.io"

View File

@@ -4,6 +4,7 @@ PKG_NAME:=ucentral-tools
PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/blogic/ucentral-tools.git
PKG_MIRROR_HASH:=9ae6a0cd431595871c233550427c4043c2ba7ddb3c5d87e46ab74a03b2b5a947
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2021-01-28
PKG_SOURCE_VERSION:=b013fc636e48d407870a46aaa68a09ed74de8d6f

View File

@@ -4,9 +4,11 @@ PKG_NAME:=ucentral-wifi
PKG_RELEASE:=1
PKG_SOURCE_URL=https://github.com/blogic/ucentral-wifi.git
PKG_MIRROR_HASH:=8e730a37026a37f113038ae27489bb92104d0a091403b7cc1f379188dddd2699
#PKG_MIRROR_HASH:=b6a3bfbd0823c54bb6fb3899e583db8580474a24c1b238d97be152ea8eccf6e5
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2022-01-10
PKG_SOURCE_VERSION:=955fed125e0597dda14cf52fb7224991072d6146
PKG_SOURCE_VERSION:=aa9c3ee716929d75852a11640362a09bb32c5262
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_LICENSE:=BSD-3-Clause

View File

@@ -12,9 +12,9 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=https://github.com/jow-/ucode.git
PKG_MIRROR_HASH:=376b89c35967d3761acb192af9fb6b7b20dbcc50d03c8ed851751d2376bf26b4
PKG_SOURCE_DATE:=2021-07-30
PKG_SOURCE_VERSION:=03b6a8efc1834a4114f0d11e1a7cecff3242b305
PKG_MIRROR_HASH:=6af37293d6d7023f30728c76a02b4e48d323262a45058410760a30256e0dbe2b
PKG_SOURCE_VERSION:=8fd4746da31b945a6259ac846f7cf8dcfef0b1ef
PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
PKG_LICENSE:=ISC

View File

@@ -1,15 +1,15 @@
From eac420899717e2d23f6d13304bd67278a7e91730 Mon Sep 17 00:00:00 2001
From 25df1c3e41f274f70e4fbf5fdc10e4290ba019f5 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 20 Jan 2022 10:48:35 +0100
Subject: [PATCH 1/2] fixes
Subject: [PATCH] fixes
---
lib/nl80211.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++----
lib/nl80211.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++----
lib/rtnl.c | 1 +
2 files changed, 71 insertions(+), 6 deletions(-)
2 files changed, 87 insertions(+), 6 deletions(-)
diff --git a/lib/nl80211.c b/lib/nl80211.c
index fc24fb8..1d0871a 100644
index fc24fb8..3e21141 100644
--- a/lib/nl80211.c
+++ b/lib/nl80211.c
@@ -45,6 +45,8 @@ limitations under the License.
@@ -132,7 +132,7 @@ index fc24fb8..1d0871a 100644
.attrs = {
{ NL80211_STA_INFO_INACTIVE_TIME, "inactive_time", DT_U32, 0, NULL },
{ NL80211_STA_INFO_RX_BYTES, "rx_bytes", DT_U32, 0, NULL },
@@ -724,21 +783,22 @@ static const uc_nl_nested_spec_t nl80211_sta_info_nla = {
@@ -724,21 +783,37 @@ static const uc_nl_nested_spec_t nl80211_sta_info_nla = {
{ NL80211_STA_INFO_NONPEER_PM, "nonpeer_pm", DT_U32, 0, NULL },
{ NL80211_STA_INFO_CHAIN_SIGNAL, "chain_signal", DT_S8, DF_MULTIPLE|DF_AUTOIDX, NULL },
{ NL80211_STA_INFO_CHAIN_SIGNAL_AVG, "chain_signal_avg", DT_S8, DF_MULTIPLE|DF_AUTOIDX, NULL },
@@ -149,25 +149,41 @@ index fc24fb8..1d0871a 100644
{ NL80211_STA_INFO_CONNECTED_TO_AS, "connected_to_as", DT_BOOL, 0, NULL },
{ NL80211_STA_INFO_CONNECTED_TO_GATE, "connected_to_gate", DT_BOOL, 0, NULL },
+ { NL80211_STA_INFO_CONNECTED_TIME, "connected_time", DT_U32, 0, NULL },
+ }
+};
+
+static const uc_nl_nested_spec_t nl80211_survey_info_nla = {
+ .headsize = 0,
+ .nattrs = 8,
+ .attrs = {
+ { NL80211_SURVEY_INFO_FREQUENCY, "frequency", DT_U32, 0, NULL },
+ { NL80211_SURVEY_INFO_TIME, "time", DT_U64, 0, NULL },
+ { NL80211_SURVEY_INFO_TIME_TX, "time_tx", DT_U64, 0, NULL },
+ { NL80211_SURVEY_INFO_TIME_RX, "time_rx", DT_U64, 0, NULL },
+ { NL80211_SURVEY_INFO_TIME_BUSY, "busy", DT_U64, 0, NULL },
+ { NL80211_SURVEY_INFO_TIME_EXT_BUSY, "ext_busy", DT_U64, 0, NULL },
+ { NL80211_SURVEY_INFO_TIME_SCAN, "scan", DT_U64, 0, NULL },
+ { NL80211_SURVEY_INFO_NOISE, "noise", DT_U8, 0, NULL },
}
};
static const uc_nl_nested_spec_t nl80211_msg = {
.headsize = 0,
- .nattrs = 124,
+ .nattrs = 125,
+ .nattrs = 126,
.attrs = {
{ NL80211_ATTR_4ADDR, "4addr", DT_U8, 0, NULL },
{ NL80211_ATTR_AIRTIME_WEIGHT, "airtime_weight", DT_U16, 0, NULL },
@@ -864,6 +924,7 @@ static const uc_nl_nested_spec_t nl80211_msg = {
@@ -864,6 +939,8 @@ static const uc_nl_nested_spec_t nl80211_msg = {
{ NL80211_ATTR_WPA_VERSIONS, "wpa_versions", DT_U32, 0, NULL },
{ NL80211_ATTR_SUPPORTED_IFTYPES, "supported_iftypes", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla },
{ NL80211_ATTR_SOFTWARE_IFTYPES, "software_iftypes", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla },
+ { NL80211_ATTR_MAX_AP_ASSOC_STA, "max_ap_assoc", DT_U16, 0, NULL },
+ { NL80211_ATTR_SURVEY_INFO, "survey_info", DT_NESTED, 0, &nl80211_survey_info_nla },
}
};
@@ -1044,6 +1105,9 @@ uc_nl_parse_attrs(struct nl_msg *msg, char *base, const uc_nl_attr_spec_t *attrs
@@ -1044,6 +1121,9 @@ uc_nl_parse_attrs(struct nl_msg *msg, char *base, const uc_nl_attr_spec_t *attrs
bool exists;
for (i = 0; i < nattrs; i++) {

View File

@@ -1,213 +0,0 @@
From 9c77d85f8e121bf0994eb4bc572eea5cf093f0c6 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Tue, 25 Jan 2022 16:54:48 +0100
Subject: [PATCH] add os library
Signed-off-by: John Crispin <john@phrozen.org>
---
CMakeLists.txt | 7 +++
lib/os.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 174 insertions(+)
create mode 100644 lib/os.c
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7c84fc3..f7d4f83 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -27,6 +27,7 @@ OPTION(RTNL_SUPPORT "Route Netlink plugin support" ON)
OPTION(NL80211_SUPPORT "Wireless Netlink plugin support" ON)
OPTION(RESOLV_SUPPORT "NS resolve plugin support" ON)
OPTION(STRUCT_SUPPORT "Struct plugin support" ON)
+OPTION(OS_SUPPORT "OS plugin support" ON)
SET(LIB_SEARCH_PATH "${CMAKE_INSTALL_PREFIX}/lib/ucode/*.so:${CMAKE_INSTALL_PREFIX}/share/ucode/*.uc:./*.so:./*.uc" CACHE STRING "Default library search path")
STRING(REPLACE ":" "\", \"" LIB_SEARCH_DEFINE "${LIB_SEARCH_PATH}")
@@ -143,6 +144,12 @@ IF(NL80211_SUPPORT)
TARGET_LINK_LIBRARIES(nl80211_lib ${nl})
ENDIF()
+IF(OS_SUPPORT)
+ SET(LIBRARIES ${LIBRARIES} os_lib)
+ ADD_LIBRARY(os_lib MODULE lib/os.c)
+ SET_TARGET_PROPERTIES(os_lib PROPERTIES OUTPUT_NAME os PREFIX "")
+ENDIF()
+
IF(RESOLV_SUPPORT)
SET(LIBRARIES ${LIBRARIES} resolv_lib)
ADD_LIBRARY(resolv_lib MODULE lib/resolv.c)
diff --git a/lib/os.c b/lib/os.c
new file mode 100644
index 0000000..cebad15
--- /dev/null
+++ b/lib/os.c
@@ -0,0 +1,167 @@
+#include <glob.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#include <sys/sysinfo.h>
+
+#include "ucode/module.h"
+
+static regex_t pat_vmdata, pat_vmstk;
+static struct sysinfo info;
+static long systick;
+
+static void __attribute__((constructor))
+measure_init()
+{
+ regcomp(&pat_vmdata, "VmData:[ \t]*([0-9]*) kB", REG_EXTENDED);
+ regcomp(&pat_vmstk, "VmStk:[ \t]*([0-9]*) kB", REG_EXTENDED);
+ sysinfo(&info);
+ systick = sysconf(_SC_CLK_TCK);
+}
+
+static void __attribute__((destructor))
+measure_fini()
+{
+ regfree(&pat_vmdata);
+ regfree(&pat_vmstk);
+}
+
+static char *
+strnchr(char *buf, int c, int i)
+{
+ while (*buf && i) {
+ buf = strchr(buf, c);
+ buf++;
+ i--;
+ }
+ return buf;
+}
+
+static int
+measure_process(uc_value_t *obj, pid_t pid)
+{
+ int fd;
+ char buffer[512] = "";
+ ssize_t rxed;
+ regmatch_t matches[2];
+ glob_t gl;
+ size_t i;
+ char *ch;
+
+ uint32_t fdcount = 0;
+ uint32_t mem = 0;
+
+ snprintf(buffer, sizeof(buffer), "/proc/%i/fd/*", (int)pid);
+
+ if (glob(buffer, GLOB_NOESCAPE | GLOB_MARK, NULL, &gl))
+ return -1;
+
+ for (i = 0; i < gl.gl_pathc; i++)
+ if (isdigit(basename(gl.gl_pathv[i])[0]))
+ fdcount = fdcount + 1;
+ globfree(&gl);
+ ucv_object_add(obj, "fd", ucv_int64_new(fdcount));
+
+ snprintf(buffer, sizeof(buffer), "/proc/%i/stat", (int)pid);
+ fd = open(buffer, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rxed = read(fd, buffer, sizeof(buffer) - 1);
+ close(fd);
+ if (rxed == -1)
+ return -1;
+
+ buffer[rxed] = 0;
+
+ ch = strnchr(buffer, ' ', 14);
+ if (ch)
+ ucv_object_add(obj, "load", ucv_int64_new(atoll(ch)));
+
+ ch = strnchr(buffer, ' ', 21);
+ if (ch)
+ ucv_object_add(obj, "age", ucv_int64_new(info.uptime - atol(ch) / systick));
+
+ snprintf(buffer, sizeof(buffer), "/proc/%i/status", (int)pid);
+ fd = open(buffer, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ rxed = read(fd, buffer, sizeof(buffer) - 1);
+ close(fd);
+ if (rxed == -1)
+ return -1;
+
+ buffer[rxed] = 0;
+
+ if (!regexec(&pat_vmdata, buffer, 2, matches, 0))
+ mem += atoi(buffer + matches[1].rm_so) * 1024;
+
+ if (!regexec(&pat_vmstk, buffer, 2, matches, 0))
+ mem += atoi(buffer + matches[1].rm_so) * 1024;
+
+ ucv_object_add(obj, "memory", ucv_int64_new(mem));
+
+ return 0;
+}
+
+static uc_value_t *
+uc_system_hostname(uc_vm_t *vm, size_t nargs)
+{
+ char buf[255] = {};
+
+ if (gethostname(buf, sizeof(buf)) < 0)
+ return NULL;
+
+ return ucv_string_new(buf);
+}
+
+static uc_value_t *
+uc_system_loadavg(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *res_obj = NULL;
+ int i;
+
+ sysinfo(&info);
+
+ res_obj = ucv_array_new(vm);
+ for (i = 0; i < 3; i++)
+ ucv_array_push(res_obj, ucv_double_new(((double) info.loads[i]) / 65535.0f));
+
+ return res_obj;
+}
+
+static uc_value_t *
+uc_system_process(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *pid = uc_fn_arg(0);
+ uc_value_t *res_obj = NULL;
+
+ if (ucv_type(pid) != UC_INTEGER)
+ return NULL;
+
+ res_obj = ucv_object_new(vm);
+
+ measure_process(res_obj, ucv_uint64_get(pid));
+
+ return res_obj;
+}
+
+static const uc_function_list_t system_fns[] = {
+ { "hostname", uc_system_hostname },
+ { "loadavg", uc_system_loadavg },
+ { "process", uc_system_process },
+};
+
+void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
+{
+ uc_function_list_register(scope, system_fns);
+}
--
2.25.1

View File

@@ -5,6 +5,7 @@ PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=https://github.com/blogic/udevmand.git
PKG_MIRROR_HASH:=25e47c7f3d454cc5eba4e9c19fc9da8431e3c2b1b97b8f0f49798f51c2722df7
PKG_SOURCE_DATE:=20220112
PKG_SOURCE_VERSION:=065f75cb88aa317441adffeddc8d5302cfaafc8a
CMAKE_INSTALL:=1

View File

@@ -7,6 +7,7 @@ PKG_LICENSE:=GPL-2.0
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_SOURCE_URL=https://github.com/blogic/udhcpsnoop.git
PKG_MIRROR_HASH:=721f005e51c46b9381f3e5a6576b8a31afd3903ddb0e7b569d7337a57ca33dd2
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2021-04-12
PKG_SOURCE_VERSION:=b86639904147a40be32ac43cd89c21109ffc3543

View File

@@ -7,6 +7,7 @@ PKG_LICENSE:=GPL-2.0
PKG_MAINTAINER:=John Crispin <john@phrozen.org>
PKG_SOURCE_URL=https://github.com/blogic/udnssnoop.git
PKG_MIRROR_HASH:=afd17cc6aed4a151bc0f437b84491d751932a39f93f429418200e9e8be53dfad
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2021-04-12
PKG_SOURCE_VERSION:=67e1e5f0bfc12222aa59c54e7066b1c00a680e56

View File

@@ -4,6 +4,7 @@ PKG_NAME:=usteer
PKG_RELEASE:=1
PKG_SOURCE_URL=https://git.openwrt.org/project/usteer.git
PKG_MIRROR_HASH:=34a9f2867b3e9050d4707b986481681f97f6fad71bc3fb3276fa3c3b26e2ab67
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2021-04-19
PKG_SOURCE_VERSION:=f42bf2962edd0199e4c96ebf19933b2846bcce27

View File

@@ -7,6 +7,7 @@ PKG_LICENSE:=GPLv2
PKG_LICENSE_FILES:=
PKG_SOURCE_URL:=https://github.com/greearb/ath10k-ct.git
PKG_MIRROR_HASH:=37b4f00231cb0ae00f63da1c94ae53c940c76d047ce0fb081c08a35fffbfd2c0
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2021-05-22b
PKG_SOURCE_VERSION:=54a9ac02f1139596ea4361ebbc3e444955d86cfd

View File

@@ -132,7 +132,7 @@ mac80211_hostapd_setup_base() {
json_select config
[ "$auto_channel" -gt 0 ] && channel=acs_survey
[ "$auto_channel" -gt 0 ] && channel=0
[ "$auto_channel" -gt 0 ] && json_get_vars acs_exclude_dfs
[ -n "$acs_exclude_dfs" ] && [ "$acs_exclude_dfs" -gt 0 ] &&
@@ -1162,10 +1162,13 @@ drv_mac80211_setup() {
if [ "$no_reload" != "0" ]; then
add_ap=1
ubus wait_for hostapd
local hostapd_res="$(ubus call hostapd config_add "{\"iface\":\"$primary_ap\", \"config\":\"${hostapd_conf_file}\"}")"
local hostapd_res
[ -f /tmp/wifi_fail_test ] || hostapd_res="$(ubus call hostapd config_add "{\"iface\":\"$primary_ap\", \"config\":\"${hostapd_conf_file}\"}")"
ret="$?"
rm -f /tmp/wifi_fail_test
[ "$ret" != 0 -o -z "$hostapd_res" ] && {
wireless_setup_failed HOSTAPD_START_FAILED
logger failed to start wifi trying again
# wireless_setup_failed HOSTAPD_START_FAILED
return
}
wireless_add_process "$(jsonfilter -s "$hostapd_res" -l 1 -e @.pid)" "/usr/sbin/hostapd" 1 1

View File

@@ -0,0 +1,45 @@
include $(TOPDIR)/rules.mk
PKG:=ath11k-fwtest
PKG_NAME:=$(PKG)
PKG_VERSION:=1.0
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG)
include $(INCLUDE_DIR)/package.mk
define Package/ath11k-fwtest
SECTION:=QCA
CATEGORY:=QCA
URL:=http://www.qca.qualcomm.com
MAINTAINER:=Qualcomm Atheros, Inc.
TITLE:=QCA ath11k fwtest utility
DEPENDS:= +libnl
endef
define Package/ath11k-fwtest/description
This Package contains ath11k fwtest utility
endef
TARGET_CFLAGS += -O1 -Wall -fpie -I. -I$(STAGING_DIR)/usr/include/ -I $(STAGING_DIR)/usr/include/mac80211/uapi -I $(STAGING_DIR)/usr/include/libnl3
TARGET_LDFLAGS += -lnl-3 -lnl-genl-3
define Build/Compile
mkdir -p $(PKG_BUILD_DIR)/install/sbin
$(MAKE) -C $(PKG_BUILD_DIR)/ \
CC="$(TARGET_CC)" \
CFLAGS="$(TARGET_CFLAGS)" \
LDFLAGS="$(TARGET_LDFLAGS)"
endef
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/ath11k-fwtest $(1)/usr/sbin
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/ath11k-fwtest $(1)/usr/sbin
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@@ -0,0 +1,29 @@
# Makefile for ath11k-fwtest
ALL=ath11k-fwtest
OBJS = fwtest.o
# Making default targets:
all: local install
@echo All done in `pwd`
local : $(ALL)
@echo Made outputs in `pwd`
install: local
@cp -a -f ath11k-fwtest ./install/sbin
@echo Installed outputs from `pwd`
fwtest.o : fwtest.c
$(CC) -c $(CFLAGS) fwtest.c
ath11k-fwtest: $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $@
# Remove all generated files
clean:
@rm -f *.o
.PHONY: all clean install

View File

@@ -0,0 +1,429 @@
/*
* Copyright (c) 2014, 2019 Qualcomm Technologies, Inc.
*
* All Rights Reserved.
* Confidential and Proprietary - Qualcomm Technologies, Inc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <linux/nl80211.h>
#include <linux/netlink.h>
#include <net/if.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/family.h>
#include <netlink/genl/ctrl.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
#define ATH11K_TM_DATA_MAX_LEN 5000
#define ATH11K_WMI_UNIT_TEST_MAX_NUM_ARGS 100
#define WMI_TAG_ARRAY_UINT32 16
#define WMI_TAG_VDEV_SET_PARAM_CMD 95
#define WMI_TAG_PDEV_SET_PARAM_CMD 82
#define WMI_TAG_UNIT_TEST_CMD 327
#define WMI_TLV_HDR_SIZE (sizeof(unsigned int))
#define WMI_TLV_LEN_SHIFT 0
#define WMI_TLV_LEN_MASK 0x0000ffff
#define WMI_TLV_TAG_SHIFT 16
#define WMI_TLV_TAG_MASK 0xffff0000
#define FIELD_PREP(a, b) (((a) << (b##_SHIFT)) & (b##_MASK))
#define WMI_GRP_FWTEST 0x1f
#define WMI_GRP_PDEV 0x04
#define WMI_GRP_VDEV 0x05
#define WMI_TLV_CMD(grp_id) (((grp_id) << 12) | 0x1)
#define WMI_UNIT_TEST_CMDID (WMI_TLV_CMD(WMI_GRP_FWTEST) + 2)
#define WMI_VDEV_SET_PARAM_CMDID (WMI_TLV_CMD(WMI_GRP_VDEV) + 7)
#define WMI_PDEV_SET_PARAM_CMDID (WMI_TLV_CMD(WMI_GRP_PDEV) + 2)
enum ath11k_tm_attr {
__ATH11K_TM_ATTR_INVALID = 0,
ATH11K_TM_ATTR_CMD = 1,
ATH11K_TM_ATTR_DATA = 2,
ATH11K_TM_ATTR_WMI_CMDID = 3,
ATH11K_TM_ATTR_VERSION_MAJOR = 4,
ATH11K_TM_ATTR_VERSION_MINOR = 5,
ATH11K_TM_ATTR_WMI_OP_VERSION = 6,
/* keep last */
__ATH11K_TM_ATTR_AFTER_LAST,
ATH11K_TM_ATTR_MAX = __ATH11K_TM_ATTR_AFTER_LAST - 1,
};
/* All ath11k testmode interface commands specified in
* ATH11K_TM_ATTR_CMD
*/
enum ath11k_tm_cmd {
/* Returns the supported ath11k testmode interface version in
* ATH11K_TM_ATTR_VERSION. Always guaranteed to work. User space
* uses this to verify it's using the correct version of the
* testmode interface
*/
ATH11K_TM_CMD_GET_VERSION = 0,
/* Boots the UTF firmware, the netdev interface must be down at the
* time.
*/
ATH11K_TM_CMD_TESTMODE_START = 1,
/* Shuts down the UTF firmware and puts the driver back into OFF
* state.
*/
ATH11K_TM_CMD_TESTMODE_STOP = 2,
/* The command used to transmit a FW test WMI command to the firmware
* and the event to receive WMI events from the firmware. Without
* struct wmi_cmd_hdr header, only the WMI payload. Command id is
* provided with ATH11K_TM_ATTR_WMI_CMDID and payload in
* ATH11K_TM_ATTR_DATA.
*/
ATH11K_TM_CMD_WMI_FW_TEST = 3,
/* The command used to transmit a FTM WMI command to the firmware
* and the event to receive WMI events from the firmware.The data
* received only contain the payload, Need to add the tlv
* header and send the cmd to fw with commandid WMI_PDEV_UTF_CMDID.
*/
ATH11K_TM_CMD_WMI_FTM = 4,
};
struct nl80211_socket_info {
struct nl_sock *nl_sock;
int genl_family_id;
};
struct wmi_unit_test_cmd {
unsigned int tlv_header;
unsigned int vdev_id;
unsigned int module_id;
unsigned int num_args;
unsigned int diag_token;
};
struct wmi_vdev_pdev_set_param_cmd {
unsigned int tlv_header;
unsigned int vdev_pdev_id;
unsigned int param_id;
unsigned int param_value;
};
enum wmi_unit_test_cmd_type {
ATH11K_WMI_FW_UNIT_TEST_CMD,
ATH11K_WMI_VDEV_SET_PARAM_CMD,
ATH11K_WMI_PDEV_SET_PARAM_CMD,
};
int init_nl_sock(struct nl80211_socket_info *sock)
{
int ret;
sock->nl_sock = nl_socket_alloc();
if (!sock->nl_sock) {
fprintf(stderr, "Failed to create nl socket\n");
return -ENOMEM;
}
if (genl_connect(sock->nl_sock)) {
fprintf(stderr, "Failed to connect to nl socket\n");
ret = -ENOLINK;
goto free_nl_sock;
}
nl_socket_set_buffer_size(sock->nl_sock, 0, ATH11K_TM_DATA_MAX_LEN);
sock->genl_family_id = genl_ctrl_resolve(sock->nl_sock, "nl80211");
if (sock->genl_family_id < 0) {
fprintf(stderr, "genl family not found!!\n");
ret = -ENOENT;
goto free_nl_sock;
}
return 0;
free_nl_sock:
nl_socket_free(sock->nl_sock);
return ret;
}
void usage(char *argv[])
{
fprintf(stderr, "Usage: %s -t <cmd type> -i <wlanX> -m <moduleid> -v <vdevid> <argument list>\n",
argv[0]);
}
static int nl_cb_error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
{
int *ret = arg;
*ret = err->error;
return NL_STOP;
}
static int nl_cb_finish_handler(struct nl_msg *msg, void *arg)
{
int *ret = arg;
*ret = 0;
return NL_SKIP;
}
static int nl_cb_ack_handler(struct nl_msg *msg, void *arg)
{
int *ret = arg;
*ret = 0;
return NL_STOP;
}
void *ath11k_fwtest_fill_cmd_buf(unsigned int module_id, unsigned int vdev_id,
int num_args, char *argv[], int optind, int *buf_sz)
{
struct wmi_unit_test_cmd *cmd;
unsigned int *buf;
int buf_size, i;
buf_size = sizeof(struct wmi_unit_test_cmd) + WMI_TLV_HDR_SIZE + num_args * sizeof(unsigned int);
*buf_sz = buf_size;
buf = (unsigned int *) malloc(buf_size);
if (!buf) {
fprintf(stderr, "Failed to allocate memory\n");
return NULL;
}
memset((void *)buf, 0, buf_size);
cmd = (struct wmi_unit_test_cmd *) buf;
cmd->tlv_header = FIELD_PREP(WMI_TAG_UNIT_TEST_CMD, WMI_TLV_TAG) |
FIELD_PREP(sizeof(struct wmi_unit_test_cmd) - WMI_TLV_HDR_SIZE, WMI_TLV_LEN);
cmd->module_id = module_id;
cmd->vdev_id = vdev_id;
cmd->num_args = num_args;
cmd->diag_token = 0;
buf = (unsigned int *)((char *)buf + sizeof(struct wmi_unit_test_cmd));
*buf = FIELD_PREP(WMI_TAG_ARRAY_UINT32, WMI_TLV_TAG) |
FIELD_PREP(num_args * sizeof(unsigned int), WMI_TLV_LEN);
buf++;
for (i = 0; i < num_args; i++, buf++)
*buf = strtoul(argv[optind + i], NULL, 0);
return cmd;
}
void *ath11k_wmi_vdev_pdev_set_cmd_fill_buf(unsigned int type, unsigned int vdev_pdev_id,
char *argv[], int optind, int *buf_sz)
{
struct wmi_vdev_pdev_set_param_cmd *cmd;
unsigned int *buf;
int buf_size;
int tag;
buf_size = sizeof(struct wmi_vdev_pdev_set_param_cmd);
*buf_sz = buf_size;
buf = (unsigned int *) malloc(buf_size);
if (!buf) {
fprintf(stderr, "Failed to allocate memory\n");
return NULL;
}
memset((void *)buf, 0, buf_size);
cmd = (struct wmi_vdev_pdev_set_param_cmd *) buf;
if (type == ATH11K_WMI_VDEV_SET_PARAM_CMD)
tag = WMI_TAG_VDEV_SET_PARAM_CMD;
else
tag = WMI_TAG_PDEV_SET_PARAM_CMD;
cmd->tlv_header = FIELD_PREP(tag, WMI_TLV_TAG) |
FIELD_PREP(sizeof(struct wmi_vdev_pdev_set_param_cmd) - WMI_TLV_HDR_SIZE, WMI_TLV_LEN);
cmd->vdev_pdev_id = vdev_pdev_id;
cmd->param_id = strtoul(argv[optind], NULL, 0);
cmd->param_value = strtoul(argv[optind + 1], NULL, 0);
return cmd;
}
int main(int argc, char *argv[])
{
struct nl80211_socket_info sock;
void *cmd = NULL;
struct nl_msg *msg;
struct nlattr *nest;
struct nl_cb *cb;
unsigned int cmd_id;
char *ifname = NULL;
int netdev_idx;
unsigned int module_id = UINT_MAX;
unsigned int vdev_id = UINT_MAX;
unsigned int pdev_id = UINT_MAX;
unsigned int type = ATH11K_WMI_FW_UNIT_TEST_CMD;
int num_args;
int buf_size;
int opt;
int ret = 1;
while (1) {
opt = getopt(argc, argv, "t:i:m:v:p:h");
if (opt < 0)
break;
switch (opt) {
case 'i':
ifname = optarg;
break;
case 't':
type = strtoul(optarg, NULL, 0);
break;
case 'm':
module_id = strtoul(optarg, NULL, 0);
break;
case 'v':
vdev_id = strtoul(optarg, NULL, 0);
break;
case 'p':
pdev_id = strtoul(optarg, NULL, 0);
break;
case 'h':
/* fall through */
default:
usage(argv);
return ret;
}
}
if (!ifname || module_id == UINT_MAX ||
(type != ATH11K_WMI_PDEV_SET_PARAM_CMD && vdev_id == UINT_MAX)) {
fprintf(stderr, "Mandatory options are missing!!\n");
usage(argv);
return -EINVAL;
}
if (optind >= argc) {
fprintf(stderr, "Argument list missing!!\n");
usage(argv);
return ret;
}
num_args = argc - optind;
if (num_args > ATH11K_WMI_UNIT_TEST_MAX_NUM_ARGS) {
fprintf(stderr, "Arguments exceeded max limit, limit:%d\n",
ATH11K_WMI_UNIT_TEST_MAX_NUM_ARGS);
return ret;
}
netdev_idx = if_nametoindex(ifname);
if (!netdev_idx) {
fprintf(stderr, "%s not found\n", ifname);
return -ENOENT;
}
ret = init_nl_sock(&sock);
if (ret < 0) {
fprintf(stderr, "Failed to initialize nl socket\n");
return ret;
}
msg = nlmsg_alloc();
if (!msg) {
fprintf(stderr, "Failed to allocate nl message\n");
ret = -ENOMEM;
goto free_nl_sock;
}
cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!cb) {
fprintf(stderr, "failed to allocate netlink callback\n");
ret = -ENOMEM;
goto free_nl_msg;
}
switch (type) {
case ATH11K_WMI_FW_UNIT_TEST_CMD:
cmd = ath11k_fwtest_fill_cmd_buf(module_id, vdev_id, num_args, argv, optind, &buf_size);
cmd_id = WMI_UNIT_TEST_CMDID;
break;
case ATH11K_WMI_VDEV_SET_PARAM_CMD:
cmd = ath11k_wmi_vdev_pdev_set_cmd_fill_buf(type, vdev_id, argv, optind, &buf_size);
cmd_id = WMI_VDEV_SET_PARAM_CMDID;
break;
case ATH11K_WMI_PDEV_SET_PARAM_CMD:
if (pdev_id == 0 || pdev_id == UINT_MAX)
break;
cmd = ath11k_wmi_vdev_pdev_set_cmd_fill_buf(type, pdev_id, argv, optind, &buf_size);
cmd_id = WMI_PDEV_SET_PARAM_CMDID;
break;
default:
fprintf(stderr, "Unknown fw unittest type\n");
ret = -EINVAL;
goto free_nl_msg;
}
if (!cmd) {
fprintf(stderr, "failed to fill cmd buffer, please check inputs\n");
ret = -EINVAL;
goto free_nl_msg;
}
genlmsg_put(msg, 0, 0, sock.genl_family_id, 0, 0,
NL80211_CMD_TESTMODE, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev_idx);
nest = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
if (!nest) {
fprintf(stderr, "Failed to nest test input\n");
ret = -ENOMEM;
goto free_cmd_buf;
}
NLA_PUT_U32(msg, ATH11K_TM_ATTR_CMD, ATH11K_TM_CMD_WMI_FW_TEST);
NLA_PUT_U32(msg, ATH11K_TM_ATTR_WMI_CMDID, cmd_id);
NLA_PUT(msg, ATH11K_TM_ATTR_DATA, buf_size, cmd);
nla_nest_end(msg, nest);
ret = nl_send_auto_complete(sock.nl_sock, msg);
if (ret < 0) {
fprintf(stderr, "Failed to send nl msg: %d\n", ret);
goto free_cmd_buf;
}
ret = 1;
nl_cb_err(cb, NL_CB_CUSTOM, nl_cb_error_handler, &ret);
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl_cb_finish_handler, &ret);
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl_cb_ack_handler, &ret);
while (ret > 0)
nl_recvmsgs(sock.nl_sock, cb);
if (ret < 0)
fprintf(stderr, "command failed: %s (%d)\n", strerror(-ret), ret);
goto free_cmd_buf;
nla_put_failure:
fprintf(stderr, "nl put operation failed!!\n");
free_cmd_buf:
free(cmd);
nl_cb_put(cb);
free_nl_msg:
nlmsg_free(msg);
free_nl_sock:
nl_socket_free(sock.nl_sock);
return ret;
}

View File

@@ -31,13 +31,15 @@ ALLWIFIBOARDS:= \
cig-wf196 \
cybertan-eww622-a1 \
edgecore-eap101 \
gl-ax1800 \
sercomm-wallaby \
edgecore-eap102 \
edgecore-eap104 \
wallys-dr6018 \
wallys-dr6018-v4 \
tplink-ex227 \
tplink-ex447
tplink-ex447 \
yuncore-ax840
ALLWIFIPACKAGES:=$(foreach BOARD,$(ALLWIFIBOARDS),ath11k-wifi-$(BOARD))
@@ -79,6 +81,11 @@ $(call Package/ath11k-wifi-default)
TITLE:=cig-wf196 6G bdf
endef
define Package/ath11k-wifi-gl-ax1800
$(call Package/ath11k-wifi-default)
TITLE:=gl-ax1800 bdf
endef
define ath11k-wifi-install-one-to
$(INSTALL_DIR) $(2)/lib/firmware/$(3)/
$(INSTALL_DATA) $(1) $(2)/lib/firmware/$(3)/board.bin
@@ -161,6 +168,11 @@ define Package/ath11k-wifi-cig-wf196_6g/install
$(INSTALL_DATA) ./board-cig-wf196_6g.bin.QCN9074 $(1)/lib/firmware/ath11k/QCN9074/hw1.0/board.bin
endef
define Package/ath11k-wifi-gl-ax1800/install
$(INSTALL_DIR) $(1)/lib/firmware/ath11k/IPQ6018/hw1.0/
$(INSTALL_DATA) ./board-gl-ax1800.bin.IPQ6018 $(1)/lib/firmware/ath11k/IPQ6018/hw1.0/board-2.bin
endef
$(eval $(call generate-ath11k-wifi-package,cig-wf188,Cigtech WF188))
$(eval $(call generate-ath11k-wifi-package,cig-wf188n,Cigtech WF188n))
$(eval $(call generate-ath11k-wifi-package,cig-wf194c,Cigtech WF194c))
@@ -175,6 +187,7 @@ $(eval $(call generate-ath11k-wifi-package,edgecore-eap102,Edgecore EAP102))
$(eval $(call generate-ath11k-wifi-package,edgecore-eap104,Edgecore EAP104))
$(eval $(call generate-ath11k-wifi-package,tplink-ex227,TP-Link EX227))
$(eval $(call generate-ath11k-wifi-package,tplink-ex447,TP-Link EX447))
$(eval $(call generate-ath11k-wifi-package,yuncore-ax840,YunCore AX840))
$(foreach PACKAGE,$(ALLWIFIPACKAGES),$(eval $(call BuildPackage,$(PACKAGE))))
$(eval $(call BuildPackage,ath11k-wifi-qcom-ipq5018))

Binary file not shown.

View File

@@ -61,6 +61,7 @@ PKG_EXTRA_CFLAGS:= \
$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(PKG_EXTRA_KCONFIG)))) \
NOSTDINC_FLAGS = \
$(KERNEL_NOSTDINC_FLAGS) \
-I$(PKG_BUILD_DIR)/net/batman-adv \
-I$(STAGING_DIR)/usr/include/mac80211-backport \
-I$(STAGING_DIR)/usr/include/mac80211-backport/uapi \

View File

@@ -12,11 +12,9 @@ or newer - otherwise it will not work as expected.
This reverts commit 725b4ef5be840cfcd0ca33b9393c14dee40c10f7.
diff --git a/compat-include/net/genetlink.h b/compat-include/net/genetlink.h
index 56a9ab22c062b1d0d01ef9d09ce796075d3d6df7..8f542bef10dc0f2682ab2d428c90df9ab97977ce 100644
--- a/compat-include/net/genetlink.h
+++ b/compat-include/net/genetlink.h
@@ -31,17 +31,15 @@ void batadv_genl_dump_check_consistent(struct netlink_callback *cb,
@@ -31,17 +31,15 @@ void batadv_genl_dump_check_consistent(s
#endif /* LINUX_VERSION_IS_LESS(4, 15, 0) */
@@ -48,7 +46,7 @@ index 56a9ab22c062b1d0d01ef9d09ce796075d3d6df7..8f542bef10dc0f2682ab2d428c90df9a
unsigned int n_mcgrps;
struct module *module;
@@ -96,32 +94,24 @@ static inline int batadv_genl_register_family(struct batadv_genl_family *family)
@@ -96,32 +94,24 @@ static inline int batadv_genl_register_f
family->family.pre_doit = family->pre_doit;
family->family.post_doit = family->post_doit;
family->family.mcgrps = family->mcgrps;
@@ -89,7 +87,7 @@ index 56a9ab22c062b1d0d01ef9d09ce796075d3d6df7..8f542bef10dc0f2682ab2d428c90df9a
family->family.ops = ops;
family->copy_ops = ops;
@@ -136,7 +126,7 @@ typedef struct genl_ops batadv_genl_ops_old;
@@ -136,7 +126,7 @@ typedef struct genl_ops batadv_genl_ops_
#define batadv_post_doit(__x, __y, __z) \
batadv_post_doit(const batadv_genl_ops_old *ops, __y, __z)
@@ -98,7 +96,7 @@ index 56a9ab22c062b1d0d01ef9d09ce796075d3d6df7..8f542bef10dc0f2682ab2d428c90df9a
#define genl_family batadv_genl_family
#define genl_register_family(family) \
@@ -160,6 +150,6 @@ batadv_genl_unregister_family(struct batadv_genl_family *family)
@@ -160,6 +150,6 @@ batadv_genl_unregister_family(struct bat
genlmsg_multicast_netns(&(_family)->family, _net, _skb, _portid, \
_group, _flags)
@@ -106,11 +104,9 @@ index 56a9ab22c062b1d0d01ef9d09ce796075d3d6df7..8f542bef10dc0f2682ab2d428c90df9a
+#endif /* LINUX_VERSION_IS_LESS(5, 2, 0) */
#endif /* _NET_BATMAN_ADV_COMPAT_NET_GENETLINK_H_ */
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index f317d206b411d87b4da2f57e35c3fb78cedfb160..bdac5dbd899a9540d58052fd32c8c89520927390 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -1351,7 +1351,7 @@ static void batadv_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
@@ -1351,7 +1351,7 @@ static void batadv_post_doit(const struc
}
}
@@ -119,7 +115,7 @@ index f317d206b411d87b4da2f57e35c3fb78cedfb160..bdac5dbd899a9540d58052fd32c8c895
{
.cmd = BATADV_CMD_GET_MESH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -1485,8 +1485,8 @@ struct genl_family batadv_netlink_family __ro_after_init = {
@@ -1485,8 +1485,8 @@ struct genl_family batadv_netlink_family
.pre_doit = batadv_pre_doit,
.post_doit = batadv_post_doit,
.module = THIS_MODULE,

View File

@@ -9,9 +9,6 @@ This reverts commit 1810de05310d5c5e9140f870ac21052f38bc06b8.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
diff --git a/compat-include/linux/minmax.h b/compat-include/linux/minmax.h
deleted file mode 100644
index 9b7269e8a760361c1650b947c77702f0bdcd73d9..0000000000000000000000000000000000000000
--- a/compat-include/linux/minmax.h
+++ /dev/null
@@ -1,20 +0,0 @@
@@ -35,8 +32,6 @@ index 9b7269e8a760361c1650b947c77702f0bdcd73d9..00000000000000000000000000000000
-#endif
-
-#endif /* _NET_BATMAN_ADV_COMPAT_LINUX_MINMAX_H_ */
diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c
index e1ca2b8c315235f234c9061fc73cde2c1b76aa46..eeb3f6d00d8541b377c9703837ef76b05e8d061e 100644
--- a/net/batman-adv/bat_v.c
+++ b/net/batman-adv/bat_v.c
@@ -15,7 +15,6 @@
@@ -47,8 +42,6 @@ index e1ca2b8c315235f234c9061fc73cde2c1b76aa46..eeb3f6d00d8541b377c9703837ef76b0
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/rculist.h>
diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c
index 423c2d17170387bfe89b83c4e20f06d525a36b30..4d8e3fdb4427a431cab903bc8a20edb816079fd7 100644
--- a/net/batman-adv/bat_v_elp.c
+++ b/net/batman-adv/bat_v_elp.c
@@ -18,7 +18,6 @@
@@ -59,8 +52,6 @@ index 423c2d17170387bfe89b83c4e20f06d525a36b30..4d8e3fdb4427a431cab903bc8a20edb8
#include <linux/netdevice.h>
#include <linux/nl80211.h>
#include <linux/prandom.h>
diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
index a0a9636d17406362f879f342300a18e75424efa5..89ba88322c9c11acc49a9dcd9877ad8767fe713b 100644
--- a/net/batman-adv/bat_v_ogm.c
+++ b/net/batman-adv/bat_v_ogm.c
@@ -18,7 +18,6 @@
@@ -71,8 +62,6 @@ index a0a9636d17406362f879f342300a18e75424efa5..89ba88322c9c11acc49a9dcd9877ad87
#include <linux/mutex.h>
#include <linux/netdevice.h>
#include <linux/prandom.h>
diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c
index a5d9d800082bade3a1d52cc040557e41f963fac3..96873d47fac5cb9b4fbfa217eedf1f92818b0e98 100644
--- a/net/batman-adv/fragmentation.c
+++ b/net/batman-adv/fragmentation.c
@@ -14,8 +14,8 @@
@@ -85,8 +74,6 @@ index a5d9d800082bade3a1d52cc040557e41f963fac3..96873d47fac5cb9b4fbfa217eedf1f92
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 4a6a25d551a83b1723e80a349e1a655a2152b0ac..eabde547d308438257622879e77d84c24daa2199 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -18,7 +18,6 @@
@@ -97,8 +84,6 @@ index 4a6a25d551a83b1723e80a349e1a655a2152b0ac..eabde547d308438257622879e77d84c2
#include <linux/mutex.h>
#include <linux/netdevice.h>
#include <linux/printk.h>
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 3ddd66e4c29ef532de33c7182cc0cc470b33fd4f..c552bc4168d0abd7bf6d23e570d583806fb162b1 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -23,7 +23,6 @@
@@ -109,8 +94,6 @@ index 3ddd66e4c29ef532de33c7182cc0cc470b33fd4f..c552bc4168d0abd7bf6d23e570d58380
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/printk.h>
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index bdac5dbd899a9540d58052fd32c8c89520927390..b6a703ddd8e97e6a02e8d73c5728802f090ab419 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -23,7 +23,6 @@
@@ -121,8 +104,6 @@ index bdac5dbd899a9540d58052fd32c8c89520927390..b6a703ddd8e97e6a02e8d73c5728802f
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/printk.h>
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index 789c851732b78ad9d1515f7b171219cc770c7045..46b774c08c947def8f72f260224254b01c3a387d 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -23,7 +23,6 @@

View File

@@ -5,11 +5,9 @@ Subject: batman-adv: Fix build of multicast code against Linux < 5.13
Fixes: 007b4c4b031f ("batman-adv: convert ifmcaddr6 to RCU")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 1d63c8cbbfe7b16e360e91bcf3bb77ec7b12893b..ece9fb5dd81bfadbdbe15363dfd8fd257dbe942f 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -454,9 +454,14 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
@@ -454,9 +454,14 @@ batadv_mcast_mla_softif_get_ipv6(struct
return 0;
}
@@ -24,7 +22,7 @@ index 1d63c8cbbfe7b16e360e91bcf3bb77ec7b12893b..ece9fb5dd81bfadbdbe15363dfd8fd25
if (IPV6_ADDR_MC_SCOPE(&pmc6->mca_addr) <
IPV6_ADDR_SCOPE_LINKLOCAL)
continue;
@@ -485,6 +490,9 @@ batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
@@ -485,6 +490,9 @@ batadv_mcast_mla_softif_get_ipv6(struct
hlist_add_head(&new->list, mcast_list);
ret++;
}

View File

@@ -23,11 +23,9 @@ adding a lot of extra overhead in the kernel portion.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/77c7d62618259f22f36427eaa62668e6e1c43090
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 789f257be24f36ace3e63628a3381a6d46dcccd9..680def809838097a9949de1dc9861923911f3d04 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -1849,6 +1849,8 @@ batadv_iv_ogm_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
@@ -1849,6 +1849,8 @@ batadv_iv_ogm_orig_dump_subentry(struct
orig_node->orig) ||
nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
neigh_node->addr) ||
@@ -36,7 +34,7 @@ index 789f257be24f36ace3e63628a3381a6d46dcccd9..680def809838097a9949de1dc9861923
nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
neigh_node->if_incoming->net_dev->ifindex) ||
nla_put_u8(msg, BATADV_ATTR_TQ, tq_avg) ||
@@ -2078,6 +2080,8 @@ batadv_iv_ogm_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq,
@@ -2078,6 +2080,8 @@ batadv_iv_ogm_neigh_dump_neigh(struct sk
if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
hardif_neigh->addr) ||
@@ -45,7 +43,7 @@ index 789f257be24f36ace3e63628a3381a6d46dcccd9..680def809838097a9949de1dc9861923
nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
hardif_neigh->if_incoming->net_dev->ifindex) ||
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
@@ -2459,6 +2463,8 @@ static int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid,
@@ -2459,6 +2463,8 @@ static int batadv_iv_gw_dump_entry(struc
router->addr) ||
nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
router->if_incoming->net_dev->name) ||
@@ -54,11 +52,9 @@ index 789f257be24f36ace3e63628a3381a6d46dcccd9..680def809838097a9949de1dc9861923
nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_DOWN,
gw_node->bandwidth_down) ||
nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_UP,
diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c
index eeb3f6d00d8541b377c9703837ef76b05e8d061e..fd7f30f5f3033fd1a9e21518a71e66b557212374 100644
--- a/net/batman-adv/bat_v.c
+++ b/net/batman-adv/bat_v.c
@@ -145,6 +145,8 @@ batadv_v_neigh_dump_neigh(struct sk_buff *msg, u32 portid, u32 seq,
@@ -145,6 +145,8 @@ batadv_v_neigh_dump_neigh(struct sk_buff
if (nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
hardif_neigh->addr) ||
@@ -67,7 +63,7 @@ index eeb3f6d00d8541b377c9703837ef76b05e8d061e..fd7f30f5f3033fd1a9e21518a71e66b5
nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
hardif_neigh->if_incoming->net_dev->ifindex) ||
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS,
@@ -297,6 +299,8 @@ batadv_v_orig_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
@@ -297,6 +299,8 @@ batadv_v_orig_dump_subentry(struct sk_bu
if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, orig_node->orig) ||
nla_put(msg, BATADV_ATTR_NEIGH_ADDRESS, ETH_ALEN,
neigh_node->addr) ||
@@ -76,24 +72,22 @@ index eeb3f6d00d8541b377c9703837ef76b05e8d061e..fd7f30f5f3033fd1a9e21518a71e66b5
nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
neigh_node->if_incoming->net_dev->ifindex) ||
nla_put_u32(msg, BATADV_ATTR_THROUGHPUT, throughput) ||
@@ -738,6 +742,12 @@ static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid,
@@ -737,6 +741,12 @@ static int batadv_v_gw_dump_entry(struct
genlmsg_cancel(msg, hdr);
goto out;
}
+
+ if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
+ router->if_incoming->net_dev->ifindex)) {
+ genlmsg_cancel(msg, hdr);
+ goto out;
+ }
+
if (nla_put_u32(msg, BATADV_ATTR_BANDWIDTH_DOWN,
gw_node->bandwidth_down)) {
genlmsg_cancel(msg, hdr);
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index b6a703ddd8e97e6a02e8d73c5728802f090ab419..27f78f0c4aea025b964301e20f972031ab8ad478 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -813,6 +813,10 @@ static int batadv_netlink_hardif_fill(struct sk_buff *msg,
@@ -813,6 +813,10 @@ static int batadv_netlink_hardif_fill(st
bat_priv->soft_iface->ifindex))
goto nla_put_failure;
@@ -104,7 +98,7 @@ index b6a703ddd8e97e6a02e8d73c5728802f090ab419..27f78f0c4aea025b964301e20f972031
if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
net_dev->ifindex) ||
nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
@@ -1044,6 +1048,10 @@ static int batadv_netlink_vlan_fill(struct sk_buff *msg,
@@ -1044,6 +1048,10 @@ static int batadv_netlink_vlan_fill(stru
bat_priv->soft_iface->ifindex))
goto nla_put_failure;

View File

@@ -0,0 +1,31 @@
From: Sven Eckelmann <sven@narfation.org>
Date: Tue, 18 May 2021 21:00:27 +0200
Subject: batman-adv: Avoid WARN_ON timing related checks
The soft/batadv interface for a queued OGM can be changed during the time
the OGM was queued for transmission and when the OGM is actually
transmitted by the worker.
But WARN_ON must be used to denote kernel bugs and not to print simple
warnings. A warning can simply be printed using pr_warn.
Reported-by: Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Reported-by: syzbot+c0b807de416427ff3dd1@syzkaller.appspotmail.com
Fixes: 29b9256e6631 ("batman-adv: consider outgoing interface in OGM sending")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/5061f9c502d7101912089d8f4a7866e0a926a49a
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -409,8 +409,10 @@ static void batadv_iv_ogm_emit(struct ba
if (WARN_ON(!forw_packet->if_outgoing))
return;
- if (WARN_ON(forw_packet->if_outgoing->soft_iface != soft_iface))
+ if (forw_packet->if_outgoing->soft_iface != soft_iface) {
+ pr_warn("%s: soft interface switch for queued OGM\n", __func__);
return;
+ }
if (forw_packet->if_incoming->if_status != BATADV_IF_ACTIVE)
return;

View File

@@ -0,0 +1,162 @@
From: Pavel Skripkin <paskripkin@gmail.com>
Date: Sun, 24 Oct 2021 16:13:56 +0300
Subject: batman-adv: fix error handling
Syzbot reported ODEBUG warning in batadv_nc_mesh_free(). The problem was
in wrong error handling in batadv_mesh_init().
Before this patch batadv_mesh_init() was calling batadv_mesh_free() in case
of any batadv_*_init() calls failure. This approach may work well, when
there is some kind of indicator, which can tell which parts of batadv are
initialized; but there isn't any.
All written above lead to cleaning up uninitialized fields. Even if we hide
ODEBUG warning by initializing bat_priv->nc.work, syzbot was able to hit
GPF in batadv_nc_purge_paths(), because hash pointer in still NULL. [1]
To fix these bugs we can unwind batadv_*_init() calls one by one.
It is good approach for 2 reasons: 1) It fixes bugs on error handling
path 2) It improves the performance, since we won't call unneeded
batadv_*_free() functions.
So, this patch makes all batadv_*_init() clean up all allocated memory
before returning with an error to no call correspoing batadv_*_free()
and open-codes batadv_mesh_free() with proper order to avoid touching
uninitialized fields.
Link: https://lore.kernel.org/netdev/000000000000c87fbd05cef6bcb0@google.com/ [1]
Reported-and-tested-by: syzbot+28b0702ada0bf7381f58@syzkaller.appspotmail.com
Fixes: 21e838760727 ("[batman-adv] fix various race conditions during startup & shutdown")
Signed-off-by: Pavel Skripkin <paskripkin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/0631e0825c8129cd3896926da62a09ac00bf13a0
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -1556,10 +1556,14 @@ int batadv_bla_init(struct batadv_priv *
return 0;
bat_priv->bla.claim_hash = batadv_hash_new(128);
- bat_priv->bla.backbone_hash = batadv_hash_new(32);
+ if (!bat_priv->bla.claim_hash)
+ return -ENOMEM;
- if (!bat_priv->bla.claim_hash || !bat_priv->bla.backbone_hash)
+ bat_priv->bla.backbone_hash = batadv_hash_new(32);
+ if (!bat_priv->bla.backbone_hash) {
+ batadv_hash_destroy(bat_priv->bla.claim_hash);
return -ENOMEM;
+ }
batadv_hash_set_lock_class(bat_priv->bla.claim_hash,
&batadv_claim_hash_lock_class_key);
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -189,29 +189,41 @@ int batadv_mesh_init(struct net_device *
bat_priv->gw.generation = 0;
- ret = batadv_v_mesh_init(bat_priv);
- if (ret < 0)
- goto err;
-
ret = batadv_originator_init(bat_priv);
- if (ret < 0)
- goto err;
+ if (ret < 0) {
+ atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
+ goto err_orig;
+ }
ret = batadv_tt_init(bat_priv);
- if (ret < 0)
- goto err;
+ if (ret < 0) {
+ atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
+ goto err_tt;
+ }
+
+ ret = batadv_v_mesh_init(bat_priv);
+ if (ret < 0) {
+ atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
+ goto err_v;
+ }
ret = batadv_bla_init(bat_priv);
- if (ret < 0)
- goto err;
+ if (ret < 0) {
+ atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
+ goto err_bla;
+ }
ret = batadv_dat_init(bat_priv);
- if (ret < 0)
- goto err;
+ if (ret < 0) {
+ atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
+ goto err_dat;
+ }
ret = batadv_nc_mesh_init(bat_priv);
- if (ret < 0)
- goto err;
+ if (ret < 0) {
+ atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING);
+ goto err_nc;
+ }
batadv_gw_init(bat_priv);
batadv_mcast_init(bat_priv);
@@ -221,8 +233,20 @@ int batadv_mesh_init(struct net_device *
return 0;
-err:
- batadv_mesh_free(soft_iface);
+err_nc:
+ batadv_dat_free(bat_priv);
+err_dat:
+ batadv_bla_free(bat_priv);
+err_bla:
+ batadv_v_mesh_free(bat_priv);
+err_v:
+ batadv_tt_free(bat_priv);
+err_tt:
+ batadv_originator_free(bat_priv);
+err_orig:
+ batadv_purge_outstanding_packets(bat_priv, NULL);
+ atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE);
+
return ret;
}
--- a/net/batman-adv/network-coding.c
+++ b/net/batman-adv/network-coding.c
@@ -152,8 +152,10 @@ int batadv_nc_mesh_init(struct batadv_pr
&batadv_nc_coding_hash_lock_class_key);
bat_priv->nc.decoding_hash = batadv_hash_new(128);
- if (!bat_priv->nc.decoding_hash)
+ if (!bat_priv->nc.decoding_hash) {
+ batadv_hash_destroy(bat_priv->nc.coding_hash);
goto err;
+ }
batadv_hash_set_lock_class(bat_priv->nc.decoding_hash,
&batadv_nc_decoding_hash_lock_class_key);
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -4193,8 +4193,10 @@ int batadv_tt_init(struct batadv_priv *b
return ret;
ret = batadv_tt_global_init(bat_priv);
- if (ret < 0)
+ if (ret < 0) {
+ batadv_tt_local_table_free(bat_priv);
return ret;
+ }
batadv_tvlv_handler_register(bat_priv, batadv_tt_tvlv_ogm_handler_v1,
batadv_tt_tvlv_unicast_handler_v1,

View File

@@ -0,0 +1,182 @@
From: Linus Lüssing <linus.luessing@c0d3.blue>
Date: Mon, 1 Nov 2021 21:46:17 +0100
Subject: batman-adv: allow netlink usage in unprivileged containers
Currently, creating a batman-adv interface in an unprivileged LXD
container and attaching secondary interfaces to it with "ip" or "batctl"
works fine. However all batctl debug and configuration commands
fail:
root@container:~# batctl originators
Error received: Operation not permitted
root@container:~# batctl orig_interval
1000
root@container:~# batctl orig_interval 2000
root@container:~# batctl orig_interval
1000
To fix this change the generic netlink permissions from GENL_ADMIN_PERM
to GENL_UNS_ADMIN_PERM. This way a batman-adv interface is fully
maintainable as root from within a user namespace, from an unprivileged
container.
All except one batman-adv netlink setting are per interface and do not
leak information or change settings from the host system and are
therefore save to retrieve or modify as root from within an unprivileged
container.
"batctl routing_algo" / BATADV_CMD_GET_ROUTING_ALGOS is the only
exception: It provides the batman-adv kernel module wide default routing
algorithm. However it is read-only from netlink and an unprivileged
container is still not allowed to modify
/sys/module/batman_adv/parameters/routing_algo. Instead it is advised to
use the newly introduced "batctl if create routing_algo RA_NAME" /
IFLA_BATADV_ALGO_NAME to set the routing algorithm on interface
creation, which already works fine in an unprivileged container.
Cc: Tycho Andersen <tycho@tycho.pizza>
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/055fa41b73ca8dae1c1ed41777e32a8f02e80c82
--- /dev/null
+++ b/compat-include/uapi/linux/genetlink.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) B.A.T.M.A.N. contributors:
+ *
+ * Marek Lindner, Simon Wunderlich
+ *
+ * This file contains macros for maintaining compatibility with older versions
+ * of the Linux kernel.
+ */
+
+#ifndef _NET_BATMAN_ADV_COMPAT_UAPI_LINUX_GENETLINK_H_
+#define _NET_BATMAN_ADV_COMPAT_UAPI_LINUX_GENETLINK_H_
+
+#include <linux/version.h>
+#include_next <uapi/linux/genetlink.h>
+
+#if LINUX_VERSION_IS_LESS(4, 6, 0)
+
+#define GENL_UNS_ADMIN_PERM GENL_ADMIN_PERM
+
+#endif /* LINUX_VERSION_IS_LESS(4, 6, 0) */
+
+#endif /* _NET_BATMAN_ADV_COMPAT_UAPI_LINUX_GENETLINK_H_ */
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -1369,21 +1369,21 @@ static const struct genl_ops batadv_netl
{
.cmd = BATADV_CMD_TP_METER,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = batadv_netlink_tp_meter_start,
.internal_flags = BATADV_FLAG_NEED_MESH,
},
{
.cmd = BATADV_CMD_TP_METER_CANCEL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = batadv_netlink_tp_meter_cancel,
.internal_flags = BATADV_FLAG_NEED_MESH,
},
{
.cmd = BATADV_CMD_GET_ROUTING_ALGOS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_algo_dump,
},
{
@@ -1398,68 +1398,68 @@ static const struct genl_ops batadv_netl
{
.cmd = BATADV_CMD_GET_TRANSTABLE_LOCAL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_tt_local_dump,
},
{
.cmd = BATADV_CMD_GET_TRANSTABLE_GLOBAL,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_tt_global_dump,
},
{
.cmd = BATADV_CMD_GET_ORIGINATORS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_orig_dump,
},
{
.cmd = BATADV_CMD_GET_NEIGHBORS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_hardif_neigh_dump,
},
{
.cmd = BATADV_CMD_GET_GATEWAYS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_gw_dump,
},
{
.cmd = BATADV_CMD_GET_BLA_CLAIM,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_bla_claim_dump,
},
{
.cmd = BATADV_CMD_GET_BLA_BACKBONE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_bla_backbone_dump,
},
{
.cmd = BATADV_CMD_GET_DAT_CACHE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_dat_cache_dump,
},
{
.cmd = BATADV_CMD_GET_MCAST_FLAGS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.dumpit = batadv_mcast_flags_dump,
},
{
.cmd = BATADV_CMD_SET_MESH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = batadv_netlink_set_mesh,
.internal_flags = BATADV_FLAG_NEED_MESH,
},
{
.cmd = BATADV_CMD_SET_HARDIF,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = batadv_netlink_set_hardif,
.internal_flags = BATADV_FLAG_NEED_MESH |
BATADV_FLAG_NEED_HARDIF,
@@ -1475,7 +1475,7 @@ static const struct genl_ops batadv_netl
{
.cmd = BATADV_CMD_SET_VLAN,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
- .flags = GENL_ADMIN_PERM,
+ .flags = GENL_UNS_ADMIN_PERM,
.doit = batadv_netlink_set_vlan,
.internal_flags = BATADV_FLAG_NEED_MESH |
BATADV_FLAG_NEED_VLAN,

View File

@@ -0,0 +1,165 @@
From: Linus Lüssing <linus.luessing@c0d3.blue>
Date: Sat, 1 Jan 2022 06:27:13 +0100
Subject: batman-adv: mcast: don't send link-local multicast to mcast routers
The addition of routable multicast TX handling introduced a
bug/regression for packets with a link-local multicast destination:
These packets would be sent to all batman-adv nodes with a multicast
router and to all batman-adv nodes with an old version without multicast
router detection.
This even disregards the batman-adv multicast fanout setting, which can
potentially lead to an unwanted, high number of unicast transmissions or
even congestion.
Fixing this by avoiding to send link-local multicast packets to nodes in
the multicast router list.
Fixes: 3a8df00cd969 ("batman-adv: mcast: apply optimizations for routable packets, too")
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/ee013870947b9175847aa46a0686ca01dd480af4
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1380,6 +1380,7 @@ batadv_mcast_forw_rtr_node_get(struct ba
* @bat_priv: the bat priv with all the soft interface information
* @skb: The multicast packet to check
* @orig: an originator to be set to forward the skb to
+ * @is_routable: stores whether the destination is routable
*
* Return: the forwarding mode as enum batadv_forw_mode and in case of
* BATADV_FORW_SINGLE set the orig to the single originator the skb
@@ -1387,17 +1388,16 @@ batadv_mcast_forw_rtr_node_get(struct ba
*/
enum batadv_forw_mode
batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
- struct batadv_orig_node **orig)
+ struct batadv_orig_node **orig, int *is_routable)
{
int ret, tt_count, ip_count, unsnoop_count, total_count;
bool is_unsnoopable = false;
unsigned int mcast_fanout;
struct ethhdr *ethhdr;
- int is_routable = 0;
int rtr_count = 0;
ret = batadv_mcast_forw_mode_check(bat_priv, skb, &is_unsnoopable,
- &is_routable);
+ is_routable);
if (ret == -ENOMEM)
return BATADV_FORW_NONE;
else if (ret < 0)
@@ -1410,7 +1410,7 @@ batadv_mcast_forw_mode(struct batadv_pri
ip_count = batadv_mcast_forw_want_all_ip_count(bat_priv, ethhdr);
unsnoop_count = !is_unsnoopable ? 0 :
atomic_read(&bat_priv->mcast.num_want_all_unsnoopables);
- rtr_count = batadv_mcast_forw_rtr_count(bat_priv, is_routable);
+ rtr_count = batadv_mcast_forw_rtr_count(bat_priv, *is_routable);
total_count = tt_count + ip_count + unsnoop_count + rtr_count;
@@ -1730,6 +1730,7 @@ batadv_mcast_forw_want_rtr(struct batadv
* @bat_priv: the bat priv with all the soft interface information
* @skb: the multicast packet to transmit
* @vid: the vlan identifier
+ * @is_routable: stores whether the destination is routable
*
* Sends copies of a frame with multicast destination to any node that signaled
* interest in it, that is either via the translation table or the according
@@ -1742,7 +1743,7 @@ batadv_mcast_forw_want_rtr(struct batadv
* is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise.
*/
int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
- unsigned short vid)
+ unsigned short vid, int is_routable)
{
int ret;
@@ -1758,12 +1759,16 @@ int batadv_mcast_forw_send(struct batadv
return ret;
}
+ if (!is_routable)
+ goto skip_mc_router;
+
ret = batadv_mcast_forw_want_rtr(bat_priv, skb, vid);
if (ret != NET_XMIT_SUCCESS) {
kfree_skb(skb);
return ret;
}
+skip_mc_router:
consume_skb(skb);
return ret;
}
--- a/net/batman-adv/multicast.h
+++ b/net/batman-adv/multicast.h
@@ -43,7 +43,8 @@ enum batadv_forw_mode {
enum batadv_forw_mode
batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
- struct batadv_orig_node **mcast_single_orig);
+ struct batadv_orig_node **mcast_single_orig,
+ int *is_routable);
int batadv_mcast_forw_send_orig(struct batadv_priv *bat_priv,
struct sk_buff *skb,
@@ -51,7 +52,7 @@ int batadv_mcast_forw_send_orig(struct b
struct batadv_orig_node *orig_node);
int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
- unsigned short vid);
+ unsigned short vid, int is_routable);
void batadv_mcast_init(struct batadv_priv *bat_priv);
@@ -68,7 +69,8 @@ void batadv_mcast_purge_orig(struct bata
static inline enum batadv_forw_mode
batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
- struct batadv_orig_node **mcast_single_orig)
+ struct batadv_orig_node **mcast_single_orig,
+ int *is_routable)
{
return BATADV_FORW_ALL;
}
@@ -85,7 +87,7 @@ batadv_mcast_forw_send_orig(struct batad
static inline int
batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
- unsigned short vid)
+ unsigned short vid, int is_routable)
{
kfree_skb(skb);
return NET_XMIT_DROP;
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -198,6 +198,7 @@ static netdev_tx_t batadv_interface_tx(s
int gw_mode;
enum batadv_forw_mode forw_mode = BATADV_FORW_SINGLE;
struct batadv_orig_node *mcast_single_orig = NULL;
+ int mcast_is_routable = 0;
int network_offset = ETH_HLEN;
__be16 proto;
@@ -300,7 +301,8 @@ static netdev_tx_t batadv_interface_tx(s
send:
if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) {
forw_mode = batadv_mcast_forw_mode(bat_priv, skb,
- &mcast_single_orig);
+ &mcast_single_orig,
+ &mcast_is_routable);
if (forw_mode == BATADV_FORW_NONE)
goto dropped;
@@ -365,7 +367,8 @@ send:
ret = batadv_mcast_forw_send_orig(bat_priv, skb, vid,
mcast_single_orig);
} else if (forw_mode == BATADV_FORW_SOME) {
- ret = batadv_mcast_forw_send(bat_priv, skb, vid);
+ ret = batadv_mcast_forw_send(bat_priv, skb, vid,
+ mcast_is_routable);
} else {
if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
skb))

View File

@@ -0,0 +1,36 @@
Index: hostapd-2021-02-20-59e9794c/src/ap/hostapd.c
===================================================================
--- hostapd-2021-02-20-59e9794c.orig/src/ap/hostapd.c
+++ hostapd-2021-02-20-59e9794c/src/ap/hostapd.c
@@ -11,6 +11,8 @@
#include <sqlite3.h>
#endif /* CONFIG_SQLITE */
+#include <syslog.h>
+
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
@@ -1316,6 +1318,22 @@ static int hostapd_setup_bss(struct host
os_memcpy(hapd->own_addr, if_addr, ETH_ALEN);
}
+ if (conf->wds_sta) {
+ char path[128];
+ FILE *fp;
+
+ sprintf(path, "/sys/kernel/debug/ieee80211/%s/netdev:%s/disable_offload", hostapd_drv_get_radio_name(hapd), conf->iface);
+
+ fp = fopen(path, "w");
+ if (fp) {
+ syslog(0, "WDS: disable encap - %s\n", path);
+ fprintf(fp, "1");
+ fclose(fp);
+ } else {
+ syslog(0, "WDS: failed to disable encap - %s\n", path);
+ }
+ }
+
if (conf->wmm_enabled < 0)
conf->wmm_enabled = hapd->iconf->ieee80211n | hapd->iconf->ieee80211ax;

View File

@@ -0,0 +1,29 @@
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index ad2aebf..355b4a8 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -615,9 +615,21 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
center_segment0 == channel - 6)
data->center_freq1 = 5000 + center_segment0 * 5;
else {
- wpa_printf(MSG_ERROR,
- "Wrong coupling between HT and VHT/HE channel setting");
- return -1;
+ if (channel <= 48)
+ center_segment0 = 42;
+ else if (channel <= 64)
+ center_segment0 = 58;
+ else if (channel <= 112)
+ center_segment0 = 106;
+ else if (channel <= 128)
+ center_segment0 = 122;
+ else if (channel <= 144)
+ center_segment0 = 138;
+ else if (channel <= 161)
+ center_segment0 = 155;
+ else if (channel <= 177)
+ center_segment0 = 171;
+ data->center_freq1 = 5000 + center_segment0 * 5;
}
}
break;

View File

@@ -13,7 +13,7 @@ PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
PKG_SOURCE_URL:=https://www.kernel.org/pub/software/network/iw
PKG_MD5SUM:=7a47d6f749ec69afcaf351166fd12f6f
PKG_HASH:=293a07109aeb7e36267cf59e3ce52857e9ffae3a6666eb8ac77894b1839fe1f2
PKG_MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
PKG_LICENSE:=GPL-2.0

View File

@@ -132,7 +132,7 @@ mac80211_hostapd_setup_base() {
json_select config
[ "$auto_channel" -gt 0 ] && channel=acs_survey
[ "$auto_channel" -gt 0 ] && channel=0
[ "$auto_channel" -gt 0 ] && json_get_vars acs_exclude_dfs
[ -n "$acs_exclude_dfs" ] && [ "$acs_exclude_dfs" -gt 0 ] &&
@@ -1162,10 +1162,13 @@ drv_mac80211_setup() {
if [ "$no_reload" != "0" ]; then
add_ap=1
ubus wait_for hostapd
local hostapd_res="$(ubus call hostapd config_add "{\"iface\":\"$primary_ap\", \"config\":\"${hostapd_conf_file}\"}")"
local hostapd_res
[ -f /tmp/wifi_fail_test ] || hostapd_res="$(ubus call hostapd config_add "{\"iface\":\"$primary_ap\", \"config\":\"${hostapd_conf_file}\"}")"
ret="$?"
rm -f /tmp/wifi_fail_test
[ "$ret" != 0 -o -z "$hostapd_res" ] && {
wireless_setup_failed HOSTAPD_START_FAILED
logger failed to start wifi trying again
# wireless_setup_failed HOSTAPD_START_FAILED
return
}
wireless_add_process "$(jsonfilter -s "$hostapd_res" -l 1 -e @.pid)" "/usr/sbin/hostapd" 1 1

View File

@@ -0,0 +1,74 @@
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -300,6 +300,32 @@ static ssize_t ieee80211_if_parse_smps(s
}
IEEE80211_IF_FILE_RW(smps);
+static ssize_t ieee80211_if_fmt_disable_offload(const struct ieee80211_sub_if_data *sdata,
+ char *buf, int buflen)
+{
+ return snprintf(buf, buflen, "%u\n", sdata->disable_offload);
+}
+
+static ssize_t ieee80211_if_parse_disable_offload(struct ieee80211_sub_if_data *sdata,
+ const char *buf, int buflen)
+{
+ int ret;
+ u8 val;
+
+ ret = kstrtou8(buf, 0, &val);
+ if (ret)
+ return ret;
+
+ if (!val)
+ return -EINVAL;
+
+ sdata->disable_offload = val;
+ ieee80211_recalc_offload(sdata->local);
+
+ return buflen;
+}
+IEEE80211_IF_FILE_RW(disable_offload);
+
int ieee80211_if_fmt_bmiss_threshold(const struct ieee80211_sub_if_data *sdata,
char *buf, int buflen)
{
@@ -680,6 +706,7 @@ static void add_common_files(struct ieee
DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_2ghz);
DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz);
+ DEBUGFS_ADD_MODE(disable_offload, 0600);
DEBUGFS_ADD(hw_queues);
if (sdata->local->ops->wake_tx_queue &&
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -942,6 +942,7 @@ struct ieee80211_sub_if_data {
bool control_port_no_encrypt;
bool control_port_no_preauth;
bool control_port_over_nl80211;
+ bool disable_offload;
int encrypt_headroom;
atomic_t num_tx_queued;
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -909,6 +909,9 @@ static bool ieee80211_set_sdata_offload_
flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED;
}
+ if (sdata->disable_offload)
+ flags = 0;
+
if (sdata->vif.offload_flags == flags)
return false;
@@ -939,6 +942,8 @@ static void ieee80211_set_vif_encap_ops(
if (sdata->wdev.use_4addr &&
!(bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_4ADDR))
enabled = false;
+ if (bss->disable_offload)
+ enabled = false;
sdata->dev->netdev_ops = enabled ? &ieee80211_dataif_8023_ops :
&ieee80211_dataif_ops;

View File

@@ -1,21 +0,0 @@
Index: backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/mac.c
===================================================================
--- backports-20210222_001-4.4.60-b157d2276.orig/drivers/net/wireless/ath/ath11k/mac.c
+++ backports-20210222_001-4.4.60-b157d2276/drivers/net/wireless/ath/ath11k/mac.c
@@ -6590,6 +6590,7 @@ static int ath11k_mac_op_update_vif_offl
u32 param_id, param_value;
int ret;
+ return 0;
if (ab->nss.enabled && vif->type == NL80211_IFTYPE_AP_VLAN)
return 0;
@@ -6835,6 +6836,8 @@ static int ath11k_mac_op_add_interface(s
else
param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
+ param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
+
ret = ath11k_nss_vdev_set_cmd(arvif, NSS_WIFI_VDEV_ENCAP_TYPE_CMD, param_value);
if(ret) {

View File

@@ -0,0 +1,57 @@
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -526,6 +526,7 @@ static int ath11k_ahb_ext_irq_config(str
int irq;
int ret;
bool nss_offload;
+ static int devidx = 0;
/* TCL Completion, REO Dest, ERR, Exception and h2rxdma rings are offloaded
* to nss when its enabled, hence don't enable these interrupts
@@ -539,6 +540,9 @@ static int ath11k_ahb_ext_irq_config(str
irq_grp->ab = ab;
irq_grp->grp_id = i;
init_dummy_netdev(&irq_grp->napi_ndev);
+ snprintf(irq_grp->napi_ndev.name, sizeof(irq_grp->napi_ndev.name), "%s%d:%d",
+ "ath11k_ahb", devidx, i);
+ irq_grp->napi_ndev.threaded = 1;
netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
ath11k_ahb_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
@@ -604,6 +608,8 @@ static int ath11k_ahb_ext_irq_config(str
}
}
+ devidx++;
+
return 0;
}
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -806,6 +806,7 @@ static int ath11k_pci_ext_irq_config(str
int i, j, ret, num_vectors = 0;
u32 user_base_data = 0, base_vector = 0, base_idx;
u8 domain_id;
+ static int devidx = 0;
domain_id = ath11k_pci_get_domain_id(ab);
base_idx = ATH11K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX;
@@ -822,6 +823,9 @@ static int ath11k_pci_ext_irq_config(str
irq_grp->ab = ab;
irq_grp->grp_id = i;
init_dummy_netdev(&irq_grp->napi_ndev);
+ snprintf(irq_grp->napi_ndev.name, sizeof(irq_grp->napi_ndev.name), "%s%d:%d",
+ "ath11k_pci", devidx, i);
+ irq_grp->napi_ndev.threaded = 1;
netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi,
ath11k_pci_ext_grp_napi_poll, NAPI_POLL_WEIGHT);
@@ -868,6 +872,7 @@ static int ath11k_pci_ext_irq_config(str
}
}
+ devidx++;
return 0;
}

View File

@@ -0,0 +1,30 @@
From a3598bcbc83224faf0d2ecb55761d048a1beb6d1 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@nbd.name>
Date: Fri, 10 Dec 2021 10:16:18 +0100
Subject: [PATCH] netifd: on dhcp interfaces, store the dhcp server in
interface data
Among other things, this can be used to auto-configure the DHCP server
address for wireless APs using FILS, if the bridged interface is
configured to DHCP
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
package/network/config/netifd/files/lib/netifd/dhcp.script | 1 +
1 file changed, 1 insertion(+)
diff --git a/package/network/config/netifd/files/lib/netifd/dhcp.script b/package/network/config/netifd/files/lib/netifd/dhcp.script
index e46005d84c..6fcf139beb 100755
--- a/package/network/config/netifd/files/lib/netifd/dhcp.script
+++ b/package/network/config/netifd/files/lib/netifd/dhcp.script
@@ -60,6 +60,7 @@ setup_interface () {
[ -n "$message" ] && json_add_string message "$message"
[ -n "$timezone" ] && json_add_int timezone "$timezone"
[ -n "$lease" ] && json_add_int leasetime "$lease"
+ [ -n "$serverid" ] && json_add_string dhcpserver "$serverid"
proto_close_data
proto_send_update "$INTERFACE"
--
2.25.1

View File

@@ -0,0 +1,31 @@
From 9ff18b1e8b9417c50566f469d8b3f5f36bef746a Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Fri, 11 Mar 2022 16:13:41 +0100
Subject: [PATCH] ipq40xx: disable dualboot on ecw5211
Signed-off-by: John Crispin <john@phrozen.org>
---
target/linux/ipq40xx/base-files/etc/init.d/bootcount | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/target/linux/ipq40xx/base-files/etc/init.d/bootcount b/target/linux/ipq40xx/base-files/etc/init.d/bootcount
index d2a4abcadd..36b5d56d0c 100755
--- a/target/linux/ipq40xx/base-files/etc/init.d/bootcount
+++ b/target/linux/ipq40xx/base-files/etc/init.d/bootcount
@@ -13,5 +13,13 @@ boot() {
linksys,mr8300)
mtd resetbc s_env || true
;;
+ edgecore,spw2ac1200|\
+ edgecore,spw2ac1200-lan-poe|\
+ edgecore,ecw5211)
+ avail=$(fw_printenv -n upgrade_available)
+ [ ${avail} -eq 0 ] || {
+ fw_setenv bootcount 0
+ fw_setenv upgrade_available 0
+ }
esac
}
--
2.25.1

Some files were not shown because too many files have changed in this diff Show More