diff --git a/.github/workflows/build-gluon.yml b/.github/workflows/build-gluon.yml
index e763dd53179c7923e37c0e185af2c342cac41d86..f29679f6167544e19c4d5b9d6387a3a2feefa7db 100644
--- a/.github/workflows/build-gluon.yml
+++ b/.github/workflows/build-gluon.yml
@@ -32,7 +32,7 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        target: [ar71xx-generic, ar71xx-tiny, ar71xx-nand, ath79-generic, brcm2708-bcm2708, brcm2708-bcm2709, ipq40xx-generic, ipq806x-generic, lantiq-xrx200, lantiq-xway, mpc85xx-generic, mpc85xx-p1020, ramips-mt7620, ramips-mt7621, ramips-mt76x8, ramips-rt305x, sunxi-cortexa7, x86-generic, x86-geode, x86-legacy, x86-64, ar71xx-mikrotik, brcm2708-bcm2710, mvebu-cortexa9]
+        target: [ath79-generic, ath79-nand, bcm27xx-bcm2708, bcm27xx-bcm2709, ipq40xx-generic, ipq806x-generic, lantiq-xrx200, lantiq-xway, mpc85xx-p1010, mpc85xx-p1020, ramips-mt7620, ramips-mt7621, ramips-mt76x8, ramips-rt305x, sunxi-cortexa7, x86-generic, x86-geode, x86-legacy, x86-64, bcm27xx-bcm2710, mvebu-cortexa9]
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v1
diff --git a/contrib/Dockerfile b/contrib/Dockerfile
index 3a239c68a3f8109513ae8a4129d25d8b7f0922f9..97e4410356beb42576c0c03f14504306ed8d76d0 100644
--- a/contrib/Dockerfile
+++ b/contrib/Dockerfile
@@ -6,7 +6,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
     file \
     git \
     subversion \
-    python \
+    python3 \
     build-essential \
     gawk \
     unzip \
@@ -15,7 +15,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
     libssl-dev \
     libelf-dev \
     wget \
+    rsync \
     time \
+    qemu-utils \
     ecdsautils \
     lua-check \
     shellcheck \
diff --git a/contrib/actions/install-dependencies.sh b/contrib/actions/install-dependencies.sh
index 8c5c600a8b10f58f226da32ef32d3bdf3df51bf7..bb35cc3166f4a493f3215f47f4c38ee234cce438 100755
--- a/contrib/actions/install-dependencies.sh
+++ b/contrib/actions/install-dependencies.sh
@@ -3,6 +3,6 @@
 set -e
 
 apt-get -y update
-apt-get -y install git subversion build-essential python gawk unzip libncurses5-dev zlib1g-dev libssl-dev wget time
+apt-get -y install git subversion build-essential python gawk unzip libncurses5-dev zlib1g-dev libssl-dev wget time qemu-utils
 apt-get -y clean
 rm -rf /var/lib/apt/lists/*
diff --git a/docs/user/getting_started.rst b/docs/user/getting_started.rst
index e162c4ddaef79b31cf2b66839136961c7e57ad28..3cca4267f7a0e4d5c87e7dd21358a8d1d3907f15 100644
--- a/docs/user/getting_started.rst
+++ b/docs/user/getting_started.rst
@@ -38,7 +38,7 @@ freshly installed Debian Stretch system the following packages are required:
 * `libssl-dev`
 * `wget`
 * `time` (built-in `time` doesn't work)
-
+* `qemu-utils`
 
 Building the images
 -------------------
diff --git a/docs/user/supported_devices.rst b/docs/user/supported_devices.rst
index 5dd0ae6fe0e052056a7733b9d30055a192a4d0a6..2cd5437bc839a7e3f5c5645a666ad812da53c35f 100644
--- a/docs/user/supported_devices.rst
+++ b/docs/user/supported_devices.rst
@@ -197,7 +197,6 @@ ath79-generic
 * GL.iNet
 
   - GL-AR300M-Lite
-  - GL-AR750S
 
 * OCEDO
 
@@ -213,6 +212,13 @@ ath79-generic
   - Archer C6 (v2)
   - CPE220 (v3.0)
 
+ath79-nand
+----------
+
+* GL.iNet
+
+  - GL-AR750S
+
 brcm2708-bcm2708
 ----------------
 
diff --git a/modules b/modules
index 855b0ce334dc1575695efb289fbafe6be7782dcf..1f8ea875d89083629bd305071aa67107cd2b79a6 100644
--- a/modules
+++ b/modules
@@ -1,16 +1,16 @@
 GLUON_FEEDS='packages routing gluon'
 
 OPENWRT_REPO=https://github.com/openwrt/openwrt.git
-OPENWRT_BRANCH=openwrt-19.07
-OPENWRT_COMMIT=ffd4452f8b241d1d5b5ea8a56206f51702bbd6c5
+OPENWRT_BRANCH=openwrt-21.02
+OPENWRT_COMMIT=b2a3df91fa7e9a7f8b9216a99496ecc935f3e56d
 
 PACKAGES_PACKAGES_REPO=https://github.com/openwrt/packages.git
-PACKAGES_PACKAGES_BRANCH=openwrt-19.07
-PACKAGES_PACKAGES_COMMIT=476b8b82bb7447a1ed847c96d85de567e09cdb62
+PACKAGES_PACKAGES_BRANCH=openwrt-21.02
+PACKAGES_PACKAGES_COMMIT=5fa605a1fa76bc68e3f70122713e592a1b25f068
 
 PACKAGES_ROUTING_REPO=https://github.com/openwrt-routing/packages.git
-PACKAGES_ROUTING_BRANCH=openwrt-19.07
-PACKAGES_ROUTING_COMMIT=101632e153b41238bc19dfd96ba2d23339dbcb76
+PACKAGES_ROUTING_BRANCH=openwrt-21.02
+PACKAGES_ROUTING_COMMIT=2baff33918c089fd3744c7192f8ae7a29c47a8d7
 
 PACKAGES_GLUON_REPO=https://github.com/freifunk-gluon/packages.git
 PACKAGES_GLUON_COMMIT=b644a2a8d8bf2543d12f782f59a2b2ecdc7bda97
diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac b/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac
index dae573db6ba2e83c52dc0b2a87bd05611f1f05f6..3ff33ee0f0db869d20ec81b04faf46f95009bf76 100755
--- a/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac
+++ b/package/gluon-core/luasrc/lib/gluon/upgrade/010-primary-mac
@@ -124,14 +124,14 @@ local primary_addrs = {
 			'netgear,dgn3500b',
 		}},
 		{'ramips', 'mt7620', {
-			'c20-v1',
-			'c20i',
-			'c50',
-			'tplink,c2-v1',
-			'ex3700'
+			'netgear,ex3700',
+			'tplink,archer-c2-v1',
+			'tplink,archer-c20-v1',
+			'tplink,archer-c20i',
+			'tplink,archer-c50-v1',
 		}},
 		{'ramips', 'mt76x8', {
-			'xiaomi,mir4a-100m',
+			'xiaomi,mi-router-4a-100m',
 		}},
 		{'x86'},
 	}},
@@ -154,7 +154,7 @@ local primary_addrs = {
 			'ocedo,panda',
 		}},
 		{'ramips', 'mt7620', {
-			'miwifi-mini',
+			'xiaomi,miwifi-mini',
 		}},
 	}},
 	{phy(1), {
@@ -164,7 +164,7 @@ local primary_addrs = {
 			'tl-wr902ac-v1',
 		}},
 		{'ramips', 'mt7621', {
-			'dir-860l-b1',
+			'dlink,dir-860l-b1',
 		}},
 	}},
 	-- label-mac-device default
diff --git a/package/gluon-core/luasrc/lib/gluon/upgrade/020-interfaces b/package/gluon-core/luasrc/lib/gluon/upgrade/020-interfaces
index 5bb1926d467066d25f2e0581633a29f824a556a1..9d1b84c88d6189c8425a26a340e47646132d069d 100755
--- a/package/gluon-core/luasrc/lib/gluon/upgrade/020-interfaces
+++ b/package/gluon-core/luasrc/lib/gluon/upgrade/020-interfaces
@@ -73,4 +73,11 @@ end
 uci:delete('network', 'lan')
 uci:delete('network', 'wan')
 
+uci:foreach('network', 'device', function(dev)
+	if dev['type'] ~= 'bridge' then return end
+	if dev['ifname'] ~= 'lan' and dev['ifname'] ~= 'wan' then return end
+
+	uci:delete('network', dev['.name'])
+end)
+
 uci:save('network')
diff --git a/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua b/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua
index 4de2efaf135f49b6974374715f5ce43a7a20f66a..d8ffcafd91e66cb8a30cb33c8d72196877f36d00 100644
--- a/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua
+++ b/package/gluon-core/luasrc/usr/lib/lua/gluon/util.lua
@@ -134,7 +134,7 @@ end
 -- Safe glob: returns an empty table when the glob fails because of
 -- a non-existing path
 function M.glob(pattern)
-	return posix_glob.glob(pattern) or {}
+	return posix_glob.glob(pattern, 0) or {}
 end
 
 -- Generates a (hopefully) unique MAC address
diff --git a/package/gluon-web/luasrc/usr/lib/lua/gluon/web/dispatcher.lua b/package/gluon-web/luasrc/usr/lib/lua/gluon/web/dispatcher.lua
index 2d72777661b2d9a6f565e4836129c7bf3d23ad37..42dc47d1276c2a7c089847655a6ba986bf5e89e4 100644
--- a/package/gluon-web/luasrc/usr/lib/lua/gluon/web/dispatcher.lua
+++ b/package/gluon-web/luasrc/usr/lib/lua/gluon/web/dispatcher.lua
@@ -159,10 +159,10 @@ local function dispatch(config, http, request)
 			ctl()
 		end
 
-		for _, path in ipairs(glob.glob(base .. "*.lua") or {}) do
+		for _, path in ipairs(glob.glob(base .. "*.lua", 0) or {}) do
 			load_ctl(path)
 		end
-		for _, path in ipairs(glob.glob(base .. "*/*.lua") or {}) do
+		for _, path in ipairs(glob.glob(base .. "*/*.lua", 0) or {}) do
 			load_ctl(path)
 		end
 	end
diff --git a/patches/openwrt/0004-dropbear-add-a-failsafe-mode-that-will-always-allow-password-less-root-login.patch b/patches/openwrt/0003-dropbear-add-a-failsafe-mode-that-will-always-allow-password-less-root-login.patch
similarity index 100%
rename from patches/openwrt/0004-dropbear-add-a-failsafe-mode-that-will-always-allow-password-less-root-login.patch
rename to patches/openwrt/0003-dropbear-add-a-failsafe-mode-that-will-always-allow-password-less-root-login.patch
diff --git a/patches/openwrt/0003-libjson-c-Add-support-for-custom-format-strings-for-doubles.patch b/patches/openwrt/0003-libjson-c-Add-support-for-custom-format-strings-for-doubles.patch
deleted file mode 100644
index a596021957af770dbdf1365691e1d14911c58c30..0000000000000000000000000000000000000000
--- a/patches/openwrt/0003-libjson-c-Add-support-for-custom-format-strings-for-doubles.patch
+++ /dev/null
@@ -1,101 +0,0 @@
-From: Jan-Philipp Litza <janphilipp@litza.de>
-Date: Fri, 6 May 2016 16:44:29 +0200
-Subject: libjson-c: Add support for custom format strings for doubles
-
-diff --git a/package/libs/libjson-c/patches/002-custom-format-string.patch b/package/libs/libjson-c/patches/002-custom-format-string.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..b67433a7baf37654a17fa5036c4266b33bdda9f2
---- /dev/null
-+++ b/package/libs/libjson-c/patches/002-custom-format-string.patch
-@@ -0,0 +1,91 @@
-+From 21dc5dc92bd56f5f4dc2c90b9ea6bf1e1407714e Mon Sep 17 00:00:00 2001
-+From: Jan-Philipp Litza <janphilipp@litza.de>
-+Date: Fri, 6 May 2016 16:12:44 +0200
-+Subject: [PATCH] Export json_object_double_to_json_string() and use custom
-+ format string
-+BCC: janphilipp@litza.de
-+
-+---
-+ json_object.c | 12 ++++++------
-+ json_object.h | 28 ++++++++++++++++++++++++++++
-+ 2 files changed, 34 insertions(+), 6 deletions(-)
-+
-+--- a/json_object.c
-++++ b/json_object.c
-+@@ -55,7 +55,6 @@ static struct json_object* json_object_n
-+ static json_object_to_json_string_fn json_object_object_to_json_string;
-+ static json_object_to_json_string_fn json_object_boolean_to_json_string;
-+ static json_object_to_json_string_fn json_object_int_to_json_string;
-+-static json_object_to_json_string_fn json_object_double_to_json_string;
-+ static json_object_to_json_string_fn json_object_string_to_json_string;
-+ static json_object_to_json_string_fn json_object_array_to_json_string;
-+ 
-+@@ -560,10 +559,10 @@ int64_t json_object_get_int64(struct jso
-+ 
-+ /* json_object_double */
-+ 
-+-static int json_object_double_to_json_string(struct json_object* jso,
-+-					     struct printbuf *pb,
-+-					     int level,
-+-						 int flags)
-++int json_object_double_to_json_string(struct json_object* jso,
-++				      struct printbuf *pb,
-++				      int level,
-++				      int flags)
-+ {
-+   char buf[128], *p, *q;
-+   int size;
-+@@ -579,7 +578,8 @@ static int json_object_double_to_json_st
-+     else
-+       size = snprintf(buf, sizeof(buf), "-Infinity");
-+   else
-+-    size = snprintf(buf, sizeof(buf), "%.17g", jso->o.c_double);
-++    size = snprintf(buf, sizeof(buf),
-++        jso->_userdata ? (const char*) jso->_userdata : "%.17g", jso->o.c_double);
-+ 
-+   p = strchr(buf, ',');
-+   if (p) {
-+--- a/json_object.h
-++++ b/json_object.h
-+@@ -515,6 +515,9 @@ extern int64_t json_object_get_int64(str
-+ /* double type methods */
-+ 
-+ /** Create a new empty json_object of type json_type_double
-++ *
-++ * @see json_object_double_to_json_string() for how to set a custom format string.
-++ *
-+  * @param d the double
-+  * @returns a json_object of type json_type_double
-+  */
-+@@ -543,6 +546,31 @@ extern struct json_object* json_object_n
-+  */
-+ extern struct json_object* json_object_new_double_s(double d, const char *ds);
-+ 
-++
-++/** Serialize a json_object of type json_type_double to a string.
-++ *
-++ * This function isn't meant to be called directly. Instead, you can set a
-++ * custom format string for the serialization of this double using the
-++ * following call (where "%.17g" actually is the default):
-++ *
-++ * @code
-++ *   jso = json_object_new_double(d);
-++ *   json_object_set_serializer(jso, json_object_double_to_json_string,
-++ *       "%.17g", NULL);
-++ * @endcode
-++ *
-++ * @see printf(3) man page for format strings
-++ *
-++ * @param jso The json_type_double object that is serialized.
-++ * @param pb The destination buffer.
-++ * @param level Ignored.
-++ * @param flags Ignored.
-++ */
-++extern int json_object_double_to_json_string(struct json_object* jso,
-++					     struct printbuf *pb,
-++					     int level,
-++					     int flags);
-++
-+ /** Get the double floating point value of a json_object
-+  *
-+  * The type is coerced to a double if the passed object is not a double.
diff --git a/patches/openwrt/0005-kernel-ebtables-add-support-for-ICMP-IGMP-type-matches.patch b/patches/openwrt/0004-kernel-ebtables-add-support-for-ICMP-IGMP-type-matches.patch
similarity index 100%
rename from patches/openwrt/0005-kernel-ebtables-add-support-for-ICMP-IGMP-type-matches.patch
rename to patches/openwrt/0004-kernel-ebtables-add-support-for-ICMP-IGMP-type-matches.patch
diff --git a/patches/openwrt/0006-build-set-TARGET_ROOTFS_PARTSIZE-to-make-combined-image-fit-in-128MB.patch b/patches/openwrt/0006-build-set-TARGET_ROOTFS_PARTSIZE-to-make-combined-image-fit-in-128MB.patch
deleted file mode 100644
index 773b2800824bf0a6d7b4e080b587c59b6fbdd89c..0000000000000000000000000000000000000000
--- a/patches/openwrt/0006-build-set-TARGET_ROOTFS_PARTSIZE-to-make-combined-image-fit-in-128MB.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From: Matthias Schiffer <mschiffer@universe-factory.net>
-Date: Sat, 21 Sep 2019 13:21:36 +0200
-Subject: build: set TARGET_ROOTFS_PARTSIZE to make combined image fit in 128MB
-
-Change TARGET_ROOTFS_PARTSIZE from 128 to 104 MiB, so the whole image
-(bootloader + boot + root) will fit on a 128MB CF card by default.
-
-With these settings, the generated images (tested on x86-generic and
-x86-64) have 126,353,408 bytes; the smallest CF card marketed as "128MB"
-that I found a datasheet for (a Transcend TS128MCF80) has 126,959,616
-bytes.
-
-Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
-
-diff --git a/config/Config-images.in b/config/Config-images.in
-index 8548c7cd24742daad4fb1c64e58bad82590795c2..dc7a9cbd54ffbe3c78a7fdbd124f389c102ef6c1 100644
---- a/config/Config-images.in
-+++ b/config/Config-images.in
-@@ -274,7 +274,7 @@ menu "Target Images"
- 	config TARGET_ROOTFS_PARTSIZE
- 		int "Root filesystem partition size (in MB)"
- 		depends on GRUB_IMAGES || USES_ROOTFS_PART || TARGET_ROOTFS_EXT4FS || TARGET_omap || TARGET_rb532 || TARGET_sunxi || TARGET_uml
--		default 256
-+		default 104
- 		help
- 		  Select the root filesystem partition size.
- 
diff --git a/patches/openwrt/0007-ipq-wifi-add-BDF-for-Aruba-AP-303.patch b/patches/openwrt/0007-ipq-wifi-add-BDF-for-Aruba-AP-303.patch
deleted file mode 100644
index bfc386a2d56b103b07ecdd374809ab970a9e4b3f..0000000000000000000000000000000000000000
--- a/patches/openwrt/0007-ipq-wifi-add-BDF-for-Aruba-AP-303.patch
+++ /dev/null
@@ -1,92 +0,0 @@
-From: David Bauer <mail@david-bauer.net>
-Date: Sun, 15 Dec 2019 23:02:54 +0100
-Subject: ipq-wifi: add BDF for Aruba AP-303
-
-The BDF originates from the vendor-firmware.
-
-Signed-off-by: David Bauer <mail@david-bauer.net>
-(cherry picked from commit 4113d8a2554adf5ecee55cc07956eafad378eaff)
-
-diff --git a/package/firmware/ipq-wifi/Makefile b/package/firmware/ipq-wifi/Makefile
-index eb7c2df1aa36ded7774a772c8a7e02b2acb81b40..cc0505b97c6a04bafd88972cf6ce7890a637c33b 100644
---- a/package/firmware/ipq-wifi/Makefile
-+++ b/package/firmware/ipq-wifi/Makefile
-@@ -25,6 +25,7 @@ endef
- 
- ALLWIFIBOARDS:= \
- 	alfa-network_ap120c-ac \
-+	aruba_ap-303 \
- 	asus_map-ac2200 \
- 	avm_fritzbox-7530 \
- 	avm_fritzrepeater-1200 \
-@@ -97,6 +98,7 @@ endef
- # Add $(eval $(call generate-ipq-wifi-package,<devicename>,<display name>))
- 
- $(eval $(call generate-ipq-wifi-package,alfa-network_ap120c-ac,ALFA Network AP120C-AC))
-+$(eval $(call generate-ipq-wifi-package,aruba_ap-303,Aruba AP-303))
- $(eval $(call generate-ipq-wifi-package,asus_map-ac2200,ASUS MAP-AC2200))
- $(eval $(call generate-ipq-wifi-package,avm_fritzbox-7530,AVM FRITZ!Box 7530))
- $(eval $(call generate-ipq-wifi-package,avm_fritzrepeater-1200,AVM FRITZRepeater 1200))
-diff --git a/package/firmware/ipq-wifi/board-aruba_ap-303.qca4019 b/package/firmware/ipq-wifi/board-aruba_ap-303.qca4019
-new file mode 100644
-index 0000000000000000000000000000000000000000..4848115cfbe3a4a0ed6b17cac929731ecbd7968c
-GIT binary patch
-literal 24316
-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
-NIrrxNmNc!u{{!hMI2Hf^
-
-literal 0
-HcmV?d00001
-
diff --git a/patches/openwrt/0008-ipq40xx-add-support-for-Aruba-AP-303.patch b/patches/openwrt/0008-ipq40xx-add-support-for-Aruba-AP-303.patch
deleted file mode 100644
index 8b5fc9dd77cf2e1036da6691f282068bb1c0a967..0000000000000000000000000000000000000000
--- a/patches/openwrt/0008-ipq40xx-add-support-for-Aruba-AP-303.patch
+++ /dev/null
@@ -1,646 +0,0 @@
-From: David Bauer <mail@david-bauer.net>
-Date: Wed, 23 Oct 2019 22:25:14 +0200
-Subject: ipq40xx: add support for Aruba AP-303
-
-Hardware
---------
-
-SoC:   Qualcomm IPQ4029
-RAM:   512M DDR3
-FLASH: - 128MB NAND (Macronix MX30LF1G18AC)
-       - 4MB SPI-NOR (Macronix MX25R3235F)
-TPM:   Atmel AT97SC3203
-BLE:   Texas Instruments CC2540T
-       attached to ttyMSM0
-ETH:   Atheros AR8035
-LED:   WiFi (amber / green)
-       System (red / green)
-BTN:   Reset
-
-To connect to the serial console, you can solder to the labled pads next
-to the USB port or use your Aruba supplied UARt adapter.
-
-Do NOT plug a standard USB cable into the Console labled USB-port!
-Aruba/HPE simply put UART on the micro-USB pins. You can solder yourself
-an adapter cable:
-
-VCC - NC
- D+ - TX
- D- - RX
-GND - GND
-
-The console setting in bootloader and OS is 9600 8N1. Voltage level is
-3.3V.
-
-To enable a full list of commands in the U-Boot "help" command, execute
-the literal "diag" command.
-
-Installation
-------------
-
-1. Get the OpenWrt initramfs image. Rename it to ipq40xx.ari and put it
-   into the TFTP server root directory. Configure the TFTP server to
-   be reachable at 192.168.1.75/24. Connect the machine running the TFTP
-   server to the ethernet port of the access point.
-
-2. Connect to the serial console. Interrupt autobooting by pressing
-   Enter when prompted.
-
-3. Configure the bootargs and bootcmd for OpenWrt.
-   $ setenv bootargs_openwrt "setenv bootargs console=ttyMSM1,9600n8"
-   $ setenv nandboot_openwrt "run bootargs_openwrt; ubi part aos1;
-     ubi read 0x85000000 kernel; bootm 0x85000000"
-   $ setenv ramboot_openwrt "run bootargs_openwrt;
-     setenv ipaddr 192.168.1.105; setenv serverip 192.168.1.75;
-     netget; set fdt_high 0x87000000; bootm"
-   $ setenv bootcmd "run nandboot_openwrt"
-   $ saveenv
-
-4. Load OpenWrt into RAM:
-   $ run ramboot_openwrt
-
-5. After OpenWrt booted, transfer the OpenWrt sysupgrade image to the
-   /tmp folder on the device.
-
-6. Flash OpenWrt:
-   $ ubidetach -p /dev/mtd1
-   $ ubiformat /dev/mtd1
-   $ sysupgrade -n /tmp/openwrt-sysupgrade.bin
-
-To go back to the stock firmware, simply reset the bootcmd in the
-bootloader to the original value:
-
-  $ setenv bootcmd "boot"
-  $ saveenv
-
-Signed-off-by: David Bauer <mail@david-bauer.net>
-(cherry picked from commit 102c8c55f217606cdbdc9a449667e034676b3e75)
-
-diff --git a/target/linux/ipq40xx/base-files/etc/board.d/02_network b/target/linux/ipq40xx/base-files/etc/board.d/02_network
-index 01825b8bac46eec6325de00396d96307c946f975..49dd570242533068adf2c9df89e78560ba5f70eb 100755
---- a/target/linux/ipq40xx/base-files/etc/board.d/02_network
-+++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network
-@@ -39,6 +39,7 @@ ipq40xx_setup_interfaces()
- 		ucidef_add_switch "switch0" \
- 			"0u@eth0" "1:lan" "2:lan" "3:lan" "4:lan"
- 		;;
-+	aruba,ap-303|\
- 	avm,fritzrepeater-1200|\
- 	engenius,eap1300|\
- 	meraki,mr33|\
-diff --git a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
-index b0035ce8a394b6e87d7d89b9f55a6ec7c66e448e..15a2f2c09f8a92cc0accfbf9a977dbeb3355570d 100644
---- a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
-+++ b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
-@@ -137,6 +137,10 @@ case "$FIRMWARE" in
- 	qcom,ap-dk01.1-c1)
- 		ath10kcal_extract "ART" 4096 12064
- 		;;
-+	aruba,ap-303)
-+		ath10kcal_extract "ART" 4096 12064
-+		ath10kcal_patch_mac_crc $(mtd_get_mac_binary mfginfo 29)
-+		;;
- 	asus,map-ac2200)
- 		ath10kcal_ubi_extract "Factory" 4096 12064
- 		;;
-@@ -199,6 +203,10 @@ case "$FIRMWARE" in
- 	qcom,ap-dk01.1-c1)
- 		ath10kcal_extract "ART" 20480 12064
- 		;;
-+	aruba,ap-303)
-+		ath10kcal_extract "ART" 20480 12064
-+		ath10kcal_patch_mac_crc $(macaddr_add $(mtd_get_mac_binary mfginfo 29) +1)
-+		;;
- 	asus,map-ac2200)
- 		ath10kcal_ubi_extract "Factory" 20480 12064
- 		;;
-diff --git a/target/linux/ipq40xx/base-files/etc/inittab b/target/linux/ipq40xx/base-files/etc/inittab
-index 809bba5e5ff49869429c91cf791cea73ab67d14e..3181021a0592720657b815c3eac803a57f4ea438 100644
---- a/target/linux/ipq40xx/base-files/etc/inittab
-+++ b/target/linux/ipq40xx/base-files/etc/inittab
-@@ -2,3 +2,4 @@
- ::sysinit:/etc/init.d/rcS S boot
- ::shutdown:/etc/init.d/rcS K shutdown
- ttyMSM0::askfirst:/usr/libexec/login.sh
-+ttyMSM1::askfirst:/usr/libexec/login.sh
-diff --git a/target/linux/ipq40xx/base-files/lib/preinit/06_set_preinit_iface_ipq40xx.sh b/target/linux/ipq40xx/base-files/lib/preinit/06_set_preinit_iface_ipq40xx.sh
-index be4b6322cb6a91f489dfec237ac6b79ce079e0eb..a0dec1042a3dd7416ece3307666c8ecf9d15d277 100644
---- a/target/linux/ipq40xx/base-files/lib/preinit/06_set_preinit_iface_ipq40xx.sh
-+++ b/target/linux/ipq40xx/base-files/lib/preinit/06_set_preinit_iface_ipq40xx.sh
-@@ -4,6 +4,7 @@ set_preinit_iface() {
- 	. /lib/functions.sh
- 
- 	case $(board_name) in
-+	aruba,ap-303| \
- 	asus,rt-ac58u| \
- 	avm,fritzbox-4040| \
- 	glinet,gl-b1300| \
-diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
-index a7b7da1bf378f7cc19e960c497bc52efb3bae4fb..7253139497a8a8b9fab49cef3fce5eabe98d8002 100644
---- a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
-+++ b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
-@@ -48,6 +48,7 @@ platform_do_upgrade() {
- 	case "$(board_name)" in
- 	8dev,jalapeno |\
- 	alfa-network,ap120c-ac |\
-+	aruba,ap-303 |\
- 	avm,fritzbox-7530 |\
- 	avm,fritzrepeater-1200 |\
- 	avm,fritzrepeater-3000 |\
-diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-ap-303.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-ap-303.dts
-new file mode 100644
-index 0000000000000000000000000000000000000000..7929494d027aca5c696910232a36d484f5ce6562
---- /dev/null
-+++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4029-ap-303.dts
-@@ -0,0 +1,418 @@
-+// SPDX-License-Identifier: GPL-2.0 OR MIT
-+
-+#include "qcom-ipq4019.dtsi"
-+#include <dt-bindings/gpio/gpio.h>
-+#include <dt-bindings/input/input.h>
-+#include <dt-bindings/soc/qcom,tcsr.h>
-+
-+/ {
-+	model = "Aruba AP-303";
-+	compatible = "aruba,ap-303";
-+
-+	aliases {
-+		led-boot = &led_system_green;
-+		led-failsafe = &led_system_red;
-+		led-running = &led_system_green;
-+		led-upgrade = &led_system_red;
-+	};
-+
-+	memory {
-+		device_type = "memory";
-+		reg = <0x80000000 0x10000000>;
-+	};
-+
-+	soc {
-+		mdio@90000 {
-+			status = "okay";
-+			pinctrl-0 = <&mdio_pins>;
-+			pinctrl-names = "default";
-+
-+			/delete-node/ ethernet-phy@0;
-+			/delete-node/ ethernet-phy@2;
-+			/delete-node/ ethernet-phy@3;
-+			/delete-node/ ethernet-phy@4;
-+
-+			ethernet-phy@5 {
-+				reg = <0x5>;
-+			};
-+		};
-+
-+		counter@4a1000 {
-+			compatible = "qcom,qca-gcnt";
-+			reg = <0x4a1000 0x4>;
-+		};
-+
-+		ess_tcsr@1953000 {
-+			compatible = "qcom,tcsr";
-+			reg = <0x1953000 0x1000>;
-+			qcom,ess-interface-select = <TCSR_ESS_PSGMII_RGMII5>;
-+		};
-+
-+		tcsr@1949000 {
-+			compatible = "qcom,tcsr";
-+			reg = <0x1949000 0x100>;
-+			qcom,wifi_glb_cfg = <TCSR_WIFI_GLB_CFG>;
-+		};
-+
-+		tcsr@1957000 {
-+			compatible = "qcom,tcsr";
-+			reg = <0x1957000 0x100>;
-+			qcom,wifi_noc_memtype_m0_m2 = <TCSR_WIFI_NOC_MEMTYPE_M0_M2>;
-+		};
-+
-+		blsp1_uart2: serial@78b0000 {
-+		};
-+
-+		crypto@8e3a000 {
-+			status = "okay";
-+		};
-+
-+		watchdog@b017000 {
-+			status = "okay";
-+		};
-+
-+		ess-switch@c000000 {
-+			switch_mac_mode = <0x3>; /* mac mode for RGMII RMII */
-+			switch_lan_bmp = <0x0>; /* lan port bitmap */
-+			switch_wan_bmp = <0x10>; /* wan port bitmap */
-+		};
-+
-+		edma@c080000 {
-+			qcom,single-phy;
-+			qcom,num_gmac = <1>;
-+			phy-mode = "rgmii-id";
-+			status = "okay";
-+		};
-+
-+		i2c_0: i2c@78b7000 {
-+			pinctrl-0 = <&i2c_0_pins>;
-+			pinctrl-names = "default";
-+			status = "ok";
-+
-+			tpm@29 {
-+				/* No Driver */
-+				compatible = "atmel,at97sc3203";
-+				reg = <0x29>;
-+				read-only;
-+			};
-+		};
-+	};
-+
-+	leds {
-+		compatible = "gpio-leds";
-+
-+		wifi_green {
-+			label = "ap-303:green:wifi";
-+			gpios = <&tlmm 39 GPIO_ACTIVE_HIGH>;
-+			linux,default-trigger = "phy0tpt";
-+		};
-+
-+		wifi_amber {
-+			label = "ap-303:amber:wifi";
-+			gpios = <&tlmm 40 GPIO_ACTIVE_HIGH>;
-+			linux,default-trigger = "phy1tpt";
-+		};
-+
-+		led_system_red: system_red {
-+			label = "ap-303:red:system";
-+			gpios = <&tlmm 46 GPIO_ACTIVE_HIGH>;
-+		};
-+
-+		led_system_green: system_green {
-+			label = "ap-303:green:system";
-+			gpios = <&tlmm 47 GPIO_ACTIVE_HIGH>;
-+		};
-+	};
-+
-+	keys {
-+		compatible = "gpio-keys";
-+
-+		reset {
-+			label = "Reset button";
-+			gpios = <&tlmm 50 GPIO_ACTIVE_LOW>;
-+			linux,code = <KEY_RESTART>;
-+		};
-+	};
-+};
-+
-+&blsp_dma {
-+	status = "okay";
-+};
-+
-+&blsp1_uart1 {
-+	/* Texas Instruments CC2540T BLE radio */
-+	pinctrl-0 = <&serial_0_pins>;
-+	pinctrl-names = "default";
-+	status = "okay";
-+};
-+
-+&blsp1_uart2 {
-+	pinctrl-0 = <&serial_1_pins>;
-+	pinctrl-names = "default";
-+	status = "okay";
-+};
-+
-+&cryptobam {
-+	status = "okay";
-+};
-+
-+&gmac0 {
-+	qcom,phy_mdio_addr = <5>;
-+	qcom,poll_required = <1>;
-+	vlan_tag = <0 0x20>;
-+};
-+
-+&qpic_bam {
-+	status = "okay";
-+};
-+
-+&tlmm {
-+	/*
-+	 * In addition to the Pins listed below,
-+	 * the following GPIOs have "features":
-+	 * 54 - out - active low to force HW reset
-+	 * 41 - out - active low to reset TPM
-+	 * 43 - out - active low to reset BLE radio
-+	 * 19 - in  - active high when DC powered
-+	 */
-+	mdio_pins: mdio_pinmux {
-+		mux_1 {
-+			pins = "gpio6";
-+			function = "mdio";
-+			bias-pull-up;
-+		};
-+		mux_2 {
-+			pins = "gpio7";
-+			function = "mdc";
-+			bias-pull-up;
-+		};
-+	};
-+
-+	nand_pins: nand_pins {
-+		pullups {
-+			pins = "gpio53", "gpio58", "gpio59";
-+			function = "qpic";
-+			bias-pull-up;
-+		};
-+
-+		pulldowns {
-+			pins = "gpio54", "gpio55", "gpio56",
-+				"gpio57", "gpio60", "gpio61",
-+				"gpio62", "gpio63", "gpio64",
-+				"gpio65", "gpio66", "gpio67",
-+				"gpio68", "gpio69";
-+			function = "qpic";
-+			bias-pull-down;
-+		};
-+	};
-+
-+	spi_0_pins: spi_0_pinmux {
-+		pin {
-+			function = "blsp_spi0";
-+			pins = "gpio13", "gpio14", "gpio15";
-+			drive-strength = <12>;
-+			bias-disable;
-+		};
-+		pin_cs {
-+			function = "gpio";
-+			pins = "gpio12";
-+			drive-strength = <2>;
-+			bias-disable;
-+			output-high;
-+		};
-+	};
-+	i2c_0_pins: i2c_0_pinmux {
-+		mux {
-+			pins = "gpio10", "gpio11";
-+			function = "blsp_i2c0";
-+			drive-strength = <4>;
-+			bias-disable;
-+		};
-+	};
-+
-+	serial_0_pins: serial_0_pinmux {
-+		mux {
-+			pins = "gpio16", "gpio17";
-+			function = "blsp_uart0";
-+			bias-disable;
-+		};
-+	};
-+
-+	serial_1_pins: serial_1_pinmux {
-+		mux {
-+			pins = "gpio8", "gpio9";
-+			function = "blsp_uart1";
-+			bias-disable;
-+		};
-+	};
-+
-+	phy-reset {
-+		line-name = "PHY-reset";
-+		gpios = <42 GPIO_ACTIVE_HIGH>;
-+		gpio-hog;
-+		output-high;
-+	};
-+};
-+
-+&nand {
-+	pinctrl-0 = <&nand_pins>;
-+	pinctrl-names = "default";
-+	status = "okay";
-+
-+	nand@0 {
-+		partitions {
-+			compatible = "fixed-partitions";
-+			#address-cells = <1>;
-+			#size-cells = <1>;
-+
-+			partition@0 {
-+				/* 'aos0' in Aruba firmware */
-+				label = "aos0";
-+				reg = <0x0 0x2000000>;
-+				read-only;
-+			};
-+
-+			partition@2000000 {
-+				/* 'aos1' in AVM firmware */
-+				label = "ubi";
-+				reg = <0x2000000 0x2000000>;
-+			};
-+
-+			partition@4000000 {
-+				label = "aruba-ubifs";
-+				reg = <0x4000000 0x4000000>;
-+				read-only;
-+			};
-+		};
-+	};
-+};
-+
-+&blsp1_spi1 {
-+	pinctrl-0 = <&spi_0_pins>;
-+	pinctrl-names = "default";
-+	status = "okay";
-+	cs-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>;
-+
-+	flash@0 {
-+		compatible = "jedec,spi-nor";
-+		reg = <0>;
-+		spi-max-frequency = <24000000>;
-+
-+		partitions {
-+			compatible = "fixed-partitions";
-+			#address-cells = <1>;
-+			#size-cells = <1>;
-+
-+			/*
-+			 * There is no partition map for the NOR flash
-+			 * in the stock firmware.
-+			 *
-+			 * All partitions here are based on offsets
-+			 * found in the U-Boot GPL code and information
-+			 * from smem.
-+			 */
-+
-+			partition@0 {
-+				label = "sbl1";
-+				reg = <0x0 0x40000>;
-+				read-only;
-+			};
-+
-+			partition@40000 {
-+				label = "mibib";
-+				reg = <0x40000 0x20000>;
-+				read-only;
-+			};
-+
-+			partition@60000 {
-+				label = "qsee";
-+				reg = <0x60000 0x60000>;
-+				read-only;
-+			};
-+
-+			partition@c0000 {
-+				label = "cdt";
-+				reg = <0xc0000 0x10000>;
-+				read-only;
-+			};
-+
-+			partition@d0000 {
-+				label = "ddrparams";
-+				reg = <0xd0000 0x10000>;
-+				read-only;
-+			};
-+
-+			partition@e0000 {
-+				label = "ART";
-+				reg = <0xe0000 0x10000>;
-+				read-only;
-+			};
-+
-+			partition@f0000 {
-+				label = "appsbl";
-+				reg = <0xf0000 0xf0000>;
-+				read-only;
-+			};
-+
-+			partition@1e0000 {
-+				label = "mfginfo";
-+				reg = <0x1e0000 0x10000>;
-+				read-only;
-+			};
-+
-+			partition@1f0000 {
-+				label = "apcd";
-+				reg = <0x1f0000 0x10000>;
-+				read-only;
-+			};
-+
-+			partition@200000 {
-+				label = "osss";
-+				reg = <0x200000 0x180000>;
-+				read-only;
-+			};
-+
-+			partition@380000 {
-+				/* This is empty */
-+				label = "appsblenv";
-+				reg = <0x380000 0x10000>;
-+				read-only;
-+			};
-+
-+			partition@390000 {
-+				label = "pds";
-+				reg = <0x390000 0x10000>;
-+				read-only;
-+			};
-+
-+			partition@3a0000 {
-+				label = "fcache";
-+				reg = <0x3a0000 0x10000>;
-+				read-only;
-+			};
-+
-+			partition@3b0000 {
-+				/* Called osss1 in smem */
-+				label = "u-boot-env-bak";
-+				reg = <0x3b0000 0x10000>;
-+				read-only;
-+			};
-+
-+			partition@3f0000 {
-+				label = "u-boot-env";
-+				reg = <0x3f0000 0x10000>;
-+				read-only;
-+			};
-+		};
-+	};
-+};
-+
-+&wifi0 {
-+	status = "okay";
-+	qcom,ath10k-calibration-variant = "Aruba-AP-303";
-+};
-+
-+&wifi1 {
-+	status = "okay";
-+	qcom,ath10k-calibration-variant = "Aruba-AP-303";
-+};
-diff --git a/target/linux/ipq40xx/image/Makefile b/target/linux/ipq40xx/image/Makefile
-index 98c81726d9c12bd466df2150c3e98a76cfb46f78..68dcbc59a42f6d8360b87c7b4e74cd34f697b465 100644
---- a/target/linux/ipq40xx/image/Makefile
-+++ b/target/linux/ipq40xx/image/Makefile
-@@ -85,6 +85,15 @@ define Device/alfa-network_ap120c-ac
- endef
- TARGET_DEVICES += alfa-network_ap120c-ac
- 
-+define Device/aruba_ap-303
-+	$(call Device/FitImageLzma)
-+	DEVICE_TITLE := Aruba AP-303
-+	DEVICE_DTS := qcom-ipq4029-ap-303
-+	DEVICE_PACKAGES := ipq-wifi-aruba_ap-303
-+	IMAGES := sysupgrade.bin
-+endef
-+TARGET_DEVICES += aruba_ap-303
-+
- define Device/asus_map-ac2200
- 	$(call Device/FitImageLzma)
- 	DEVICE_DTS := qcom-ipq4019-map-ac2200
-diff --git a/target/linux/ipq40xx/patches-4.14/304-mtd-spi-nor-Add-support-for-mx25r3235f.patch b/target/linux/ipq40xx/patches-4.14/304-mtd-spi-nor-Add-support-for-mx25r3235f.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..d95923a1610d4764538e79bb783702903edcdcad
---- /dev/null
-+++ b/target/linux/ipq40xx/patches-4.14/304-mtd-spi-nor-Add-support-for-mx25r3235f.patch
-@@ -0,0 +1,26 @@
-+From 158acdbf0336f601971637f988b57a6a67a0869b Mon Sep 17 00:00:00 2001
-+From: David Bauer <mail@david-bauer.net>
-+Date: Sun, 15 Dec 2019 13:10:50 +0100
-+Subject: [PATCH] mtd: spi-nor: Add support for mx25r3235f
-+
-+Add MTD support for the Macronix MX25R3235F SPI NOR chip from Macronix.
-+The chip has 4MB of total capacity, divided into a total of 64 sectors,
-+each 64KB sized. The chip also supports 4KB large sectors.
-+Additionally, it supports dual and quad read modes.
-+
-+Signed-off-by: David Bauer <mail@david-bauer.net>
-+---
-+ drivers/mtd/spi-nor/spi-nor.c | 2 ++
-+ 1 file changed, 2 insertions(+)
-+
-+--- a/drivers/mtd/spi-nor/spi-nor.c
-++++ b/drivers/mtd/spi-nor/spi-nor.c
-+@@ -1024,6 +1024,8 @@ static const struct flash_info spi_nor_i
-+ 	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, SECT_4K) },
-+ 	{ "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
-+ 	{ "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
-++	{ "mx25r3235f",  INFO(0xc22816, 0, 64 * 1024,  64,
-++			 SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-+ 	{ "mx25u3235f",	 INFO(0xc22536, 0, 64 * 1024, 64, 0) },
-+ 	{ "mx25u2033e",  INFO(0xc22532, 0, 64 * 1024,   4, SECT_4K) },
-+ 	{ "mx25u4035",   INFO(0xc22533, 0, 64 * 1024,   8, SECT_4K) },
-diff --git a/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch b/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch
-index f7efd415f1f1c000867793b3b133e44b3e50b0fd..fc8a88336491c2ac7c2a93fafb1f2b6fd38695be 100644
---- a/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch
-+++ b/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch
-@@ -10,7 +10,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
- 
- --- a/arch/arm/boot/dts/Makefile
- +++ b/arch/arm/boot/dts/Makefile
--@@ -697,7 +697,31 @@ dtb-$(CONFIG_ARCH_QCOM) += \
-+@@ -697,7 +697,32 @@ dtb-$(CONFIG_ARCH_QCOM) += \
-  	qcom-apq8074-dragonboard.dtb \
-  	qcom-apq8084-ifc6540.dtb \
-  	qcom-apq8084-mtp.dtb \
-@@ -37,6 +37,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
- +	qcom-ipq4019-qxwlan-e2600ac-c1.dtb \
- +	qcom-ipq4019-qxwlan-e2600ac-c2.dtb \
- +	qcom-ipq4028-wpj428.dtb \
-++	qcom-ipq4029-ap-303.dtb \
- +	qcom-ipq4029-gl-b1300.dtb \
- +	qcom-ipq4029-mr33.dtb \
-  	qcom-ipq8064-ap148.dtb \
diff --git a/patches/openwrt/0009-ath79-enable-GL-AR750S-NOR-variant-from-master.patch b/patches/openwrt/0009-ath79-enable-GL-AR750S-NOR-variant-from-master.patch
deleted file mode 100644
index 1b9848d75369ddc99ebb359f70f867f2514cbbf3..0000000000000000000000000000000000000000
--- a/patches/openwrt/0009-ath79-enable-GL-AR750S-NOR-variant-from-master.patch
+++ /dev/null
@@ -1,61 +0,0 @@
-From: Jan Alexander <jan@nalx.net>
-Date: Tue, 31 Mar 2020 21:50:28 +0200
-Subject: ath79: enable GL-AR750S NOR variant from master
-
-diff --git a/target/linux/ath79/base-files/etc/board.d/02_network b/target/linux/ath79/base-files/etc/board.d/02_network
-index 5dda551caae0429880ee9d5965bfb6797d218e6d..b8fac8816c9a2b2a87a5d1335b41127666afe2e4 100755
---- a/target/linux/ath79/base-files/etc/board.d/02_network
-+++ b/target/linux/ath79/base-files/etc/board.d/02_network
-@@ -155,7 +155,7 @@ ath79_setup_interfaces()
- 	etactica,eg200)
- 		ucidef_set_interface_lan "eth0" "dhcp"
- 		;;
--	glinet,gl-ar750s)
-+	glinet,gl-ar750s-nor)
- 		ucidef_add_switch "switch0" \
- 			"0@eth0" "2:lan:2" "3:lan:1" "1:wan"
- 		;;
-diff --git a/target/linux/ath79/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ath79/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
-index d93e6dcd71ab19c53905daa41e95cc4fc614f114..c917f38211d0b246f064dba4b7feefecf61f5856 100644
---- a/target/linux/ath79/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
-+++ b/target/linux/ath79/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
-@@ -117,7 +117,7 @@ case "$FIRMWARE" in
- 		ath10kcal_extract "art" 20480 2116
- 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) +1)
- 		;;
--	glinet,gl-ar750s)
-+	glinet,gl-ar750s-nor)
- 		ath10kcal_extract "art" 20480 2116
- 		ath10kcal_patch_mac $(macaddr_add $(mtd_get_mac_binary art 0) +1)
- 		;;
-diff --git a/target/linux/ath79/dts/qca9563_glinet_gl-ar750s.dts b/target/linux/ath79/dts/qca9563_glinet_gl-ar750s.dts
-index 03922bcd1fe9a453d5916537609317b94eea18c6..ff64e16d1ce7a94d16529e5954e1d50513a5e2cb 100644
---- a/target/linux/ath79/dts/qca9563_glinet_gl-ar750s.dts
-+++ b/target/linux/ath79/dts/qca9563_glinet_gl-ar750s.dts
-@@ -7,8 +7,8 @@
- #include "qca956x.dtsi"
- 
- / {
--	compatible = "glinet,gl-ar750s", "qca,qca9563";
--	model = "GL.iNet GL-AR750S";
-+	compatible = "glinet,gl-ar750s-nor", "qca,qca9563";
-+	model = "GL.iNet GL-AR750S (NOR)";
- 
- 	aliases {
- 		led-boot = &power;
-diff --git a/target/linux/ath79/image/generic.mk b/target/linux/ath79/image/generic.mk
-index 55053be34f11f0df982c85f94c9180fdba9ff221..892ef10f870e347c8a1509cecd35bce4b5e98bee 100644
---- a/target/linux/ath79/image/generic.mk
-+++ b/target/linux/ath79/image/generic.mk
-@@ -403,9 +403,9 @@ define Device/glinet_gl-ar750s
-   DEVICE_TITLE := GL.iNet GL-AR750S
-   DEVICE_PACKAGES := kmod-usb2 kmod-ath10k-ct ath10k-firmware-qca9887-ct block-mount
-   IMAGE_SIZE := 16000k
--  SUPPORTED_DEVICES += gl-ar750s
-+  SUPPORTED_DEVICES += gl-ar750s glinet,gl-ar750s-nor
- endef
--#TARGET_DEVICES += glinet_gl-ar750s
-+TARGET_DEVICES += glinet_gl-ar750s
- 
- define Device/glinet_gl-x750
-   ATH_SOC := qca9531
diff --git a/patches/openwrt/0010-tools-add-zstd.patch b/patches/openwrt/0010-tools-add-zstd.patch
deleted file mode 100644
index d0e86820697411065f472540f3dd3e660b2f75f9..0000000000000000000000000000000000000000
--- a/patches/openwrt/0010-tools-add-zstd.patch
+++ /dev/null
@@ -1,113 +0,0 @@
-From: Matthias Schiffer <mschiffer@universe-factory.net>
-Date: Wed, 13 May 2020 20:22:12 +0200
-Subject: tools: add zstd
-
-Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
-(cherry picked from commit 258dc0d0fd3aae47add9b7dca40848a92d03a4ea)
-
-diff --git a/tools/Makefile b/tools/Makefile
-index b8d986b80cc4b34addf2b35a2b143cfcb583c717..33266ca72d01fa564fb3f06d675219d700edd481 100644
---- a/tools/Makefile
-+++ b/tools/Makefile
-@@ -33,7 +33,7 @@ tools-$(CONFIG_TARGET_mxs) += elftosb sdimage
- tools-$(CONFIG_TARGET_ar71xx) += lzma-old
- tools-$(CONFIG_TARGET_ar71xx)$(CONFIG_TARGET_ath79) += squashfs
- tools-$(CONFIG_USES_MINOR) += kernel2minor
--tools-y += lzma squashfskit4 zip
-+tools-y += lzma squashfskit4 zip zstd
- tools-$(BUILD_B43_TOOLS) += b43-tools
- tools-$(BUILD_ISL) += isl
- tools-$(CONFIG_USE_SPARSE) += sparse
-diff --git a/tools/zstd/Makefile b/tools/zstd/Makefile
-new file mode 100644
-index 0000000000000000000000000000000000000000..7459725e8e79b846ed96551753d07fdd02459598
---- /dev/null
-+++ b/tools/zstd/Makefile
-@@ -0,0 +1,20 @@
-+include $(TOPDIR)/rules.mk
-+
-+PKG_NAME:=zstd
-+PKG_VERSION:=1.4.4
-+
-+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
-+PKG_SOURCE_URL:=@GITHUB/facebook/zstd/releases/download/v$(PKG_VERSION)
-+PKG_HASH:=a364f5162c7d1a455cc915e8e3cf5f4bd8b75d09bc0f53965b0c9ca1383c52c8
-+
-+PKG_LICENSE:=BSD-3-Clause
-+PKG_LICENSE_FILES:=LICENSE
-+PKG_CPE_ID:=cpe:/a:facebook:zstandard
-+
-+HOST_BUILD_PARALLEL:=1
-+
-+include $(INCLUDE_DIR)/host-build.mk
-+
-+HOST_MAKE_FLAGS = PREFIX=$(HOST_BUILD_PREFIX) HAVE_ZLIB=0 HAVE_LZMA=0 HAVE_LZ4=0
-+
-+$(eval $(call HostBuild))
-diff --git a/tools/zstd/patches/0001-build-issue-More-portable-header-prefix-usage-1987.patch b/tools/zstd/patches/0001-build-issue-More-portable-header-prefix-usage-1987.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..6d743aa3855262c2a0956f70ec99588ce9ebe53b
---- /dev/null
-+++ b/tools/zstd/patches/0001-build-issue-More-portable-header-prefix-usage-1987.patch
-@@ -0,0 +1,61 @@
-+From 06a57cf57e3c4e887cadcf688e3081154f3f6db4 Mon Sep 17 00:00:00 2001
-+Message-Id: <06a57cf57e3c4e887cadcf688e3081154f3f6db4.1589392463.git.mschiffer@universe-factory.net>
-+From: Bimba Shrestha <bimbashrestha@fb.com>
-+Date: Thu, 6 Feb 2020 14:10:51 -0800
-+Subject: [PATCH] [build-issue] More portable header prefix usage (#) (#1987)
-+
-+* make 4.3 build issue fix
-+
-+* Changing header name and adding comment
-+---
-+ programs/Makefile | 11 +++++++----
-+ 1 file changed, 7 insertions(+), 4 deletions(-)
-+
-+diff --git a/programs/Makefile b/programs/Makefile
-+index b75314a83f43..a9ee3cb5311b 100644
-+--- a/programs/Makefile
-++++ b/programs/Makefile
-+@@ -94,9 +94,12 @@ endif
-+ 
-+ VOID = /dev/null
-+ 
-++# Make 4.3 doesn't support '\#' anymore (https://lwn.net/Articles/810071/)
-++NUM_SYMBOL := \#
-++
-+ # thread detection
-+ NO_THREAD_MSG := ==> no threads, building without multithreading support
-+-HAVE_PTHREAD := $(shell printf '\#include <pthread.h>\nint main(void) { return 0; }' > have_pthread.c && $(CC) $(FLAGS) -o have_pthread$(EXT) have_pthread.c -pthread 2> $(VOID) && rm have_pthread$(EXT) && echo 1 || echo 0; rm have_pthread.c)
-++HAVE_PTHREAD := $(shell printf '$(NUM_SYMBOL)include <pthread.h>\nint main(void) { return 0; }' > have_pthread.c && $(CC) $(FLAGS) -o have_pthread$(EXT) have_pthread.c -pthread 2> $(VOID) && rm have_pthread$(EXT) && echo 1 || echo 0; rm have_pthread.c)
-+ HAVE_THREAD := $(shell [ "$(HAVE_PTHREAD)" -eq "1" -o -n "$(filter Windows%,$(OS))" ] && echo 1 || echo 0)
-+ ifeq ($(HAVE_THREAD), 1)
-+ THREAD_MSG := ==> building with threading support
-+@@ -108,7 +111,7 @@ endif
-+ 
-+ # zlib detection
-+ NO_ZLIB_MSG := ==> no zlib, building zstd without .gz support
-+-HAVE_ZLIB := $(shell printf '\#include <zlib.h>\nint main(void) { return 0; }' > have_zlib.c && $(CC) $(FLAGS) -o have_zlib$(EXT) have_zlib.c -lz 2> $(VOID) && rm have_zlib$(EXT) && echo 1 || echo 0; rm have_zlib.c)
-++HAVE_ZLIB := $(shell printf '$(NUM_SYMBOL)include <zlib.h>\nint main(void) { return 0; }' > have_zlib.c && $(CC) $(FLAGS) -o have_zlib$(EXT) have_zlib.c -lz 2> $(VOID) && rm have_zlib$(EXT) && echo 1 || echo 0; rm have_zlib.c)
-+ ifeq ($(HAVE_ZLIB), 1)
-+ ZLIB_MSG := ==> building zstd with .gz compression support
-+ ZLIBCPP = -DZSTD_GZCOMPRESS -DZSTD_GZDECOMPRESS
-+@@ -119,7 +122,7 @@ endif
-+ 
-+ # lzma detection
-+ NO_LZMA_MSG := ==> no liblzma, building zstd without .xz/.lzma support
-+-HAVE_LZMA := $(shell printf '\#include <lzma.h>\nint main(void) { return 0; }' > have_lzma.c && $(CC) $(FLAGS) -o have_lzma$(EXT) have_lzma.c -llzma 2> $(VOID) && rm have_lzma$(EXT) && echo 1 || echo 0; rm have_lzma.c)
-++HAVE_LZMA := $(shell printf '$(NUM_SYMBOL)include <lzma.h>\nint main(void) { return 0; }' > have_lzma.c && $(CC) $(FLAGS) -o have_lzma$(EXT) have_lzma.c -llzma 2> $(VOID) && rm have_lzma$(EXT) && echo 1 || echo 0; rm have_lzma.c)
-+ ifeq ($(HAVE_LZMA), 1)
-+ LZMA_MSG := ==> building zstd with .xz/.lzma compression support
-+ LZMACPP = -DZSTD_LZMACOMPRESS -DZSTD_LZMADECOMPRESS
-+@@ -130,7 +133,7 @@ endif
-+ 
-+ # lz4 detection
-+ NO_LZ4_MSG := ==> no liblz4, building zstd without .lz4 support
-+-HAVE_LZ4 := $(shell printf '\#include <lz4frame.h>\n\#include <lz4.h>\nint main(void) { return 0; }' > have_lz4.c && $(CC) $(FLAGS) -o have_lz4$(EXT) have_lz4.c -llz4 2> $(VOID) && rm have_lz4$(EXT) && echo 1 || echo 0; rm have_lz4.c)
-++HAVE_LZ4 := $(shell printf '$(NUM_SYMBOL)include <lz4frame.h>\n\#include <lz4.h>\nint main(void) { return 0; }' > have_lz4.c && $(CC) $(FLAGS) -o have_lz4$(EXT) have_lz4.c -llz4 2> $(VOID) && rm have_lz4$(EXT) && echo 1 || echo 0; rm have_lz4.c)
-+ ifeq ($(HAVE_LZ4), 1)
-+ LZ4_MSG := ==> building zstd with .lz4 compression support
-+ LZ4CPP = -DZSTD_LZ4COMPRESS -DZSTD_LZ4DECOMPRESS
-+-- 
-+2.26.2
-+
diff --git a/patches/openwrt/0011-build-compress-kernel-debuginfo-using-zstd.patch b/patches/openwrt/0011-build-compress-kernel-debuginfo-using-zstd.patch
deleted file mode 100644
index 66678df2491bd884948d4d21ca8f3c437bb40602..0000000000000000000000000000000000000000
--- a/patches/openwrt/0011-build-compress-kernel-debuginfo-using-zstd.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From: Matthias Schiffer <mschiffer@universe-factory.net>
-Date: Wed, 13 May 2020 20:33:46 +0200
-Subject: build: compress kernel debuginfo using zstd
-
-zstd with its default settings (compression level -3) compresses better
-than bzip2 -9 (which is the default setting), and is an order of magnitude
-faster.
-
-I made the following measurements for the most common compression tools
-(all standard Debian Buster versions, default flags unless noted
-otherwise), using the debug information of a large x86-64 kernel with
-ALL_KMODS:
-
-* kernel-debug.tar: 376M
-* kernel-debug.tar.gz: 101M, compressed in ~12s
-* kernel-debug.tar.bz2: 91M, compressed in ~15s
-* kernel-debug.tar.xz: 57M, compressed in ~101s
-* kernel-debug.tar.zst: 86M, compressed in ~1s
-
-With zstd, there is still some room for improvement by increasing the
-compression, but the slight increase in compression ratio
-(22.83% -> 19.46%) does not justify the significant increase in
-compression time (about 5 times on my machine) in my opinion.
-
-Note that multithreaded compression (-T argument) does not affect
-reproducibility with zstd.
-
-Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
-(cherry picked from commit 4bd7990488b0ca7b5cae16f0a9147a4146759053)
-
-diff --git a/include/kernel-build.mk b/include/kernel-build.mk
-index 3fdf7efc52857a5184348cc1261848f75751b8a9..af7c3a8f0bb15c7e0d7072876705ff0bf4f9c8d1 100644
---- a/include/kernel-build.mk
-+++ b/include/kernel-build.mk
-@@ -70,7 +70,7 @@ ifdef CONFIG_COLLECT_KERNEL_DEBUG
- 	$(FIND) $(KERNEL_BUILD_DIR)/debug -type f | $(XARGS) $(KERNEL_CROSS)strip --only-keep-debug
- 	$(TAR) c -C $(KERNEL_BUILD_DIR) debug \
- 		$(if $(SOURCE_DATE_EPOCH),--mtime="@$(SOURCE_DATE_EPOCH)") \
--		| bzip2 -c -9 > $(BIN_DIR)/kernel-debug.tar.bz2
-+		| zstd -T0 -f -o $(BIN_DIR)/kernel-debug.tar.zst
-   endef
- endif
- 
diff --git a/patches/openwrt/0012-mac80211-rt2800-enable-MFP-support-unconditionally.patch b/patches/openwrt/0012-mac80211-rt2800-enable-MFP-support-unconditionally.patch
deleted file mode 100644
index 0a8ca213a422f81626aa6164cec1b7074ff5617c..0000000000000000000000000000000000000000
--- a/patches/openwrt/0012-mac80211-rt2800-enable-MFP-support-unconditionally.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From: Rui Salvaterra <rsalvaterra@gmail.com>
-Date: Mon, 25 May 2020 14:49:07 +0100
-Subject: mac80211: rt2800: enable MFP support unconditionally
-
-This gives us WPA3 support out of the box without having to manually disable
-hardware crypto. The driver will fall back to software crypto if the connection
-requires management frame protection.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-[apply to openwrt-1907]
-Signed-off-by: David Bauer <mail@david-bauer.net>
-
-diff --git a/package/kernel/mac80211/patches/rt2x00/080-rt2800-enable-MFP-support-unconditionally.patch b/package/kernel/mac80211/patches/rt2x00/080-rt2800-enable-MFP-support-unconditionally.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..1d55b2756c365a13b2315e874809e2397fb35855
---- /dev/null
-+++ b/package/kernel/mac80211/patches/rt2x00/080-rt2800-enable-MFP-support-unconditionally.patch
-@@ -0,0 +1,44 @@
-+From b6b15e20421fefae9f78274f9fef80bc97bf5d5c Mon Sep 17 00:00:00 2001
-+From: Rui Salvaterra <rsalvaterra@gmail.com>
-+Date: Mon, 25 May 2020 14:49:07 +0100
-+Subject: [PATCH] rt2800: enable MFP support unconditionally
-+
-+This gives us WPA3 support out of the box without having to manually disable
-+hardware crypto. The driver will fall back to software crypto if the connection
-+requires management frame protection.
-+
-+Suggested-by: Stanislaw Gruszka <stf_xl@wp.pl>
-+Signed-off-by: Rui Salvaterra <rsalvaterra@gmail.com>
-+Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
-+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
-+Link: https://lore.kernel.org/r/20200525134906.1672-1-rsalvaterra@gmail.com
-+---
-+ drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 4 +---
-+ drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 3 ++-
-+ 2 files changed, 3 insertions(+), 4 deletions(-)
-+
-+--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
-+@@ -9985,9 +9985,7 @@ static int rt2800_probe_hw_mode(struct r
-+ 	if (!rt2x00_is_usb(rt2x00dev))
-+ 		ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING);
-+ 
-+-	/* Set MFP if HW crypto is disabled. */
-+-	if (rt2800_hwcrypt_disabled(rt2x00dev))
-+-		ieee80211_hw_set(rt2x00dev->hw, MFP_CAPABLE);
-++	ieee80211_hw_set(rt2x00dev->hw, MFP_CAPABLE);
-+ 
-+ 	SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
-+ 	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
-+--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
-++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
-+@@ -459,7 +459,8 @@ int rt2x00mac_set_key(struct ieee80211_h
-+ 	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
-+ 		return 0;
-+ 
-+-	if (!rt2x00_has_cap_hw_crypto(rt2x00dev))
-++	/* The hardware can't do MFP */
-++	if (!rt2x00_has_cap_hw_crypto(rt2x00dev) || (sta && sta->mfp))
-+ 		return -EOPNOTSUPP;
-+ 
-+ 	/*
diff --git a/patches/openwrt/0013-mac80211-create-channel-list-for-fixed-channel-operation.patch b/patches/openwrt/0013-mac80211-create-channel-list-for-fixed-channel-operation.patch
deleted file mode 100644
index c2178b1eb9e1602600c33b1adc4e45d838854bf8..0000000000000000000000000000000000000000
--- a/patches/openwrt/0013-mac80211-create-channel-list-for-fixed-channel-operation.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From: David Bauer <mail@david-bauer.net>
-Date: Sat, 4 Jul 2020 13:20:02 +0200
-Subject: mac80211: create channel list for fixed channel operation
-
-Currently a device which has a DFS channel selected using the UCI
-channel setting might switch to a non-DFS channel in case no chanlist is
-provided (UCI setting "channels") when the radio detects a DFS event.
-
-Automatically add a chanlist consisting of the configured channel when
-the device does not operate in auto-channel mode and no chanlist set to
-circumvent this issue.
-
-Signed-off-by: David Bauer <mail@david-bauer.net>
-
-diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
-index 36aebbb2ccfec2137d5d260fe2111d77f531ddec..367a3e8e37a8e8435c35ca2912ef0855efbdfc78 100644
---- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
-+++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
-@@ -100,6 +100,9 @@ mac80211_hostapd_setup_base() {
- 	json_get_vars noscan ht_coex
- 	json_get_values ht_capab_list ht_capab tx_burst
- 
-+	[ "$auto_channel" = 0 ] && [ -z "$channel_list" ] && \
-+		channel_list="$channel"
-+
- 	set_default noscan 0
- 
- 	[ "$noscan" -gt 0 ] && hostapd_noscan=1
diff --git a/patches/openwrt/0014-hostapd-enter-DFS-state-if-no-available-channel-is-found.patch b/patches/openwrt/0014-hostapd-enter-DFS-state-if-no-available-channel-is-found.patch
deleted file mode 100644
index bed5a3765c7814db8e8e9684a4cd74b7ecf2c7eb..0000000000000000000000000000000000000000
--- a/patches/openwrt/0014-hostapd-enter-DFS-state-if-no-available-channel-is-found.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From: David Bauer <mail@david-bauer.net>
-Date: Sat, 4 Jul 2020 13:20:07 +0200
-Subject: hostapd: enter DFS state if no available channel is found
-
-Previously hostapd would not stop transmitting when a DFS event was
-detected and no available channel to switch to was available.
-
-Disable and re-enable the interface to enter DFS state. This way, TX
-does not happen until the kernel notifies hostapd about the NOP
-expiring.
-
-Signed-off-by: David Bauer <mail@david-bauer.net>
-
-diff --git a/package/network/services/hostapd/patches/800-dfs-enter-DFS-state-if-no-available-channel-is-found.patch b/package/network/services/hostapd/patches/800-dfs-enter-DFS-state-if-no-available-channel-is-found.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..59e903f06ae66208517c2d620b4cd128f41f25c1
---- /dev/null
-+++ b/package/network/services/hostapd/patches/800-dfs-enter-DFS-state-if-no-available-channel-is-found.patch
-@@ -0,0 +1,28 @@
-+From cefc52e6b93731c713f1bba1cb5e7e92105b758b Mon Sep 17 00:00:00 2001
-+From: David Bauer <mail@david-bauer.net>
-+Date: Fri, 3 Jul 2020 23:00:34 +0200
-+Subject: [PATCH] dfs: enter DFS state if no available channel is found
-+
-+Previously hostapd would not stop transmitting when a DFS event was
-+detected and no available channel to switch to was available.
-+
-+Disable and re-enable the interface to enter DFS state. This way, TX
-+does not happen until the kernel notifies hostapd about the NOP
-+expiring.
-+
-+Signed-off-by: David Bauer <mail@david-bauer.net>
-+---
-+ src/ap/dfs.c | 11 +++++++++--
-+ 1 file changed, 9 insertions(+), 2 deletions(-)
-+
-+--- a/src/ap/dfs.c
-++++ b/src/ap/dfs.c
-+@@ -930,6 +930,8 @@ static int hostapd_dfs_start_channel_swi
-+ 			wpa_printf(MSG_INFO,
-+ 				   "%s: no DFS channels left, waiting for NOP to finish",
-+ 				   __func__);
-++			hostapd_disable_iface(iface);
-++			hostapd_enable_iface(iface);
-+ 			return err;
-+ 		}
-+ 
diff --git a/patches/openwrt/0015-kernel-bridge-Implement-MLD-Querier-wake-up-calls-Android-bug-workaround.patch b/patches/openwrt/0015-kernel-bridge-Implement-MLD-Querier-wake-up-calls-Android-bug-workaround.patch
deleted file mode 100644
index ad9cc4f1546dfef308aec986c7fe0c506e57708e..0000000000000000000000000000000000000000
--- a/patches/openwrt/0015-kernel-bridge-Implement-MLD-Querier-wake-up-calls-Android-bug-workaround.patch
+++ /dev/null
@@ -1,2605 +0,0 @@
-From: Linus Lüssing <linus.luessing@c0d3.blue>
-Date: Tue, 30 Jun 2020 18:01:56 +0200
-Subject: kernel: bridge: Implement MLD Querier wake-up calls / Android bug workaround
-
-Implement a configurable MLD Querier wake-up calls "feature" which
-works around a widely spread Android bug in connection with IGMP/MLD
-snooping.
-
-Currently there are mobile devices (e.g. Android) which are not able
-to receive and respond to MLD Queries reliably because the Wifi driver
-filters a lot of ICMPv6 when the device is asleep - including
-MLD. This in turn breaks IPv6 communication when MLD Snooping is
-enabled. However there is one ICMPv6 type which is allowed to pass and
-which can be used to wake up the mobile device: ICMPv6 Echo Requests.
-
-If this bridge is the selected MLD Querier then setting
-"multicast_wakeupcall" to a number n greater than 0 will send n
-ICMPv6 Echo Requests to each host behind this port to wake
-them up with each MLD Query. Upon receiving a matching ICMPv6 Echo
-Reply an MLD Query with a unicast ethernet destination will be sent
-to the specific host(s).
-
-Link: https://issuetracker.google.com/issues/149630944
-Link: https://github.com/freifunk-gluon/gluon/issues/1832
-
-Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
-
-diff --git a/package/network/config/netifd/patches/0001-bridge-Add-multicast_wakeupcall-option.patch b/package/network/config/netifd/patches/0001-bridge-Add-multicast_wakeupcall-option.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..7ae2960d51d78b03be368bbfd17aff9219da524d
---- /dev/null
-+++ b/package/network/config/netifd/patches/0001-bridge-Add-multicast_wakeupcall-option.patch
-@@ -0,0 +1,169 @@
-+From 026c823dc34c34393498f10a489ea8773866e9e4 Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@c0d3.blue>
-+Date: Sun, 5 Jul 2020 23:33:51 +0200
-+Subject: [PATCH] bridge: Add multicast_wakeupcall option
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+This makes the new per bridge port multicast_wakeupcall feature
-+for the Linux bridge configurable for wireless interfaces and enables it
-+by default for an AP interface.
-+
-+The MLD Querier wake-up calls "feature" works around a widely spread Android
-+bug in connection with IGMP/MLD snooping.
-+
-+Currently there are mobile devices (e.g. Android) which are not able
-+to receive and respond to MLD Queries reliably because the Wifi driver
-+filters a lot of ICMPv6 when the device is asleep - including
-+MLD. This in turn breaks IPv6 communication when MLD Snooping is
-+enabled. However there is one ICMPv6 type which is allowed to pass and
-+which can be used to wake up the mobile device: ICMPv6 Echo Requests.
-+
-+If this bridge is the selected MLD Querier then setting
-+"multicast_wakeupcall" to a number n greater than 0 will send n
-+ICMPv6 Echo Requests to each host behind this port to wake
-+them up with each MLD Query. Upon receiving a matching ICMPv6 Echo
-+Reply an MLD Query with a unicast ethernet destination will be sent
-+to the specific host(s).
-+
-+Link: https://issuetracker.google.com/issues/149630944
-+Link: https://github.com/freifunk-gluon/gluon/issues/1832
-+
-+Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
-+---
-+ device.c       |  9 +++++++++
-+ device.h       | 21 ++++++++++++---------
-+ system-linux.c | 13 +++++++++++++
-+ 3 files changed, 34 insertions(+), 9 deletions(-)
-+
-+diff --git a/device.c b/device.c
-+index 128151a..2e8c24c 100644
-+--- a/device.c
-++++ b/device.c
-+@@ -50,6 +50,7 @@ static const struct blobmsg_policy dev_attrs[__DEV_ATTR_MAX] = {
-+ 	[DEV_ATTR_NEIGHGCSTALETIME] = { .name = "neighgcstaletime", .type = BLOBMSG_TYPE_INT32 },
-+ 	[DEV_ATTR_DADTRANSMITS] = { .name = "dadtransmits", .type = BLOBMSG_TYPE_INT32 },
-+ 	[DEV_ATTR_MULTICAST_TO_UNICAST] = { .name = "multicast_to_unicast", .type = BLOBMSG_TYPE_BOOL },
-++	[DEV_ATTR_MULTICAST_WAKEUPCALL] = { .name = "multicast_wakeupcall", .type = BLOBMSG_TYPE_INT32 },
-+ 	[DEV_ATTR_MULTICAST_ROUTER] = { .name = "multicast_router", .type = BLOBMSG_TYPE_INT32 },
-+ 	[DEV_ATTR_MULTICAST_FAST_LEAVE] = { .name = "multicast_fast_leave", . type = BLOBMSG_TYPE_BOOL },
-+ 	[DEV_ATTR_MULTICAST] = { .name ="multicast", .type = BLOBMSG_TYPE_BOOL },
-+@@ -223,6 +224,7 @@ device_merge_settings(struct device *dev, struct device_settings *n)
-+ 	n->multicast = s->flags & DEV_OPT_MULTICAST ?
-+ 		s->multicast : os->multicast;
-+ 	n->multicast_to_unicast = s->multicast_to_unicast;
-++	n->multicast_wakeupcall = s->multicast_wakeupcall;
-+ 	n->multicast_router = s->multicast_router;
-+ 	n->multicast_fast_leave = s->multicast_fast_leave;
-+ 	n->learning = s->learning;
-+@@ -330,6 +332,11 @@ device_init_settings(struct device *dev, struct blob_attr **tb)
-+ 		s->flags |= DEV_OPT_MULTICAST_TO_UNICAST;
-+ 	}
-+ 
-++	if ((cur = tb[DEV_ATTR_MULTICAST_WAKEUPCALL])) {
-++		s->multicast_wakeupcall = blobmsg_get_u32(cur);
-++		s->flags |= DEV_OPT_MULTICAST_WAKEUPCALL;
-++	}
-++
-+ 	if ((cur = tb[DEV_ATTR_MULTICAST_ROUTER])) {
-+ 		s->multicast_router = blobmsg_get_u32(cur);
-+ 		if (s->multicast_router <= 2)
-+@@ -1028,6 +1035,8 @@ device_dump_status(struct blob_buf *b, struct device *dev)
-+ 			blobmsg_add_u32(b, "dadtransmits", st.dadtransmits);
-+ 		if (st.flags & DEV_OPT_MULTICAST_TO_UNICAST)
-+ 			blobmsg_add_u8(b, "multicast_to_unicast", st.multicast_to_unicast);
-++		if (st.flags & DEV_OPT_MULTICAST_WAKEUPCALL)
-++			blobmsg_add_u32(b, "multicast_wakeupcall", st.multicast_wakeupcall);
-+ 		if (st.flags & DEV_OPT_MULTICAST_ROUTER)
-+ 			blobmsg_add_u32(b, "multicast_router", st.multicast_router);
-+ 		if (st.flags & DEV_OPT_MULTICAST_FAST_LEAVE)
-+diff --git a/device.h b/device.h
-+index 5f3fae2..4935db0 100644
-+--- a/device.h
-++++ b/device.h
-+@@ -42,6 +42,7 @@ enum {
-+ 	DEV_ATTR_NEIGHREACHABLETIME,
-+ 	DEV_ATTR_DADTRANSMITS,
-+ 	DEV_ATTR_MULTICAST_TO_UNICAST,
-++	DEV_ATTR_MULTICAST_WAKEUPCALL,
-+ 	DEV_ATTR_MULTICAST_ROUTER,
-+ 	DEV_ATTR_MULTICAST_FAST_LEAVE,
-+ 	DEV_ATTR_MULTICAST,
-+@@ -95,15 +96,16 @@ enum {
-+ 	DEV_OPT_MTU6			= (1 << 12),
-+ 	DEV_OPT_DADTRANSMITS		= (1 << 13),
-+ 	DEV_OPT_MULTICAST_TO_UNICAST	= (1 << 14),
-+-	DEV_OPT_MULTICAST_ROUTER	= (1 << 15),
-+-	DEV_OPT_MULTICAST		= (1 << 16),
-+-	DEV_OPT_LEARNING		= (1 << 17),
-+-	DEV_OPT_UNICAST_FLOOD		= (1 << 18),
-+-	DEV_OPT_NEIGHGCSTALETIME	= (1 << 19),
-+-	DEV_OPT_MULTICAST_FAST_LEAVE	= (1 << 20),
-+-	DEV_OPT_SENDREDIRECTS		= (1 << 21),
-+-	DEV_OPT_NEIGHLOCKTIME		= (1 << 22),
-+-	DEV_OPT_ISOLATE			= (1 << 23),
-++	DEV_OPT_MULTICAST_WAKEUPCALL	= (1 << 15),
-++	DEV_OPT_MULTICAST_ROUTER	= (1 << 16),
-++	DEV_OPT_MULTICAST		= (1 << 17),
-++	DEV_OPT_LEARNING		= (1 << 18),
-++	DEV_OPT_UNICAST_FLOOD		= (1 << 19),
-++	DEV_OPT_NEIGHGCSTALETIME	= (1 << 20),
-++	DEV_OPT_MULTICAST_FAST_LEAVE	= (1 << 21),
-++	DEV_OPT_SENDREDIRECTS		= (1 << 22),
-++	DEV_OPT_NEIGHLOCKTIME		= (1 << 23),
-++	DEV_OPT_ISOLATE			= (1 << 24),
-+ };
-+ 
-+ /* events broadcasted to all users of a device */
-+@@ -164,6 +166,7 @@ struct device_settings {
-+ 	int neigh4locktime;
-+ 	unsigned int dadtransmits;
-+ 	bool multicast_to_unicast;
-++	unsigned int multicast_wakeupcall;
-+ 	unsigned int multicast_router;
-+ 	bool multicast_fast_leave;
-+ 	bool multicast;
-+diff --git a/system-linux.c b/system-linux.c
-+index acfd40e..f1abccf 100644
-+--- a/system-linux.c
-++++ b/system-linux.c
-+@@ -355,6 +355,11 @@ static void system_bridge_set_multicast_to_unicast(struct device *dev, const cha
-+ 	system_set_dev_sysctl("/sys/class/net/%s/brport/multicast_to_unicast", dev->ifname, val);
-+ }
-+ 
-++static void system_bridge_set_multicast_wakeupcall(struct device *dev, const char *val)
-++{
-++	system_set_dev_sysctl("/sys/class/net/%s/brport/multicast_wakeupcall", dev->ifname, val);
-++}
-++
-+ static void system_bridge_set_multicast_fast_leave(struct device *dev, const char *val)
-+ {
-+ 	system_set_dev_sysctl("/sys/class/net/%s/brport/multicast_fast_leave", dev->ifname, val);
-+@@ -784,8 +789,10 @@ static char *system_get_bridge(const char *name, char *buf, int buflen)
-+ static void
-+ system_bridge_set_wireless(struct device *bridge, struct device *dev)
-+ {
-++	unsigned int mcast_wakeupcall = dev->wireless_ap ? 2 : 0;
-+ 	bool mcast_to_ucast = dev->wireless_ap;
-+ 	bool hairpin = true;
-++	char buf[64];
-+ 
-+ 	if (bridge->settings.flags & DEV_OPT_MULTICAST_TO_UNICAST &&
-+ 	    !bridge->settings.multicast_to_unicast)
-+@@ -796,6 +803,12 @@ system_bridge_set_wireless(struct device *bridge, struct device *dev)
-+ 
-+ 	system_bridge_set_multicast_to_unicast(dev, mcast_to_ucast ? "1" : "0");
-+ 	system_bridge_set_hairpin_mode(dev, hairpin ? "1" : "0");
-++
-++	if (bridge->settings.flags & DEV_OPT_MULTICAST_WAKEUPCALL)
-++		mcast_wakeupcall = dev->settings.multicast_wakeupcall;
-++
-++	snprintf(buf, sizeof(buf), "%u", mcast_wakeupcall);
-++	system_bridge_set_multicast_wakeupcall(dev, buf);
-+ }
-+ 
-+ int system_bridge_addif(struct device *bridge, struct device *dev)
-+-- 
-+2.27.0
-+
-diff --git a/target/linux/generic/backport-4.14/111-bridge-simplify-ip_mc_check_igmp-and-ipv6_mc_check_m.patch b/target/linux/generic/backport-4.14/111-bridge-simplify-ip_mc_check_igmp-and-ipv6_mc_check_m.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..e8f60cc4cc267d3bb1c38770b7e1447765514f2b
---- /dev/null
-+++ b/target/linux/generic/backport-4.14/111-bridge-simplify-ip_mc_check_igmp-and-ipv6_mc_check_m.patch
-@@ -0,0 +1,506 @@
-+From 2a0f1172f505121c75313f6cce2874476b82ce45 Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@c0d3.blue>
-+Date: Mon, 21 Jan 2019 07:26:25 +0100
-+Subject: [PATCH] bridge: simplify ip_mc_check_igmp() and
-+ ipv6_mc_check_mld() calls
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+This patch refactors ip_mc_check_igmp(), ipv6_mc_check_mld() and
-+their callers (more precisely, the Linux bridge) to not rely on
-+the skb_trimmed parameter anymore.
-+
-+An skb with its tail trimmed to the IP packet length was initially
-+introduced for the following three reasons:
-+
-+1) To be able to verify the ICMPv6 checksum.
-+2) To be able to distinguish the version of an IGMP or MLD query.
-+   They are distinguishable only by their size.
-+3) To avoid parsing data for an IGMPv3 or MLDv2 report that is
-+   beyond the IP packet but still within the skb.
-+
-+The first case still uses a cloned and potentially trimmed skb to
-+verfiy. However, there is no need to propagate it to the caller.
-+For the second and third case explicit IP packet length checks were
-+added.
-+
-+This hopefully makes ip_mc_check_igmp() and ipv6_mc_check_mld() easier
-+to read and verfiy, as well as easier to use.
-+
-+Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
-+Signed-off-by: David S. Miller <davem@davemloft.net>
-+---
-+ include/linux/igmp.h       | 11 +++++++-
-+ include/linux/ip.h         |  5 ++++
-+ include/linux/ipv6.h       |  6 ++++
-+ include/net/addrconf.h     | 12 +++++++-
-+ net/batman-adv/multicast.c |  4 +--
-+ net/bridge/br_multicast.c  | 56 ++++++++++++++++++--------------------
-+ net/ipv4/igmp.c            | 23 +++-------------
-+ net/ipv6/mcast_snoop.c     | 24 +++-------------
-+ 8 files changed, 69 insertions(+), 72 deletions(-)
-+
-+diff --git a/include/linux/igmp.h b/include/linux/igmp.h
-+index f8231854b5d6..858143489a2a 100644
-+--- a/include/linux/igmp.h
-++++ b/include/linux/igmp.h
-+@@ -18,6 +18,7 @@
-+ #include <linux/skbuff.h>
-+ #include <linux/timer.h>
-+ #include <linux/in.h>
-++#include <linux/ip.h>
-+ #include <linux/refcount.h>
-+ #include <uapi/linux/igmp.h>
-+ 
-+@@ -106,6 +107,14 @@ struct ip_mc_list {
-+ #define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)
-+ #define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value)
-+ 
-++static inline int ip_mc_may_pull(struct sk_buff *skb, unsigned int len)
-++{
-++	if (skb_transport_offset(skb) + ip_transport_len(skb) < len)
-++		return -EINVAL;
-++
-++	return pskb_may_pull(skb, len);
-++}
-++
-+ extern int ip_check_mc_rcu(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u8 proto);
-+ extern int igmp_rcv(struct sk_buff *);
-+ extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
-+@@ -128,6 +137,6 @@ extern void ip_mc_unmap(struct in_device *);
-+ extern void ip_mc_remap(struct in_device *);
-+ extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
-+ extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
-+-int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed);
-++int ip_mc_check_igmp(struct sk_buff *skb);
-+ 
-+ #endif
-+diff --git a/include/linux/ip.h b/include/linux/ip.h
-+index 492bc6513533..482b7b7c9f30 100644
-+--- a/include/linux/ip.h
-++++ b/include/linux/ip.h
-+@@ -34,4 +34,9 @@ static inline struct iphdr *ipip_hdr(const struct sk_buff *skb)
-+ {
-+ 	return (struct iphdr *)skb_transport_header(skb);
-+ }
-++
-++static inline unsigned int ip_transport_len(const struct sk_buff *skb)
-++{
-++	return ntohs(ip_hdr(skb)->tot_len) - skb_network_header_len(skb);
-++}
-+ #endif	/* _LINUX_IP_H */
-+diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
-+index 067a6fa675ed..f2128d94a680 100644
-+--- a/include/linux/ipv6.h
-++++ b/include/linux/ipv6.h
-+@@ -103,6 +103,12 @@ static inline struct ipv6hdr *ipipv6_hdr(const struct sk_buff *skb)
-+ 	return (struct ipv6hdr *)skb_transport_header(skb);
-+ }
-+ 
-++static inline unsigned int ipv6_transport_len(const struct sk_buff *skb)
-++{
-++	return ntohs(ipv6_hdr(skb)->payload_len) + sizeof(struct ipv6hdr) -
-++	       skb_network_header_len(skb);
-++}
-++
-+ /* 
-+    This structure contains results of exthdrs parsing
-+    as offsets from skb->nh.
-+diff --git a/include/net/addrconf.h b/include/net/addrconf.h
-+index f30ee99a1d72..0eb1e1f6ea9a 100644
-+--- a/include/net/addrconf.h
-++++ b/include/net/addrconf.h
-+@@ -49,6 +49,7 @@ struct prefix_info {
-+ 	struct in6_addr		prefix;
-+ };
-+ 
-++#include <linux/ipv6.h>
-+ #include <linux/netdevice.h>
-+ #include <net/if_inet6.h>
-+ #include <net/ipv6.h>
-+@@ -189,6 +190,15 @@ u32 ipv6_addr_label(struct net *net, const struct in6_addr *addr,
-+ /*
-+  *	multicast prototypes (mcast.c)
-+  */
-++static inline int ipv6_mc_may_pull(struct sk_buff *skb,
-++				   unsigned int len)
-++{
-++	if (skb_transport_offset(skb) + ipv6_transport_len(skb) < len)
-++		return -EINVAL;
-++
-++	return pskb_may_pull(skb, len);
-++}
-++
-+ int ipv6_sock_mc_join(struct sock *sk, int ifindex,
-+ 		      const struct in6_addr *addr);
-+ int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
-+@@ -207,7 +217,7 @@ void ipv6_mc_unmap(struct inet6_dev *idev);
-+ void ipv6_mc_remap(struct inet6_dev *idev);
-+ void ipv6_mc_init_dev(struct inet6_dev *idev);
-+ void ipv6_mc_destroy_dev(struct inet6_dev *idev);
-+-int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed);
-++int ipv6_mc_check_mld(struct sk_buff *skb);
-+ void addrconf_dad_failure(struct inet6_ifaddr *ifp);
-+ 
-+ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
-+diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
-+index d47865e0e697..9b8f118c69f9 100644
-+--- a/net/batman-adv/multicast.c
-++++ b/net/batman-adv/multicast.c
-+@@ -611,7 +611,7 @@ static void batadv_mcast_mla_update(struct work_struct *work)
-+  */
-+ static bool batadv_mcast_is_report_ipv4(struct sk_buff *skb)
-+ {
-+-	if (ip_mc_check_igmp(skb, NULL) < 0)
-++	if (ip_mc_check_igmp(skb) < 0)
-+ 		return false;
-+ 
-+ 	switch (igmp_hdr(skb)->type) {
-+@@ -677,7 +677,7 @@ static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
-+  */
-+ static bool batadv_mcast_is_report_ipv6(struct sk_buff *skb)
-+ {
-+-	if (ipv6_mc_check_mld(skb, NULL) < 0)
-++	if (ipv6_mc_check_mld(skb) < 0)
-+ 		return false;
-+ 
-+ 	switch (icmp6_hdr(skb)->icmp6_type) {
-+diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
-+index b24782d53474..5224e9b3c46d 100644
-+--- a/net/bridge/br_multicast.c
-++++ b/net/bridge/br_multicast.c
-+@@ -1128,7 +1128,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
-+ 
-+ 	for (i = 0; i < num; i++) {
-+ 		len += sizeof(*grec);
-+-		if (!pskb_may_pull(skb, len))
-++		if (!ip_mc_may_pull(skb, len))
-+ 			return -EINVAL;
-+ 
-+ 		grec = (void *)(skb->data + len - sizeof(*grec));
-+@@ -1137,7 +1137,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
-+ 		nsrcs = ntohs(grec->grec_nsrcs);
-+ 
-+ 		len += nsrcs * 4;
-+-		if (!pskb_may_pull(skb, len))
-++		if (!ip_mc_may_pull(skb, len))
-+ 			return -EINVAL;
-+ 
-+ 		/* We treat this as an IGMPv2 report for now. */
-+@@ -1176,15 +1176,17 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
-+ 					struct sk_buff *skb,
-+ 					u16 vid)
-+ {
-++	unsigned int nsrcs_offset;
-+ 	const unsigned char *src;
-+ 	struct icmp6hdr *icmp6h;
-+ 	struct mld2_grec *grec;
-++	unsigned int grec_len;
-+ 	int i;
-+ 	int len;
-+ 	int num;
-+ 	int err = 0;
-+ 
-+-	if (!pskb_may_pull(skb, sizeof(*icmp6h)))
-++	if (!ipv6_mc_may_pull(skb, sizeof(*icmp6h)))
-+ 		return -EINVAL;
-+ 
-+ 	icmp6h = icmp6_hdr(skb);
-+@@ -1195,23 +1197,26 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
-+ 		__be16 *_nsrcs, __nsrcs;
-+ 		u16 nsrcs;
-+ 
-+-		_nsrcs = skb_header_pointer(skb,
-+-					    len + offsetof(struct mld2_grec,
-+-							   grec_nsrcs),
-++		nsrcs_offset = len + offsetof(struct mld2_grec, grec_nsrcs);
-++
-++		if (skb_transport_offset(skb) + ipv6_transport_len(skb) <
-++		    nsrcs_offset + sizeof(_nsrcs))
-++			return -EINVAL;
-++
-++		_nsrcs = skb_header_pointer(skb, nsrcs_offset,
-+ 					    sizeof(__nsrcs), &__nsrcs);
-+ 		if (!_nsrcs)
-+ 			return -EINVAL;
-+ 
-+ 		nsrcs = ntohs(*_nsrcs);
-++		grec_len = sizeof(*grec) +
-++			   sizeof(struct in6_addr) * nsrcs;
-+ 
-+-		if (!pskb_may_pull(skb,
-+-				   len + sizeof(*grec) +
-+-				   sizeof(struct in6_addr) * nsrcs))
-++		if (!ipv6_mc_may_pull(skb, len + grec_len))
-+ 			return -EINVAL;
-+ 
-+ 		grec = (struct mld2_grec *)(skb->data + len);
-+-		len += sizeof(*grec) +
-+-		       sizeof(struct in6_addr) * nsrcs;
-++		len += grec_len;
-+ 
-+ 		/* We treat these as MLDv1 reports for now. */
-+ 		switch (grec->grec_type) {
-+@@ -1403,6 +1408,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
-+ 				  struct sk_buff *skb,
-+ 				  u16 vid)
-+ {
-++	unsigned int transport_len = ip_transport_len(skb);
-+ 	const struct iphdr *iph = ip_hdr(skb);
-+ 	struct igmphdr *ih = igmp_hdr(skb);
-+ 	struct net_bridge_mdb_entry *mp;
-+@@ -1412,7 +1418,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
-+ 	struct br_ip saddr;
-+ 	unsigned long max_delay;
-+ 	unsigned long now = jiffies;
-+-	unsigned int offset = skb_transport_offset(skb);
-+ 	__be32 group;
-+ 	int err = 0;
-+ 
-+@@ -1423,14 +1428,14 @@ static int br_ip4_multicast_query(struct net_bridge *br,
-+ 
-+ 	group = ih->group;
-+ 
-+-	if (skb->len == offset + sizeof(*ih)) {
-++	if (transport_len == sizeof(*ih)) {
-+ 		max_delay = ih->code * (HZ / IGMP_TIMER_SCALE);
-+ 
-+ 		if (!max_delay) {
-+ 			max_delay = 10 * HZ;
-+ 			group = 0;
-+ 		}
-+-	} else if (skb->len >= offset + sizeof(*ih3)) {
-++	} else if (transport_len >= sizeof(*ih3)) {
-+ 		ih3 = igmpv3_query_hdr(skb);
-+ 		if (ih3->nsrcs)
-+ 			goto out;
-+@@ -1482,6 +1487,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
-+ 				  struct sk_buff *skb,
-+ 				  u16 vid)
-+ {
-++	unsigned int transport_len = ipv6_transport_len(skb);
-+ 	struct mld_msg *mld;
-+ 	struct net_bridge_mdb_entry *mp;
-+ 	struct mld2_query *mld2q;
-+@@ -1500,7 +1506,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
-+ 	    (port && port->state == BR_STATE_DISABLED))
-+ 		goto out;
-+ 
-+-	if (skb->len == offset + sizeof(*mld)) {
-++	if (transport_len == sizeof(*mld)) {
-+ 		if (!pskb_may_pull(skb, offset + sizeof(*mld))) {
-+ 			err = -EINVAL;
-+ 			goto out;
-+@@ -1771,12 +1777,11 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
-+ 				 struct sk_buff *skb,
-+ 				 u16 vid)
-+ {
-+-	struct sk_buff *skb_trimmed = NULL;
-+ 	const unsigned char *src;
-+ 	struct igmphdr *ih;
-+ 	int err;
-+ 
-+-	err = ip_mc_check_igmp(skb, &skb_trimmed);
-++	err = ip_mc_check_igmp(skb);
-+ 
-+ 	if (err == -ENOMSG) {
-+ 		if (!ipv4_is_local_multicast(ip_hdr(skb)->daddr)) {
-+@@ -1802,19 +1807,16 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
-+ 		err = br_ip4_multicast_add_group(br, port, ih->group, vid, src);
-+ 		break;
-+ 	case IGMPV3_HOST_MEMBERSHIP_REPORT:
-+-		err = br_ip4_multicast_igmp3_report(br, port, skb_trimmed, vid);
-++		err = br_ip4_multicast_igmp3_report(br, port, skb, vid);
-+ 		break;
-+ 	case IGMP_HOST_MEMBERSHIP_QUERY:
-+-		err = br_ip4_multicast_query(br, port, skb_trimmed, vid);
-++		err = br_ip4_multicast_query(br, port, skb, vid);
-+ 		break;
-+ 	case IGMP_HOST_LEAVE_MESSAGE:
-+ 		br_ip4_multicast_leave_group(br, port, ih->group, vid, src);
-+ 		break;
-+ 	}
-+ 
-+-	if (skb_trimmed && skb_trimmed != skb)
-+-		kfree_skb(skb_trimmed);
-+-
-+ 	br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp,
-+ 			   BR_MCAST_DIR_RX);
-+ 
-+@@ -1827,12 +1829,11 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
-+ 				 struct sk_buff *skb,
-+ 				 u16 vid)
-+ {
-+-	struct sk_buff *skb_trimmed = NULL;
-+ 	const unsigned char *src;
-+ 	struct mld_msg *mld;
-+ 	int err;
-+ 
-+-	err = ipv6_mc_check_mld(skb, &skb_trimmed);
-++	err = ipv6_mc_check_mld(skb);
-+ 
-+ 	if (err == -ENOMSG) {
-+ 		if (!ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr))
-+@@ -1854,10 +1855,10 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
-+ 						 src);
-+ 		break;
-+ 	case ICMPV6_MLD2_REPORT:
-+-		err = br_ip6_multicast_mld2_report(br, port, skb_trimmed, vid);
-++		err = br_ip6_multicast_mld2_report(br, port, skb, vid);
-+ 		break;
-+ 	case ICMPV6_MGM_QUERY:
-+-		err = br_ip6_multicast_query(br, port, skb_trimmed, vid);
-++		err = br_ip6_multicast_query(br, port, skb, vid);
-+ 		break;
-+ 	case ICMPV6_MGM_REDUCTION:
-+ 		src = eth_hdr(skb)->h_source;
-+@@ -1865,9 +1866,6 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
-+ 		break;
-+ 	}
-+ 
-+-	if (skb_trimmed && skb_trimmed != skb)
-+-		kfree_skb(skb_trimmed);
-+-
-+ 	br_multicast_count(br, port, skb, BR_INPUT_SKB_CB(skb)->igmp,
-+ 			   BR_MCAST_DIR_RX);
-+ 
-+diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
-+index b6f0ee01f2e0..d6a222032be3 100644
-+--- a/net/ipv4/igmp.c
-++++ b/net/ipv4/igmp.c
-+@@ -1538,7 +1538,7 @@ static inline __sum16 ip_mc_validate_checksum(struct sk_buff *skb)
-+ 	return skb_checksum_simple_validate(skb);
-+ }
-+ 
-+-static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
-++static int __ip_mc_check_igmp(struct sk_buff *skb)
-+ 
-+ {
-+ 	struct sk_buff *skb_chk;
-+@@ -1560,16 +1560,10 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
-+ 	if (ret)
-+ 		goto err;
-+ 
-+-	if (skb_trimmed)
-+-		*skb_trimmed = skb_chk;
-+-	/* free now unneeded clone */
-+-	else if (skb_chk != skb)
-+-		kfree_skb(skb_chk);
-+-
-+ 	ret = 0;
-+ 
-+ err:
-+-	if (ret && skb_chk && skb_chk != skb)
-++	if (skb_chk && skb_chk != skb)
-+ 		kfree_skb(skb_chk);
-+ 
-+ 	return ret;
-+@@ -1578,7 +1572,6 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
-+ /**
-+  * ip_mc_check_igmp - checks whether this is a sane IGMP packet
-+  * @skb: the skb to validate
-+- * @skb_trimmed: to store an skb pointer trimmed to IPv4 packet tail (optional)
-+  *
-+  * Checks whether an IPv4 packet is a valid IGMP packet. If so sets
-+  * skb transport header accordingly and returns zero.
-+@@ -1588,18 +1581,10 @@ static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
-+  * -ENOMSG: IP header validation succeeded but it is not an IGMP packet.
-+  * -ENOMEM: A memory allocation failure happened.
-+  *
-+- * Optionally, an skb pointer might be provided via skb_trimmed (or set it
-+- * to NULL): After parsing an IGMP packet successfully it will point to
-+- * an skb which has its tail aligned to the IP packet end. This might
-+- * either be the originally provided skb or a trimmed, cloned version if
-+- * the skb frame had data beyond the IP packet. A cloned skb allows us
-+- * to leave the original skb and its full frame unchanged (which might be
-+- * desirable for layer 2 frame jugglers).
-+- *
-+  * Caller needs to set the skb network header and free any returned skb if it
-+  * differs from the provided skb.
-+  */
-+-int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
-++int ip_mc_check_igmp(struct sk_buff *skb)
-+ {
-+ 	int ret = ip_mc_check_iphdr(skb);
-+ 
-+@@ -1609,7 +1594,7 @@ int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed)
-+ 	if (ip_hdr(skb)->protocol != IPPROTO_IGMP)
-+ 		return -ENOMSG;
-+ 
-+-	return __ip_mc_check_igmp(skb, skb_trimmed);
-++	return __ip_mc_check_igmp(skb);
-+ }
-+ EXPORT_SYMBOL(ip_mc_check_igmp);
-+ 
-+diff --git a/net/ipv6/mcast_snoop.c b/net/ipv6/mcast_snoop.c
-+index 9405b04eecc6..1a917dc80d5e 100644
-+--- a/net/ipv6/mcast_snoop.c
-++++ b/net/ipv6/mcast_snoop.c
-+@@ -136,8 +136,7 @@ static inline __sum16 ipv6_mc_validate_checksum(struct sk_buff *skb)
-+ 	return skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo);
-+ }
-+ 
-+-static int __ipv6_mc_check_mld(struct sk_buff *skb,
-+-			       struct sk_buff **skb_trimmed)
-++static int __ipv6_mc_check_mld(struct sk_buff *skb)
-+ 
-+ {
-+ 	struct sk_buff *skb_chk = NULL;
-+@@ -160,16 +159,10 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb,
-+ 	if (ret)
-+ 		goto err;
-+ 
-+-	if (skb_trimmed)
-+-		*skb_trimmed = skb_chk;
-+-	/* free now unneeded clone */
-+-	else if (skb_chk != skb)
-+-		kfree_skb(skb_chk);
-+-
-+ 	ret = 0;
-+ 
-+ err:
-+-	if (ret && skb_chk && skb_chk != skb)
-++	if (skb_chk && skb_chk != skb)
-+ 		kfree_skb(skb_chk);
-+ 
-+ 	return ret;
-+@@ -178,7 +171,6 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb,
-+ /**
-+  * ipv6_mc_check_mld - checks whether this is a sane MLD packet
-+  * @skb: the skb to validate
-+- * @skb_trimmed: to store an skb pointer trimmed to IPv6 packet tail (optional)
-+  *
-+  * Checks whether an IPv6 packet is a valid MLD packet. If so sets
-+  * skb transport header accordingly and returns zero.
-+@@ -188,18 +180,10 @@ static int __ipv6_mc_check_mld(struct sk_buff *skb,
-+  * -ENOMSG: IP header validation succeeded but it is not an MLD packet.
-+  * -ENOMEM: A memory allocation failure happened.
-+  *
-+- * Optionally, an skb pointer might be provided via skb_trimmed (or set it
-+- * to NULL): After parsing an MLD packet successfully it will point to
-+- * an skb which has its tail aligned to the IP packet end. This might
-+- * either be the originally provided skb or a trimmed, cloned version if
-+- * the skb frame had data beyond the IP packet. A cloned skb allows us
-+- * to leave the original skb and its full frame unchanged (which might be
-+- * desirable for layer 2 frame jugglers).
-+- *
-+  * Caller needs to set the skb network header and free any returned skb if it
-+  * differs from the provided skb.
-+  */
-+-int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed)
-++int ipv6_mc_check_mld(struct sk_buff *skb)
-+ {
-+ 	int ret;
-+ 
-+@@ -211,6 +195,6 @@ int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed)
-+ 	if (ret < 0)
-+ 		return ret;
-+ 
-+-	return __ipv6_mc_check_mld(skb, skb_trimmed);
-++	return __ipv6_mc_check_mld(skb);
-+ }
-+ EXPORT_SYMBOL(ipv6_mc_check_mld);
-+-- 
-+2.27.0
-+
-diff --git a/target/linux/generic/backport-4.14/112-bridge-simplify-ip_mc_check_igmp-and-ipv6_mc_check_m.patch b/target/linux/generic/backport-4.14/112-bridge-simplify-ip_mc_check_igmp-and-ipv6_mc_check_m.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..f6478bd664c8e2c366ba11c1fb9690ff77d22223
---- /dev/null
-+++ b/target/linux/generic/backport-4.14/112-bridge-simplify-ip_mc_check_igmp-and-ipv6_mc_check_m.patch
-@@ -0,0 +1,234 @@
-+From 96d914ab71c2540e8c492cbe6877854d17a5ec4c Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@c0d3.blue>
-+Date: Mon, 21 Jan 2019 07:26:26 +0100
-+Subject: [PATCH] bridge: simplify ip_mc_check_igmp() and
-+ ipv6_mc_check_mld() internals
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+With this patch the internal use of the skb_trimmed is reduced to
-+the ICMPv6/IGMP checksum verification. And for the length checks
-+the newly introduced helper functions are used instead of calculating
-+and checking with skb->len directly.
-+
-+These changes should hopefully make it easier to verify that length
-+checks are performed properly.
-+
-+Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
-+Signed-off-by: David S. Miller <davem@davemloft.net>
-+---
-+ net/ipv4/igmp.c        | 51 +++++++++++++++-------------------
-+ net/ipv6/mcast_snoop.c | 62 ++++++++++++++++++++----------------------
-+ 2 files changed, 52 insertions(+), 61 deletions(-)
-+
-+diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
-+index d6a222032be3..9033c8cb0e95 100644
-+--- a/net/ipv4/igmp.c
-++++ b/net/ipv4/igmp.c
-+@@ -1487,22 +1487,22 @@ static int ip_mc_check_igmp_reportv3(struct sk_buff *skb)
-+ 
-+ 	len += sizeof(struct igmpv3_report);
-+ 
-+-	return pskb_may_pull(skb, len) ? 0 : -EINVAL;
-++	return ip_mc_may_pull(skb, len) ? 0 : -EINVAL;
-+ }
-+ 
-+ static int ip_mc_check_igmp_query(struct sk_buff *skb)
-+ {
-+-	unsigned int len = skb_transport_offset(skb);
-+-
-+-	len += sizeof(struct igmphdr);
-+-	if (skb->len < len)
-+-		return -EINVAL;
-++	unsigned int transport_len = ip_transport_len(skb);
-++	unsigned int len;
-+ 
-+ 	/* IGMPv{1,2}? */
-+-	if (skb->len != len) {
-++	if (transport_len != sizeof(struct igmphdr)) {
-+ 		/* or IGMPv3? */
-+-		len += sizeof(struct igmpv3_query) - sizeof(struct igmphdr);
-+-		if (skb->len < len || !pskb_may_pull(skb, len))
-++		if (transport_len < sizeof(struct igmpv3_query))
-++			return -EINVAL;
-++
-++		len = skb_transport_offset(skb) + sizeof(struct igmpv3_query);
-++		if (!ip_mc_may_pull(skb, len))
-+ 			return -EINVAL;
-+ 	}
-+ 
-+@@ -1538,35 +1538,24 @@ static inline __sum16 ip_mc_validate_checksum(struct sk_buff *skb)
-+ 	return skb_checksum_simple_validate(skb);
-+ }
-+ 
-+-static int __ip_mc_check_igmp(struct sk_buff *skb)
-+-
-++static int ip_mc_check_igmp_csum(struct sk_buff *skb)
-+ {
-+-	struct sk_buff *skb_chk;
-+-	unsigned int transport_len;
-+ 	unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr);
-+-	int ret = -EINVAL;
-++	unsigned int transport_len = ip_transport_len(skb);
-++	struct sk_buff *skb_chk;
-+ 
-+-	transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb);
-++	if (!ip_mc_may_pull(skb, len))
-++		return -EINVAL;
-+ 
-+ 	skb_chk = skb_checksum_trimmed(skb, transport_len,
-+ 				       ip_mc_validate_checksum);
-+ 	if (!skb_chk)
-+-		goto err;
-++		return -EINVAL;
-+ 
-+-	if (!pskb_may_pull(skb_chk, len))
-+-		goto err;
-+-
-+-	ret = ip_mc_check_igmp_msg(skb_chk);
-+-	if (ret)
-+-		goto err;
-+-
-+-	ret = 0;
-+-
-+-err:
-+-	if (skb_chk && skb_chk != skb)
-++	if (skb_chk != skb)
-+ 		kfree_skb(skb_chk);
-+ 
-+-	return ret;
-++	return 0;
-+ }
-+ 
-+ /**
-+@@ -1594,7 +1583,11 @@ int ip_mc_check_igmp(struct sk_buff *skb)
-+ 	if (ip_hdr(skb)->protocol != IPPROTO_IGMP)
-+ 		return -ENOMSG;
-+ 
-+-	return __ip_mc_check_igmp(skb);
-++	ret = ip_mc_check_igmp_csum(skb);
-++	if (ret < 0)
-++		return ret;
-++
-++	return ip_mc_check_igmp_msg(skb);
-+ }
-+ EXPORT_SYMBOL(ip_mc_check_igmp);
-+ 
-+diff --git a/net/ipv6/mcast_snoop.c b/net/ipv6/mcast_snoop.c
-+index 1a917dc80d5e..a72ddfc40eb3 100644
-+--- a/net/ipv6/mcast_snoop.c
-++++ b/net/ipv6/mcast_snoop.c
-+@@ -77,27 +77,27 @@ static int ipv6_mc_check_mld_reportv2(struct sk_buff *skb)
-+ 
-+ 	len += sizeof(struct mld2_report);
-+ 
-+-	return pskb_may_pull(skb, len) ? 0 : -EINVAL;
-++	return ipv6_mc_may_pull(skb, len) ? 0 : -EINVAL;
-+ }
-+ 
-+ static int ipv6_mc_check_mld_query(struct sk_buff *skb)
-+ {
-++	unsigned int transport_len = ipv6_transport_len(skb);
-+ 	struct mld_msg *mld;
-+-	unsigned int len = skb_transport_offset(skb);
-++	unsigned int len;
-+ 
-+ 	/* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
-+ 	if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL))
-+ 		return -EINVAL;
-+ 
-+-	len += sizeof(struct mld_msg);
-+-	if (skb->len < len)
-+-		return -EINVAL;
-+-
-+ 	/* MLDv1? */
-+-	if (skb->len != len) {
-++	if (transport_len != sizeof(struct mld_msg)) {
-+ 		/* or MLDv2? */
-+-		len += sizeof(struct mld2_query) - sizeof(struct mld_msg);
-+-		if (skb->len < len || !pskb_may_pull(skb, len))
-++		if (transport_len < sizeof(struct mld2_query))
-++			return -EINVAL;
-++
-++		len = skb_transport_offset(skb) + sizeof(struct mld2_query);
-++		if (!ipv6_mc_may_pull(skb, len))
-+ 			return -EINVAL;
-+ 	}
-+ 
-+@@ -115,7 +115,13 @@ static int ipv6_mc_check_mld_query(struct sk_buff *skb)
-+ 
-+ static int ipv6_mc_check_mld_msg(struct sk_buff *skb)
-+ {
-+-	struct mld_msg *mld = (struct mld_msg *)skb_transport_header(skb);
-++	unsigned int len = skb_transport_offset(skb) + sizeof(struct mld_msg);
-++	struct mld_msg *mld;
-++
-++	if (!ipv6_mc_may_pull(skb, len))
-++		return -EINVAL;
-++
-++	mld = (struct mld_msg *)skb_transport_header(skb);
-+ 
-+ 	switch (mld->mld_type) {
-+ 	case ICMPV6_MGM_REDUCTION:
-+@@ -136,36 +142,24 @@ static inline __sum16 ipv6_mc_validate_checksum(struct sk_buff *skb)
-+ 	return skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo);
-+ }
-+ 
-+-static int __ipv6_mc_check_mld(struct sk_buff *skb)
-+-
-++static int ipv6_mc_check_icmpv6(struct sk_buff *skb)
-+ {
-+-	struct sk_buff *skb_chk = NULL;
-+-	unsigned int transport_len;
-+-	unsigned int len = skb_transport_offset(skb) + sizeof(struct mld_msg);
-+-	int ret = -EINVAL;
-++	unsigned int len = skb_transport_offset(skb) + sizeof(struct icmp6hdr);
-++	unsigned int transport_len = ipv6_transport_len(skb);
-++	struct sk_buff *skb_chk;
-+ 
-+-	transport_len = ntohs(ipv6_hdr(skb)->payload_len);
-+-	transport_len -= skb_transport_offset(skb) - sizeof(struct ipv6hdr);
-++	if (!ipv6_mc_may_pull(skb, len))
-++		return -EINVAL;
-+ 
-+ 	skb_chk = skb_checksum_trimmed(skb, transport_len,
-+ 				       ipv6_mc_validate_checksum);
-+ 	if (!skb_chk)
-+-		goto err;
-++		return -EINVAL;
-+ 
-+-	if (!pskb_may_pull(skb_chk, len))
-+-		goto err;
-+-
-+-	ret = ipv6_mc_check_mld_msg(skb_chk);
-+-	if (ret)
-+-		goto err;
-+-
-+-	ret = 0;
-+-
-+-err:
-+-	if (skb_chk && skb_chk != skb)
-++	if (skb_chk != skb)
-+ 		kfree_skb(skb_chk);
-+ 
-+-	return ret;
-++	return 0;
-+ }
-+ 
-+ /**
-+@@ -195,6 +189,10 @@ int ipv6_mc_check_mld(struct sk_buff *skb)
-+ 	if (ret < 0)
-+ 		return ret;
-+ 
-+-	return __ipv6_mc_check_mld(skb);
-++	ret = ipv6_mc_check_icmpv6(skb);
-++	if (ret < 0)
-++		return ret;
-++
-++	return ipv6_mc_check_mld_msg(skb);
-+ }
-+ EXPORT_SYMBOL(ipv6_mc_check_mld);
-+-- 
-+2.27.0
-+
-diff --git a/target/linux/generic/backport-4.14/113-bridge-join-all-snoopers-multicast-address.patch b/target/linux/generic/backport-4.14/113-bridge-join-all-snoopers-multicast-address.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..d98a80ffd5c28ab03deb17acd025a8c323898922
---- /dev/null
-+++ b/target/linux/generic/backport-4.14/113-bridge-join-all-snoopers-multicast-address.patch
-@@ -0,0 +1,174 @@
-+From 8fec90b6958b01ea8487cf9c821c39067644756a Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@c0d3.blue>
-+Date: Mon, 21 Jan 2019 07:26:27 +0100
-+Subject: [PATCH] bridge: join all-snoopers multicast address
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+Next to snooping IGMP/MLD queries RFC4541, section 2.1.1.a) recommends
-+to snoop multicast router advertisements to detect multicast routers.
-+
-+Multicast router advertisements are sent to an "all-snoopers"
-+multicast address. To be able to receive them reliably, we need to
-+join this group.
-+
-+Otherwise other snooping switches might refrain from forwarding these
-+advertisements to us.
-+
-+Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
-+Signed-off-by: David S. Miller <davem@davemloft.net>
-+---
-+ include/uapi/linux/in.h   |  9 ++---
-+ net/bridge/br_multicast.c | 72 ++++++++++++++++++++++++++++++++++++++-
-+ net/ipv6/mcast.c          |  2 ++
-+ 3 files changed, 78 insertions(+), 5 deletions(-)
-+
-+diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h
-+index 48e8a225b985..478443169386 100644
-+--- a/include/uapi/linux/in.h
-++++ b/include/uapi/linux/in.h
-+@@ -288,10 +288,11 @@ struct sockaddr_in {
-+ #define	IN_LOOPBACK(a)		((((long int) (a)) & 0xff000000) == 0x7f000000)
-+ 
-+ /* Defines for Multicast INADDR */
-+-#define INADDR_UNSPEC_GROUP   	0xe0000000U	/* 224.0.0.0   */
-+-#define INADDR_ALLHOSTS_GROUP 	0xe0000001U	/* 224.0.0.1   */
-+-#define INADDR_ALLRTRS_GROUP    0xe0000002U	/* 224.0.0.2 */
-+-#define INADDR_MAX_LOCAL_GROUP  0xe00000ffU	/* 224.0.0.255 */
-++#define INADDR_UNSPEC_GROUP		0xe0000000U	/* 224.0.0.0   */
-++#define INADDR_ALLHOSTS_GROUP		0xe0000001U	/* 224.0.0.1   */
-++#define INADDR_ALLRTRS_GROUP		0xe0000002U	/* 224.0.0.2 */
-++#define INADDR_ALLSNOOPERS_GROUP	0xe000006aU	/* 224.0.0.106 */
-++#define INADDR_MAX_LOCAL_GROUP		0xe00000ffU	/* 224.0.0.255 */
-+ #endif
-+ 
-+ /* <asm/byteorder.h> contains the htonl type stuff.. */
-+diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
-+index 5224e9b3c46d..917cc9d13ea9 100644
-+--- a/net/bridge/br_multicast.c
-++++ b/net/bridge/br_multicast.c
-+@@ -1970,6 +1970,68 @@ void br_multicast_init(struct net_bridge *br)
-+ #endif
-+ }
-+ 
-++static void br_ip4_multicast_join_snoopers(struct net_bridge *br)
-++{
-++	struct in_device *in_dev = in_dev_get(br->dev);
-++
-++	if (!in_dev)
-++		return;
-++
-++	ip_mc_inc_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
-++	in_dev_put(in_dev);
-++}
-++
-++#if IS_ENABLED(CONFIG_IPV6)
-++static void br_ip6_multicast_join_snoopers(struct net_bridge *br)
-++{
-++	struct in6_addr addr;
-++
-++	ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a));
-++	ipv6_dev_mc_inc(br->dev, &addr);
-++}
-++#else
-++static inline void br_ip6_multicast_join_snoopers(struct net_bridge *br)
-++{
-++}
-++#endif
-++
-++static void br_multicast_join_snoopers(struct net_bridge *br)
-++{
-++	br_ip4_multicast_join_snoopers(br);
-++	br_ip6_multicast_join_snoopers(br);
-++}
-++
-++static void br_ip4_multicast_leave_snoopers(struct net_bridge *br)
-++{
-++	struct in_device *in_dev = in_dev_get(br->dev);
-++
-++	if (WARN_ON(!in_dev))
-++		return;
-++
-++	ip_mc_dec_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
-++	in_dev_put(in_dev);
-++}
-++
-++#if IS_ENABLED(CONFIG_IPV6)
-++static void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
-++{
-++	struct in6_addr addr;
-++
-++	ipv6_addr_set(&addr, htonl(0xff020000), 0, 0, htonl(0x6a));
-++	ipv6_dev_mc_dec(br->dev, &addr);
-++}
-++#else
-++static inline void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
-++{
-++}
-++#endif
-++
-++static void br_multicast_leave_snoopers(struct net_bridge *br)
-++{
-++	br_ip4_multicast_leave_snoopers(br);
-++	br_ip6_multicast_leave_snoopers(br);
-++}
-++
-+ static void __br_multicast_open(struct net_bridge *br,
-+ 				struct bridge_mcast_own_query *query)
-+ {
-+@@ -1983,6 +2045,9 @@ static void __br_multicast_open(struct net_bridge *br,
-+ 
-+ void br_multicast_open(struct net_bridge *br)
-+ {
-++	if (!br->multicast_disabled)
-++		br_multicast_join_snoopers(br);
-++
-+ 	__br_multicast_open(br, &br->ip4_own_query);
-+ #if IS_ENABLED(CONFIG_IPV6)
-+ 	__br_multicast_open(br, &br->ip6_own_query);
-+@@ -1998,6 +2063,9 @@ void br_multicast_stop(struct net_bridge *br)
-+ 	del_timer_sync(&br->ip6_other_query.timer);
-+ 	del_timer_sync(&br->ip6_own_query.timer);
-+ #endif
-++
-++	if (!br->multicast_disabled)
-++		br_multicast_leave_snoopers(br);
-+ }
-+ 
-+ void br_multicast_dev_del(struct net_bridge *br)
-+@@ -2152,8 +2220,10 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
-+ 
-+ 	br_mc_disabled_update(br->dev, !val);
-+ 	br->multicast_disabled = !val;
-+-	if (br->multicast_disabled)
-++	if (br->multicast_disabled) {
-++		br_multicast_leave_snoopers(br);
-+ 		goto unlock;
-++	}
-+ 
-+ 	if (!netif_running(br->dev))
-+ 		goto unlock;
-+diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
-+index 611dc5d55fa0..d907c938ec1a 100644
-+--- a/net/ipv6/mcast.c
-++++ b/net/ipv6/mcast.c
-+@@ -915,6 +915,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
-+ 	ma_put(mc);
-+ 	return 0;
-+ }
-++EXPORT_SYMBOL(ipv6_dev_mc_inc);
-+ 
-+ /*
-+  *	device multicast group del
-+@@ -962,6 +963,7 @@ int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr)
-+ 
-+ 	return err;
-+ }
-++EXPORT_SYMBOL(ipv6_dev_mc_dec);
-+ 
-+ /*
-+  *	check if the interface/address pair is valid
-+-- 
-+2.27.0
-+
-diff --git a/target/linux/generic/backport-4.14/114-bridge-Snoop-Multicast-Router-Advertisements.patch b/target/linux/generic/backport-4.14/114-bridge-Snoop-Multicast-Router-Advertisements.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..92279ce9ee866dfd006e5937b718ac7bcb7e7c6a
---- /dev/null
-+++ b/target/linux/generic/backport-4.14/114-bridge-Snoop-Multicast-Router-Advertisements.patch
-@@ -0,0 +1,246 @@
-+From 690f6ed25b5fac9408fdebb7b4e8131f5b0a5c86 Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@c0d3.blue>
-+Date: Mon, 21 Jan 2019 07:26:28 +0100
-+Subject: [PATCH] bridge: Snoop Multicast Router Advertisements
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+When multiple multicast routers are present in a broadcast domain then
-+only one of them will be detectable via IGMP/MLD query snooping. The
-+multicast router with the lowest IP address will become the selected and
-+active querier while all other multicast routers will then refrain from
-+sending queries.
-+
-+To detect such rather silent multicast routers, too, RFC4286
-+("Multicast Router Discovery") provides a standardized protocol to
-+detect multicast routers for multicast snooping switches.
-+
-+This patch implements the necessary MRD Advertisement message parsing
-+and after successful processing adds such routers to the internal
-+multicast router list.
-+
-+Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
-+Signed-off-by: David S. Miller <davem@davemloft.net>
-+---
-+ include/linux/in.h          |  5 ++++
-+ include/net/addrconf.h      | 15 ++++++++++
-+ include/uapi/linux/icmpv6.h |  2 ++
-+ include/uapi/linux/igmp.h   |  1 +
-+ net/bridge/br_multicast.c   | 55 +++++++++++++++++++++++++++++++++++++
-+ net/ipv6/mcast_snoop.c      |  5 +++-
-+ 6 files changed, 82 insertions(+), 1 deletion(-)
-+
-+diff --git a/include/linux/in.h b/include/linux/in.h
-+index 31b493734763..435e7f2a513a 100644
-+--- a/include/linux/in.h
-++++ b/include/linux/in.h
-+@@ -60,6 +60,11 @@ static inline bool ipv4_is_lbcast(__be32 addr)
-+ 	return addr == htonl(INADDR_BROADCAST);
-+ }
-+ 
-++static inline bool ipv4_is_all_snoopers(__be32 addr)
-++{
-++	return addr == htonl(INADDR_ALLSNOOPERS_GROUP);
-++}
-++
-+ static inline bool ipv4_is_zeronet(__be32 addr)
-+ {
-+ 	return (addr & htonl(0xff000000)) == htonl(0x00000000);
-+diff --git a/include/net/addrconf.h b/include/net/addrconf.h
-+index 0eb1e1f6ea9a..c93530f9e8e4 100644
-+--- a/include/net/addrconf.h
-++++ b/include/net/addrconf.h
-+@@ -217,6 +217,7 @@ void ipv6_mc_unmap(struct inet6_dev *idev);
-+ void ipv6_mc_remap(struct inet6_dev *idev);
-+ void ipv6_mc_init_dev(struct inet6_dev *idev);
-+ void ipv6_mc_destroy_dev(struct inet6_dev *idev);
-++int ipv6_mc_check_icmpv6(struct sk_buff *skb);
-+ int ipv6_mc_check_mld(struct sk_buff *skb);
-+ void addrconf_dad_failure(struct inet6_ifaddr *ifp);
-+ 
-+@@ -445,6 +446,20 @@ static inline bool ipv6_addr_is_solict_mult(const struct in6_addr *addr)
-+ #endif
-+ }
-+ 
-++static inline bool ipv6_addr_is_all_snoopers(const struct in6_addr *addr)
-++{
-++#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
-++	__be64 *p = (__be64 *)addr;
-++
-++	return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) |
-++		(p[1] ^ cpu_to_be64(0x6a))) == 0UL;
-++#else
-++	return ((addr->s6_addr32[0] ^ htonl(0xff020000)) |
-++		addr->s6_addr32[1] | addr->s6_addr32[2] |
-++		(addr->s6_addr32[3] ^ htonl(0x0000006a))) == 0;
-++#endif
-++}
-++
-+ #ifdef CONFIG_PROC_FS
-+ int if6_proc_init(void);
-+ void if6_proc_exit(void);
-+diff --git a/include/uapi/linux/icmpv6.h b/include/uapi/linux/icmpv6.h
-+index caf8dc019250..325395f56bfa 100644
-+--- a/include/uapi/linux/icmpv6.h
-++++ b/include/uapi/linux/icmpv6.h
-+@@ -108,6 +108,8 @@ struct icmp6hdr {
-+ #define ICMPV6_MOBILE_PREFIX_SOL	146
-+ #define ICMPV6_MOBILE_PREFIX_ADV	147
-+ 
-++#define ICMPV6_MRDISC_ADV		151
-++
-+ /*
-+  *	Codes for Destination Unreachable
-+  */
-+diff --git a/include/uapi/linux/igmp.h b/include/uapi/linux/igmp.h
-+index 7e44ac02ca18..90c28bc466c6 100644
-+--- a/include/uapi/linux/igmp.h
-++++ b/include/uapi/linux/igmp.h
-+@@ -93,6 +93,7 @@ struct igmpv3_query {
-+ #define IGMP_MTRACE_RESP		0x1e
-+ #define IGMP_MTRACE			0x1f
-+ 
-++#define IGMP_MRDISC_ADV			0x30	/* From RFC4286 */
-+ 
-+ /*
-+  *	Use the BSD names for these for compatibility
-+diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
-+index 917cc9d13ea9..8f0bd1133bbd 100644
-+--- a/net/bridge/br_multicast.c
-++++ b/net/bridge/br_multicast.c
-+@@ -14,6 +14,7 @@
-+ #include <linux/export.h>
-+ #include <linux/if_ether.h>
-+ #include <linux/igmp.h>
-++#include <linux/in.h>
-+ #include <linux/jhash.h>
-+ #include <linux/kernel.h>
-+ #include <linux/log2.h>
-+@@ -29,10 +30,12 @@
-+ #include <net/ip.h>
-+ #include <net/switchdev.h>
-+ #if IS_ENABLED(CONFIG_IPV6)
-++#include <linux/icmpv6.h>
-+ #include <net/ipv6.h>
-+ #include <net/mld.h>
-+ #include <net/ip6_checksum.h>
-+ #include <net/addrconf.h>
-++#include <net/ipv6.h>
-+ #endif
-+ 
-+ #include "br_private.h"
-+@@ -1772,6 +1775,19 @@ static void br_multicast_pim(struct net_bridge *br,
-+ 	br_multicast_mark_router(br, port);
-+ }
-+ 
-++static int br_ip4_multicast_mrd_rcv(struct net_bridge *br,
-++				    struct net_bridge_port *port,
-++				    struct sk_buff *skb)
-++{
-++	if (ip_hdr(skb)->protocol != IPPROTO_IGMP ||
-++	    igmp_hdr(skb)->type != IGMP_MRDISC_ADV)
-++		return -ENOMSG;
-++
-++	br_multicast_mark_router(br, port);
-++
-++	return 0;
-++}
-++
-+ static int br_multicast_ipv4_rcv(struct net_bridge *br,
-+ 				 struct net_bridge_port *port,
-+ 				 struct sk_buff *skb,
-+@@ -1789,7 +1805,15 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
-+ 		} else if (pim_ipv4_all_pim_routers(ip_hdr(skb)->daddr)) {
-+ 			if (ip_hdr(skb)->protocol == IPPROTO_PIM)
-+ 				br_multicast_pim(br, port, skb);
-++		} else if (ipv4_is_all_snoopers(ip_hdr(skb)->daddr)) {
-++			err = br_ip4_multicast_mrd_rcv(br, port, skb);
-++
-++			if (err < 0 && err != -ENOMSG) {
-++				br_multicast_err_count(br, port, skb->protocol);
-++				return err;
-++			}
-+ 		}
-++
-+ 		return 0;
-+ 	} else if (err < 0) {
-+ 		br_multicast_err_count(br, port, skb->protocol);
-+@@ -1824,6 +1848,27 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
-+ }
-+ 
-+ #if IS_ENABLED(CONFIG_IPV6)
-++static int br_ip6_multicast_mrd_rcv(struct net_bridge *br,
-++				    struct net_bridge_port *port,
-++				    struct sk_buff *skb)
-++{
-++	int ret;
-++
-++	if (ipv6_hdr(skb)->nexthdr != IPPROTO_ICMPV6)
-++		return -ENOMSG;
-++
-++	ret = ipv6_mc_check_icmpv6(skb);
-++	if (ret < 0)
-++		return ret;
-++
-++	if (icmp6_hdr(skb)->icmp6_type != ICMPV6_MRDISC_ADV)
-++		return -ENOMSG;
-++
-++	br_multicast_mark_router(br, port);
-++
-++	return 0;
-++}
-++
-+ static int br_multicast_ipv6_rcv(struct net_bridge *br,
-+ 				 struct net_bridge_port *port,
-+ 				 struct sk_buff *skb,
-+@@ -1838,6 +1883,16 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
-+ 	if (err == -ENOMSG) {
-+ 		if (!ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr))
-+ 			BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
-++
-++		if (ipv6_addr_is_all_snoopers(&ipv6_hdr(skb)->daddr)) {
-++			err = br_ip6_multicast_mrd_rcv(br, port, skb);
-++
-++			if (err < 0 && err != -ENOMSG) {
-++				br_multicast_err_count(br, port, skb->protocol);
-++				return err;
-++			}
-++		}
-++
-+ 		return 0;
-+ 	} else if (err < 0) {
-+ 		br_multicast_err_count(br, port, skb->protocol);
-+diff --git a/net/ipv6/mcast_snoop.c b/net/ipv6/mcast_snoop.c
-+index a72ddfc40eb3..55e2ac179f28 100644
-+--- a/net/ipv6/mcast_snoop.c
-++++ b/net/ipv6/mcast_snoop.c
-+@@ -41,6 +41,8 @@ static int ipv6_mc_check_ip6hdr(struct sk_buff *skb)
-+ 	if (skb->len < len || len <= offset)
-+ 		return -EINVAL;
-+ 
-++	skb_set_transport_header(skb, offset);
-++
-+ 	return 0;
-+ }
-+ 
-+@@ -142,7 +144,7 @@ static inline __sum16 ipv6_mc_validate_checksum(struct sk_buff *skb)
-+ 	return skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo);
-+ }
-+ 
-+-static int ipv6_mc_check_icmpv6(struct sk_buff *skb)
-++int ipv6_mc_check_icmpv6(struct sk_buff *skb)
-+ {
-+ 	unsigned int len = skb_transport_offset(skb) + sizeof(struct icmp6hdr);
-+ 	unsigned int transport_len = ipv6_transport_len(skb);
-+@@ -161,6 +163,7 @@ static int ipv6_mc_check_icmpv6(struct sk_buff *skb)
-+ 
-+ 	return 0;
-+ }
-++EXPORT_SYMBOL(ipv6_mc_check_icmpv6);
-+ 
-+ /**
-+  * ipv6_mc_check_mld - checks whether this is a sane MLD packet
-+-- 
-+2.27.0
-+
-diff --git a/target/linux/generic/backport-4.14/115-bridge-remove-duplicated-include-from-br_multicast.c.patch b/target/linux/generic/backport-4.14/115-bridge-remove-duplicated-include-from-br_multicast.c.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..ce8b19454986f2c61a9cda24f61a9eef5eaacf56
---- /dev/null
-+++ b/target/linux/generic/backport-4.14/115-bridge-remove-duplicated-include-from-br_multicast.c.patch
-@@ -0,0 +1,28 @@
-+From 995dbd5e30c99deb8f0c91264ae8d75951b832f7 Mon Sep 17 00:00:00 2001
-+From: YueHaibing <yuehaibing@huawei.com>
-+Date: Fri, 25 Jan 2019 10:59:09 +0800
-+Subject: [PATCH] bridge: remove duplicated include from br_multicast.c
-+
-+Remove duplicated include.
-+
-+Signed-off-by: YueHaibing <yuehaibing@huawei.com>
-+Signed-off-by: David S. Miller <davem@davemloft.net>
-+---
-+ net/bridge/br_multicast.c | 1 -
-+ 1 file changed, 1 deletion(-)
-+
-+diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
-+index 8f0bd1133bbd..4c1b9c0a290b 100644
-+--- a/net/bridge/br_multicast.c
-++++ b/net/bridge/br_multicast.c
-+@@ -35,7 +35,6 @@
-+ #include <net/mld.h>
-+ #include <net/ip6_checksum.h>
-+ #include <net/addrconf.h>
-+-#include <net/ipv6.h>
-+ #endif
-+ 
-+ #include "br_private.h"
-+-- 
-+2.27.0
-+
-diff --git a/target/linux/generic/backport-4.14/116-net-Fix-ip_mc_-dec-inc-_group-allocation-context.patch b/target/linux/generic/backport-4.14/116-net-Fix-ip_mc_-dec-inc-_group-allocation-context.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..cb22c3fb97d232e8664569a5842d8c1bbd7c9596
---- /dev/null
-+++ b/target/linux/generic/backport-4.14/116-net-Fix-ip_mc_-dec-inc-_group-allocation-context.patch
-@@ -0,0 +1,221 @@
-+From cb12869990893ec947c2d97b0e64449174c72d4a Mon Sep 17 00:00:00 2001
-+From: Florian Fainelli <f.fainelli@gmail.com>
-+Date: Fri, 1 Feb 2019 20:20:52 -0800
-+Subject: [PATCH] net: Fix ip_mc_{dec,inc}_group allocation context
-+
-+After 4effd28c1245 ("bridge: join all-snoopers multicast address"), I
-+started seeing the following sleep in atomic warnings:
-+
-+[   26.763893] BUG: sleeping function called from invalid context at mm/slab.h:421
-+[   26.771425] in_atomic(): 1, irqs_disabled(): 0, pid: 1658, name: sh
-+[   26.777855] INFO: lockdep is turned off.
-+[   26.781916] CPU: 0 PID: 1658 Comm: sh Not tainted 5.0.0-rc4 #20
-+[   26.787943] Hardware name: BCM97278SV (DT)
-+[   26.792118] Call trace:
-+[   26.794645]  dump_backtrace+0x0/0x170
-+[   26.798391]  show_stack+0x24/0x30
-+[   26.801787]  dump_stack+0xa4/0xe4
-+[   26.805182]  ___might_sleep+0x208/0x218
-+[   26.809102]  __might_sleep+0x78/0x88
-+[   26.812762]  kmem_cache_alloc_trace+0x64/0x28c
-+[   26.817301]  igmp_group_dropped+0x150/0x230
-+[   26.821573]  ip_mc_dec_group+0x1b0/0x1f8
-+[   26.825585]  br_ip4_multicast_leave_snoopers.isra.11+0x174/0x190
-+[   26.831704]  br_multicast_toggle+0x78/0xcc
-+[   26.835887]  store_bridge_parm+0xc4/0xfc
-+[   26.839894]  multicast_snooping_store+0x3c/0x4c
-+[   26.844517]  dev_attr_store+0x44/0x5c
-+[   26.848262]  sysfs_kf_write+0x50/0x68
-+[   26.852006]  kernfs_fop_write+0x14c/0x1b4
-+[   26.856102]  __vfs_write+0x60/0x190
-+[   26.859668]  vfs_write+0xc8/0x168
-+[   26.863059]  ksys_write+0x70/0xc8
-+[   26.866449]  __arm64_sys_write+0x24/0x30
-+[   26.870458]  el0_svc_common+0xa0/0x11c
-+[   26.874291]  el0_svc_handler+0x38/0x70
-+[   26.878120]  el0_svc+0x8/0xc
-+
-+while toggling the bridge's multicast_snooping attribute dynamically.
-+
-+Pass a gfp_t down to igmpv3_add_delrec(), introduce
-+__igmp_group_dropped() and introduce __ip_mc_dec_group() to take a gfp_t
-+argument.
-+
-+Similarly introduce ____ip_mc_inc_group() and __ip_mc_inc_group() to
-+allow caller to specify gfp_t.
-+
-+IPv6 part of the patch appears fine.
-+
-+Fixes: 4effd28c1245 ("bridge: join all-snoopers multicast address")
-+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
-+Signed-off-by: David S. Miller <davem@davemloft.net>
-+---
-+ include/linux/igmp.h      |  8 +++++++-
-+ net/bridge/br_multicast.c |  4 ++--
-+ net/ipv4/igmp.c           | 33 +++++++++++++++++++++++----------
-+ 3 files changed, 32 insertions(+), 13 deletions(-)
-+
-+diff --git a/include/linux/igmp.h b/include/linux/igmp.h
-+index 858143489a2a..a9cccb4fcb29 100644
-+--- a/include/linux/igmp.h
-++++ b/include/linux/igmp.h
-+@@ -135,7 +135,13 @@ extern void ip_mc_up(struct in_device *);
-+ extern void ip_mc_down(struct in_device *);
-+ extern void ip_mc_unmap(struct in_device *);
-+ extern void ip_mc_remap(struct in_device *);
-+-extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
-++extern void __ip_mc_dec_group(struct in_device *in_dev, __be32 addr, gfp_t gfp);
-++static inline void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
-++{
-++	return __ip_mc_dec_group(in_dev, addr, GFP_KERNEL);
-++}
-++extern void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr,
-++			      gfp_t gfp);
-+ extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
-+ int ip_mc_check_igmp(struct sk_buff *skb);
-+ 
-+diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
-+index 4c1b9c0a290b..779af4efea27 100644
-+--- a/net/bridge/br_multicast.c
-++++ b/net/bridge/br_multicast.c
-+@@ -2031,7 +2031,7 @@ static void br_ip4_multicast_join_snoopers(struct net_bridge *br)
-+ 	if (!in_dev)
-+ 		return;
-+ 
-+-	ip_mc_inc_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
-++	__ip_mc_inc_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP), GFP_ATOMIC);
-+ 	in_dev_put(in_dev);
-+ }
-+ 
-+@@ -2062,7 +2062,7 @@ static void br_ip4_multicast_leave_snoopers(struct net_bridge *br)
-+ 	if (WARN_ON(!in_dev))
-+ 		return;
-+ 
-+-	ip_mc_dec_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP));
-++	__ip_mc_dec_group(in_dev, htonl(INADDR_ALLSNOOPERS_GROUP), GFP_ATOMIC);
-+ 	in_dev_put(in_dev);
-+ }
-+ 
-+diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
-+index 9033c8cb0e95..862f25f19441 100644
-+--- a/net/ipv4/igmp.c
-++++ b/net/ipv4/igmp.c
-+@@ -162,7 +162,8 @@ static int unsolicited_report_interval(struct in_device *in_dev)
-+ 	return interval_jiffies;
-+ }
-+ 
-+-static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im);
-++static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im,
-++			      gfp_t gfp);
-+ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im);
-+ static void igmpv3_clear_delrec(struct in_device *in_dev);
-+ static int sf_setstate(struct ip_mc_list *pmc);
-+@@ -1152,7 +1153,8 @@ static void ip_mc_filter_del(struct in_device *in_dev, __be32 addr)
-+ /*
-+  * deleted ip_mc_list manipulation
-+  */
-+-static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
-++static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im,
-++			      gfp_t gfp)
-+ {
-+ 	struct ip_mc_list *pmc;
-+ 	struct net *net = dev_net(in_dev->dev);
-+@@ -1163,7 +1165,7 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
-+ 	 * for deleted items allows change reports to use common code with
-+ 	 * non-deleted or query-response MCA's.
-+ 	 */
-+-	pmc = kzalloc(sizeof(*pmc), GFP_KERNEL);
-++	pmc = kzalloc(sizeof(*pmc), gfp);
-+ 	if (!pmc)
-+ 		return;
-+ 	spin_lock_init(&pmc->lock);
-+@@ -1264,7 +1266,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev)
-+ }
-+ #endif
-+ 
-+-static void igmp_group_dropped(struct ip_mc_list *im)
-++static void __igmp_group_dropped(struct ip_mc_list *im, gfp_t gfp)
-+ {
-+ 	struct in_device *in_dev = im->interface;
-+ #ifdef CONFIG_IP_MULTICAST
-+@@ -1295,13 +1297,18 @@ static void igmp_group_dropped(struct ip_mc_list *im)
-+ 			return;
-+ 		}
-+ 		/* IGMPv3 */
-+-		igmpv3_add_delrec(in_dev, im);
-++		igmpv3_add_delrec(in_dev, im, gfp);
-+ 
-+ 		igmp_ifc_event(in_dev);
-+ 	}
-+ #endif
-+ }
-+ 
-++static void igmp_group_dropped(struct ip_mc_list *im)
-++{
-++	__igmp_group_dropped(im, GFP_KERNEL);
-++}
-++
-+ static void igmp_group_added(struct ip_mc_list *im)
-+ {
-+ 	struct in_device *in_dev = im->interface;
-+@@ -1396,7 +1403,7 @@ static void ip_mc_hash_remove(struct in_device *in_dev,
-+  *	A socket has joined a multicast group on device dev.
-+  */
-+ 
-+-void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
-++void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr, gfp_t gfp)
-+ {
-+ 	struct ip_mc_list *im;
-+ #ifdef CONFIG_IP_MULTICAST
-+@@ -1413,7 +1420,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
-+ 		}
-+ 	}
-+ 
-+-	im = kzalloc(sizeof(*im), GFP_KERNEL);
-++	im = kzalloc(sizeof(*im), gfp);
-+ 	if (!im)
-+ 		goto out;
-+ 
-+@@ -1446,6 +1453,12 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
-+ out:
-+ 	return;
-+ }
-++EXPORT_SYMBOL(__ip_mc_inc_group);
-++
-++void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
-++{
-++	__ip_mc_inc_group(in_dev, addr, GFP_KERNEL);
-++}
-+ EXPORT_SYMBOL(ip_mc_inc_group);
-+ 
-+ static int ip_mc_check_iphdr(struct sk_buff *skb)
-+@@ -1628,7 +1641,7 @@ static void ip_mc_rejoin_groups(struct in_device *in_dev)
-+  *	A socket has left a multicast group on device dev
-+  */
-+ 
-+-void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
-++void __ip_mc_dec_group(struct in_device *in_dev, __be32 addr, gfp_t gfp)
-+ {
-+ 	struct ip_mc_list *i;
-+ 	struct ip_mc_list __rcu **ip;
-+@@ -1643,7 +1656,7 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
-+ 				ip_mc_hash_remove(in_dev, i);
-+ 				*ip = i->next_rcu;
-+ 				in_dev->mc_count--;
-+-				igmp_group_dropped(i);
-++				__igmp_group_dropped(i, gfp);
-+ 				ip_mc_clear_src(i);
-+ 
-+ 				if (!in_dev->dead)
-+@@ -1656,7 +1669,7 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
-+ 		}
-+ 	}
-+ }
-+-EXPORT_SYMBOL(ip_mc_dec_group);
-++EXPORT_SYMBOL(__ip_mc_dec_group);
-+ 
-+ /* Device changing type */
-+ 
-+-- 
-+2.27.0
-+
-diff --git a/target/linux/generic/backport-4.14/117-net-remove-unneeded-switch-fall-through.patch b/target/linux/generic/backport-4.14/117-net-remove-unneeded-switch-fall-through.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..0d390f1d2f1b4a3542257e14761a7e1a9d9072c3
---- /dev/null
-+++ b/target/linux/generic/backport-4.14/117-net-remove-unneeded-switch-fall-through.patch
-@@ -0,0 +1,42 @@
-+From 4b3920aedc1b730583dccaeb702ab67722b09b5c Mon Sep 17 00:00:00 2001
-+From: Li RongQing <lirongqing@baidu.com>
-+Date: Tue, 19 Feb 2019 10:15:56 +0800
-+Subject: [PATCH] net: remove unneeded switch fall-through
-+
-+This case block has been terminated by a return, so not need
-+a switch fall-through
-+
-+Signed-off-by: Li RongQing <lirongqing@baidu.com>
-+Signed-off-by: David S. Miller <davem@davemloft.net>
-+---
-+ net/ipv4/igmp.c        | 1 -
-+ net/ipv6/mcast_snoop.c | 1 -
-+ 2 files changed, 2 deletions(-)
-+
-+diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
-+index 862f25f19441..9fbf4f9117bb 100644
-+--- a/net/ipv4/igmp.c
-++++ b/net/ipv4/igmp.c
-+@@ -1535,7 +1535,6 @@ static int ip_mc_check_igmp_msg(struct sk_buff *skb)
-+ 	case IGMP_HOST_LEAVE_MESSAGE:
-+ 	case IGMP_HOST_MEMBERSHIP_REPORT:
-+ 	case IGMPV2_HOST_MEMBERSHIP_REPORT:
-+-		/* fall through */
-+ 		return 0;
-+ 	case IGMPV3_HOST_MEMBERSHIP_REPORT:
-+ 		return ip_mc_check_igmp_reportv3(skb);
-+diff --git a/net/ipv6/mcast_snoop.c b/net/ipv6/mcast_snoop.c
-+index 55e2ac179f28..dddd75d1be0e 100644
-+--- a/net/ipv6/mcast_snoop.c
-++++ b/net/ipv6/mcast_snoop.c
-+@@ -128,7 +128,6 @@ static int ipv6_mc_check_mld_msg(struct sk_buff *skb)
-+ 	switch (mld->mld_type) {
-+ 	case ICMPV6_MGM_REDUCTION:
-+ 	case ICMPV6_MGM_REPORT:
-+-		/* fall through */
-+ 		return 0;
-+ 	case ICMPV6_MLD2_REPORT:
-+ 		return ipv6_mc_check_mld_reportv2(skb);
-+-- 
-+2.27.0
-+
-diff --git a/target/linux/generic/backport-4.14/118-ipv6-Fix-return-value-of-ipv6_mc_may_pull-for-malfor.patch b/target/linux/generic/backport-4.14/118-ipv6-Fix-return-value-of-ipv6_mc_may_pull-for-malfor.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..c17e2b4bd7b499b92a224450be0dca311d62027a
---- /dev/null
-+++ b/target/linux/generic/backport-4.14/118-ipv6-Fix-return-value-of-ipv6_mc_may_pull-for-malfor.patch
-@@ -0,0 +1,47 @@
-+From fc8cb7c0bf06853ea1f6ee14409b7f91b0acbe85 Mon Sep 17 00:00:00 2001
-+From: Stefano Brivio <sbrivio@redhat.com>
-+Date: Tue, 13 Aug 2019 00:46:01 +0200
-+Subject: [PATCH] ipv6: Fix return value of ipv6_mc_may_pull() for
-+ malformed packets
-+
-+Commit ba5ea614622d ("bridge: simplify ip_mc_check_igmp() and
-+ipv6_mc_check_mld() calls") replaces direct calls to pskb_may_pull()
-+in br_ipv6_multicast_mld2_report() with calls to ipv6_mc_may_pull(),
-+that returns -EINVAL on buffers too short to be valid IPv6 packets,
-+while maintaining the previous handling of the return code.
-+
-+This leads to the direct opposite of the intended effect: if the
-+packet is malformed, -EINVAL evaluates as true, and we'll happily
-+proceed with the processing.
-+
-+Return 0 if the packet is too short, in the same way as this was
-+fixed for IPv4 by commit 083b78a9ed64 ("ip: fix ip_mc_may_pull()
-+return value").
-+
-+I don't have a reproducer for this, unlike the one referred to by
-+the IPv4 commit, but this is clearly broken.
-+
-+Fixes: ba5ea614622d ("bridge: simplify ip_mc_check_igmp() and ipv6_mc_check_mld() calls")
-+Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-+Acked-by: Guillaume Nault <gnault@redhat.com>
-+Signed-off-by: David S. Miller <davem@davemloft.net>
-+---
-+ include/net/addrconf.h | 2 +-
-+ 1 file changed, 1 insertion(+), 1 deletion(-)
-+
-+diff --git a/include/net/addrconf.h b/include/net/addrconf.h
-+index c93530f9e8e4..ea97f70d66b8 100644
-+--- a/include/net/addrconf.h
-++++ b/include/net/addrconf.h
-+@@ -194,7 +194,7 @@ static inline int ipv6_mc_may_pull(struct sk_buff *skb,
-+ 				   unsigned int len)
-+ {
-+ 	if (skb_transport_offset(skb) + ipv6_transport_len(skb) < len)
-+-		return -EINVAL;
-++		return 0;
-+ 
-+ 	return pskb_may_pull(skb, len);
-+ }
-+-- 
-+2.27.0
-+
-diff --git a/target/linux/generic/backport-4.14/119-timers-Add-a-function-to-start-reduce-a-timer.patch b/target/linux/generic/backport-4.14/119-timers-Add-a-function-to-start-reduce-a-timer.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..92bb9275df9d54778ce8f00b1cb6e999eae40606
---- /dev/null
-+++ b/target/linux/generic/backport-4.14/119-timers-Add-a-function-to-start-reduce-a-timer.patch
-@@ -0,0 +1,201 @@
-+From dbc2cc8bcbdb0765516a7d0201f3337e66f4f2fc Mon Sep 17 00:00:00 2001
-+From: David Howells <dhowells@redhat.com>
-+Date: Thu, 9 Nov 2017 12:35:07 +0000
-+Subject: [PATCH] timers: Add a function to start/reduce a timer
-+
-+Add a function, similar to mod_timer(), that will start a timer if it isn't
-+running and will modify it if it is running and has an expiry time longer
-+than the new time.  If the timer is running with an expiry time that's the
-+same or sooner, no change is made.
-+
-+The function looks like:
-+
-+	int timer_reduce(struct timer_list *timer, unsigned long expires);
-+
-+This can be used by code such as networking code to make it easier to share
-+a timer for multiple timeouts.  For instance, in upcoming AF_RXRPC code,
-+the rxrpc_call struct will maintain a number of timeouts:
-+
-+	unsigned long	ack_at;
-+	unsigned long	resend_at;
-+	unsigned long	ping_at;
-+	unsigned long	expect_rx_by;
-+	unsigned long	expect_req_by;
-+	unsigned long	expect_term_by;
-+
-+each of which is set independently of the others.  With timer reduction
-+available, when the code needs to set one of the timeouts, it only needs to
-+look at that timeout and then call timer_reduce() to modify the timer,
-+starting it or bringing it forward if necessary.  There is no need to refer
-+to the other timeouts to see which is earliest and no need to take any lock
-+other than, potentially, the timer lock inside timer_reduce().
-+
-+Note, that this does not protect against concurrent invocations of any of
-+the timer functions.
-+
-+As an example, the expect_rx_by timeout above, which terminates a call if
-+we don't get a packet from the server within a certain time window, would
-+be set something like this:
-+
-+	unsigned long now = jiffies;
-+	unsigned long expect_rx_by = now + packet_receive_timeout;
-+	WRITE_ONCE(call->expect_rx_by, expect_rx_by);
-+	timer_reduce(&call->timer, expect_rx_by);
-+
-+The timer service code (which might, say, be in a work function) would then
-+check all the timeouts to see which, if any, had triggered, deal with
-+those:
-+
-+	t = READ_ONCE(call->ack_at);
-+	if (time_after_eq(now, t)) {
-+		cmpxchg(&call->ack_at, t, now + MAX_JIFFY_OFFSET);
-+		set_bit(RXRPC_CALL_EV_ACK, &call->events);
-+	}
-+
-+and then restart the timer if necessary by finding the soonest timeout that
-+hasn't yet passed and then calling timer_reduce().
-+
-+The disadvantage of doing things this way rather than comparing the timers
-+each time and calling mod_timer() is that you *will* take timer events
-+unless you can finish what you're doing and delete the timer in time.
-+
-+The advantage of doing things this way is that you don't need to use a lock
-+to work out when the next timer should be set, other than the timer's own
-+lock - which you might not have to take.
-+
-+[ tglx: Fixed weird formatting and adopted it to pending changes ]
-+
-+Signed-off-by: David Howells <dhowells@redhat.com>
-+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-+Cc: keyrings@vger.kernel.org
-+Cc: linux-afs@lists.infradead.org
-+Link: https://lkml.kernel.org/r/151023090769.23050.1801643667223880753.stgit@warthog.procyon.org.uk
-+---
-+ include/linux/timer.h |  1 +
-+ kernel/time/timer.c   | 45 ++++++++++++++++++++++++++++++++++++-------
-+ 2 files changed, 39 insertions(+), 7 deletions(-)
-+
-+diff --git a/include/linux/timer.h b/include/linux/timer.h
-+index e0ea1fe87572..db65e00fb7b2 100644
-+--- a/include/linux/timer.h
-++++ b/include/linux/timer.h
-+@@ -202,6 +202,7 @@ extern void add_timer_on(struct timer_list *timer, int cpu);
-+ extern int del_timer(struct timer_list * timer);
-+ extern int mod_timer(struct timer_list *timer, unsigned long expires);
-+ extern int mod_timer_pending(struct timer_list *timer, unsigned long expires);
-++extern int timer_reduce(struct timer_list *timer, unsigned long expires);
-+ 
-+ /*
-+  * The jiffies value which is added to now, when there is no timer
-+diff --git a/kernel/time/timer.c b/kernel/time/timer.c
-+index 9f8e8892e5b0..07892e658cbd 100644
-+--- a/kernel/time/timer.c
-++++ b/kernel/time/timer.c
-+@@ -927,8 +927,11 @@ static struct timer_base *lock_timer_base(struct timer_list *timer,
-+ 	}
-+ }
-+ 
-++#define MOD_TIMER_PENDING_ONLY		0x01
-++#define MOD_TIMER_REDUCE		0x02
-++
-+ static inline int
-+-__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
-++__mod_timer(struct timer_list *timer, unsigned long expires, unsigned int options)
-+ {
-+ 	struct timer_base *base, *new_base;
-+ 	unsigned int idx = UINT_MAX;
-+@@ -948,7 +951,11 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
-+ 		 * larger granularity than you would get from adding a new
-+ 		 * timer with this expiry.
-+ 		 */
-+-		if (timer->expires == expires)
-++		long diff = timer->expires - expires;
-++
-++		if (!diff)
-++			return 1;
-++		if (options & MOD_TIMER_REDUCE && diff <= 0)
-+ 			return 1;
-+ 
-+ 		/*
-+@@ -960,6 +967,12 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
-+ 		base = lock_timer_base(timer, &flags);
-+ 		forward_timer_base(base);
-+ 
-++		if (timer_pending(timer) && (options & MOD_TIMER_REDUCE) &&
-++		    time_before_eq(timer->expires, expires)) {
-++			ret = 1;
-++			goto out_unlock;
-++		}
-++
-+ 		clk = base->clk;
-+ 		idx = calc_wheel_index(expires, clk);
-+ 
-+@@ -969,7 +982,10 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
-+ 		 * subsequent call will exit in the expires check above.
-+ 		 */
-+ 		if (idx == timer_get_idx(timer)) {
-+-			timer->expires = expires;
-++			if (!(options & MOD_TIMER_REDUCE))
-++				timer->expires = expires;
-++			else if (time_after(timer->expires, expires))
-++				timer->expires = expires;
-+ 			ret = 1;
-+ 			goto out_unlock;
-+ 		}
-+@@ -979,7 +995,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
-+ 	}
-+ 
-+ 	ret = detach_if_pending(timer, base, false);
-+-	if (!ret && pending_only)
-++	if (!ret && (options & MOD_TIMER_PENDING_ONLY))
-+ 		goto out_unlock;
-+ 
-+ 	new_base = get_target_base(base, timer->flags);
-+@@ -1040,7 +1056,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
-+  */
-+ int mod_timer_pending(struct timer_list *timer, unsigned long expires)
-+ {
-+-	return __mod_timer(timer, expires, true);
-++	return __mod_timer(timer, expires, MOD_TIMER_PENDING_ONLY);
-+ }
-+ EXPORT_SYMBOL(mod_timer_pending);
-+ 
-+@@ -1066,10 +1082,25 @@ EXPORT_SYMBOL(mod_timer_pending);
-+  */
-+ int mod_timer(struct timer_list *timer, unsigned long expires)
-+ {
-+-	return __mod_timer(timer, expires, false);
-++	return __mod_timer(timer, expires, 0);
-+ }
-+ EXPORT_SYMBOL(mod_timer);
-+ 
-++/**
-++ * timer_reduce - Modify a timer's timeout if it would reduce the timeout
-++ * @timer:	The timer to be modified
-++ * @expires:	New timeout in jiffies
-++ *
-++ * timer_reduce() is very similar to mod_timer(), except that it will only
-++ * modify a running timer if that would reduce the expiration time (it will
-++ * start a timer that isn't running).
-++ */
-++int timer_reduce(struct timer_list *timer, unsigned long expires)
-++{
-++	return __mod_timer(timer, expires, MOD_TIMER_REDUCE);
-++}
-++EXPORT_SYMBOL(timer_reduce);
-++
-+ /**
-+  * add_timer - start a timer
-+  * @timer: the timer to be added
-+@@ -1742,7 +1773,7 @@ signed long __sched schedule_timeout(signed long timeout)
-+ 	expire = timeout + jiffies;
-+ 
-+ 	setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
-+-	__mod_timer(&timer, expire, false);
-++	__mod_timer(&timer, expire, 0);
-+ 	schedule();
-+ 	del_singleshot_timer_sync(&timer);
-+ 
-+-- 
-+2.27.0
-+
-diff --git a/target/linux/generic/config-4.14 b/target/linux/generic/config-4.14
-index d54ede9efda0a3ffd84e9a0c49dc410a01737d82..15b50523bf55d9a77fc1655ec6ba6ffde6d93a3e 100644
---- a/target/linux/generic/config-4.14
-+++ b/target/linux/generic/config-4.14
-@@ -628,6 +628,7 @@ CONFIG_BRIDGE=y
- # CONFIG_BRIDGE_EBT_T_NAT is not set
- # CONFIG_BRIDGE_EBT_VLAN is not set
- CONFIG_BRIDGE_IGMP_SNOOPING=y
-+CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS=y
- # CONFIG_BRIDGE_NETFILTER is not set
- # CONFIG_BRIDGE_NF_EBTABLES is not set
- CONFIG_BRIDGE_VLAN_FILTERING=y
-diff --git a/target/linux/generic/pending-4.14/151-bridge-Implement-MLD-Querier-wake-up-calls-Android-b.patch b/target/linux/generic/pending-4.14/151-bridge-Implement-MLD-Querier-wake-up-calls-Android-b.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..d02a4bc64deafa7fe2e17e9d17b259cea999c13b
---- /dev/null
-+++ b/target/linux/generic/pending-4.14/151-bridge-Implement-MLD-Querier-wake-up-calls-Android-b.patch
-@@ -0,0 +1,632 @@
-+From 95479b1485191f0e7b95f9b37df0b39c751a5b56 Mon Sep 17 00:00:00 2001
-+From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@c0d3.blue>
-+Date: Mon, 29 Jun 2020 19:04:05 +0200
-+Subject: [PATCH] bridge: Implement MLD Querier wake-up calls / Android bug
-+ workaround
-+MIME-Version: 1.0
-+Content-Type: text/plain; charset=UTF-8
-+Content-Transfer-Encoding: 8bit
-+
-+Implement a configurable MLD Querier wake-up calls "feature" which
-+works around a widely spread Android bug in connection with IGMP/MLD
-+snooping.
-+
-+Currently there are mobile devices (e.g. Android) which are not able
-+to receive and respond to MLD Queries reliably because the Wifi driver
-+filters a lot of ICMPv6 when the device is asleep - including
-+MLD. This in turn breaks IPv6 communication when MLD Snooping is
-+enabled. However there is one ICMPv6 type which is allowed to pass and
-+which can be used to wake up the mobile device: ICMPv6 Echo Requests.
-+
-+If this bridge is the selected MLD Querier then setting
-+"multicast_wakeupcall" to a number n greater than 0 will send n
-+ICMPv6 Echo Requests to each host behind this port to wake
-+them up with each MLD Query. Upon receiving a matching ICMPv6 Echo
-+Reply an MLD Query with a unicast ethernet destination will be sent
-+to the specific host(s).
-+
-+Link: https://issuetracker.google.com/issues/149630944
-+Link: https://github.com/freifunk-gluon/gluon/issues/1832
-+
-+Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
-+---
-+ include/linux/if_bridge.h    |   1 +
-+ include/uapi/linux/if_link.h |   1 +
-+ net/bridge/Kconfig           |  26 ++++
-+ net/bridge/br_fdb.c          |  10 ++
-+ net/bridge/br_input.c        |   4 +-
-+ net/bridge/br_multicast.c    | 288 ++++++++++++++++++++++++++++++++++-
-+ net/bridge/br_netlink.c      |  19 +++
-+ net/bridge/br_private.h      |  19 +++
-+ net/bridge/br_sysfs_if.c     |  18 +++
-+ 9 files changed, 378 insertions(+), 8 deletions(-)
-+
-+diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
-+index 78d2ed50c524..44fa4235c8e8 100644
-+--- a/include/linux/if_bridge.h
-++++ b/include/linux/if_bridge.h
-+@@ -50,6 +50,7 @@ struct br_ip_list {
-+ #define BR_VLAN_TUNNEL		BIT(13)
-+ #define BR_BCAST_FLOOD		BIT(14)
-+ #define BR_ISOLATED		BIT(16)
-++#define BR_MULTICAST_WAKEUPCALL	BIT(17)
-+ 
-+ #define BR_DEFAULT_AGEING_TIME	(300 * HZ)
-+ 
-+diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
-+index 45529dba6554..d019754d6870 100644
-+--- a/include/uapi/linux/if_link.h
-++++ b/include/uapi/linux/if_link.h
-+@@ -328,6 +328,7 @@ enum {
-+ 	IFLA_BRPORT_BCAST_FLOOD,
-+ 	IFLA_BRPORT_NEIGH_SUPPRESS,
-+ 	IFLA_BRPORT_ISOLATED,
-++	IFLA_BRPORT_MCAST_WAKEUPCALL,
-+ 	__IFLA_BRPORT_MAX
-+ };
-+ #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
-+diff --git a/net/bridge/Kconfig b/net/bridge/Kconfig
-+index aa0d3b2f1bb7..66495bc07dfc 100644
-+--- a/net/bridge/Kconfig
-++++ b/net/bridge/Kconfig
-+@@ -47,6 +47,32 @@ config BRIDGE_IGMP_SNOOPING
-+ 
-+ 	  If unsure, say Y.
-+ 
-++config BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
-++	bool "MLD Querier wake-up calls"
-++	depends on BRIDGE_IGMP_SNOOPING
-++	depends on IPV6
-++	help
-++	  If you say Y here, then the MLD Snooping Querier will be built
-++	  with a per bridge port wake-up call "feature"/workaround.
-++
-++	  Currently there are mobile devices (e.g. Android) which are not able
-++	  to receive and respond to MLD Queries reliably because the Wifi driver
-++	  filters a lot of ICMPv6 when the device is asleep - including MLD.
-++	  This in turn breaks IPv6 communication when MLD Snooping is enabled.
-++	  However there is one ICMPv6 type which is allowed to pass and
-++	  which can be used to wake up the mobile device: ICMPv6 Echo Requests.
-++
-++	  If this bridge is the selected MLD Querier then setting
-++	  "multicast_wakeupcall" to a number n greater than 0 will send n
-++	  ICMPv6 Echo Requests to each host behind this port to wake them up
-++	  with each MLD Query. Upon receiving a matching ICMPv6 Echo Reply
-++	  an MLD Query with a unicast ethernet destination will be sent to the
-++	  specific host(s).
-++
-++	  Say N to exclude this support and reduce the binary size.
-++
-++	  If unsure, say N.
-++
-+ config BRIDGE_VLAN_FILTERING
-+ 	bool "VLAN filtering"
-+ 	depends on BRIDGE
-+diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
-+index 4ea5c8bbe286..180555d2f21b 100644
-+--- a/net/bridge/br_fdb.c
-++++ b/net/bridge/br_fdb.c
-+@@ -81,6 +81,10 @@ static void fdb_rcu_free(struct rcu_head *head)
-+ {
-+ 	struct net_bridge_fdb_entry *ent
-+ 		= container_of(head, struct net_bridge_fdb_entry, rcu);
-++
-++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
-++	del_timer_sync(&ent->wakeupcall_timer);
-++#endif
-+ 	kmem_cache_free(br_fdb_cache, ent);
-+ }
-+ 
-+@@ -498,6 +502,12 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
-+ 		fdb->added_by_external_learn = 0;
-+ 		fdb->offloaded = 0;
-+ 		fdb->updated = fdb->used = jiffies;
-++
-++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
-++		timer_setup(&fdb->wakeupcall_timer,
-++			    br_multicast_send_wakeupcall, 0);
-++#endif
-++
-+ 		hlist_add_head_rcu(&fdb->hlist, head);
-+ 	}
-+ 	return fdb;
-+diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
-+index 66175565efa6..cc8f04408981 100644
-+--- a/net/bridge/br_input.c
-++++ b/net/bridge/br_input.c
-+@@ -200,8 +200,10 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
-+ 	if (dst) {
-+ 		unsigned long now = jiffies;
-+ 
-+-		if (dst->is_local)
-++		if (dst->is_local) {
-++			br_multicast_wakeupcall_rcv(br, p, skb, vid);
-+ 			return br_pass_frame_up(skb);
-++		}
-+ 
-+ 		if (now != dst->used)
-+ 			dst->used = now;
-+diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
-+index 779af4efea27..6d8d1cf2ddc6 100644
-+--- a/net/bridge/br_multicast.c
-++++ b/net/bridge/br_multicast.c
-+@@ -463,10 +463,11 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br,
-+ #if IS_ENABLED(CONFIG_IPV6)
-+ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
-+ 						    const struct in6_addr *grp,
-+-						    u8 *igmp_type)
-++						    u8 *igmp_type,
-++						    bool delay)
-+ {
-++	unsigned long interval = 0;
-+ 	struct mld2_query *mld2q;
-+-	unsigned long interval;
-+ 	struct ipv6hdr *ip6h;
-+ 	struct mld_msg *mldq;
-+ 	size_t mld_hdr_size;
-+@@ -525,9 +526,13 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
-+ 
-+ 	/* ICMPv6 */
-+ 	skb_set_transport_header(skb, skb->len);
-+-	interval = ipv6_addr_any(grp) ?
-+-			br->multicast_query_response_interval :
-+-			br->multicast_last_member_interval;
-++	if (delay) {
-++		interval = ipv6_addr_any(grp) ?
-++				br->multicast_query_response_interval :
-++				br->multicast_last_member_interval;
-++		interval = jiffies_to_msecs(interval);
-++	}
-++
-+ 	*igmp_type = ICMPV6_MGM_QUERY;
-+ 	switch (br->multicast_mld_version) {
-+ 	case 1:
-+@@ -535,7 +540,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
-+ 		mldq->mld_type = ICMPV6_MGM_QUERY;
-+ 		mldq->mld_code = 0;
-+ 		mldq->mld_cksum = 0;
-+-		mldq->mld_maxdelay = htons((u16)jiffies_to_msecs(interval));
-++		mldq->mld_maxdelay = htons((u16)interval);
-+ 		mldq->mld_reserved = 0;
-+ 		mldq->mld_mca = *grp;
-+ 		mldq->mld_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
-+@@ -584,7 +589,7 @@ static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
-+ #if IS_ENABLED(CONFIG_IPV6)
-+ 	case htons(ETH_P_IPV6):
-+ 		return br_ip6_multicast_alloc_query(br, &addr->u.ip6,
-+-						    igmp_type);
-++						    igmp_type, true);
-+ #endif
-+ 	}
-+ 	return NULL;
-+@@ -906,6 +911,172 @@ static void br_multicast_select_own_querier(struct net_bridge *br,
-+ #endif
-+ }
-+ 
-++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
-++
-++#define BR_MC_WAKEUP_ID htons(0xEC6B) /* random identifier */
-++#define BR_MC_ETH_ZERO { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
-++#define BR_MC_IN6_ZERO \
-++{ \
-++	.s6_addr32[0] = 0, .s6_addr32[1] = 0, \
-++	.s6_addr32[2] = 0, .s6_addr32[3] = 0, \
-++}
-++
-++#define BR_MC_IN6_FE80 \
-++{ \
-++	.s6_addr32[0] = htonl(0xfe800000), \
-++	.s6_addr32[1] = 0, \
-++	.s6_addr32[2] = htonl(0x000000ff), \
-++	.s6_addr32[3] = htonl(0xfe000000), \
-++}
-++
-++#define BR_MC_ECHO_LEN sizeof(pkt->echohdr)
-++
-++static struct sk_buff *br_multicast_alloc_wakeupcall(struct net_bridge *br,
-++						     struct net_bridge_port *port,
-++						     u8 *eth_dst)
-++{
-++	struct in6_addr ip6_src, ip6_dst = BR_MC_IN6_FE80;
-++	struct sk_buff *skb;
-++	__wsum csum_part;
-++	__sum16 csum;
-++
-++	struct wakeupcall_pkt {
-++		struct ethhdr ethhdr;
-++		struct ipv6hdr ip6hdr;
-++		struct icmp6hdr echohdr;
-++	} __packed;
-++
-++	struct wakeupcall_pkt *pkt;
-++
-++	static const struct wakeupcall_pkt __pkt_template = {
-++		.ethhdr = {
-++			.h_dest = BR_MC_ETH_ZERO, // update
-++			.h_source = BR_MC_ETH_ZERO, // update
-++			.h_proto = htons(ETH_P_IPV6),
-++		},
-++		.ip6hdr = {
-++			.priority = 0,
-++			.version = 0x6,
-++			.flow_lbl = { 0x00, 0x00, 0x00 },
-++			.payload_len = htons(BR_MC_ECHO_LEN),
-++			.nexthdr = IPPROTO_ICMPV6,
-++			.hop_limit = 1,
-++			.saddr = BR_MC_IN6_ZERO, // update
-++			.daddr = BR_MC_IN6_ZERO, // update
-++		},
-++		.echohdr = {
-++			.icmp6_type = ICMPV6_ECHO_REQUEST,
-++			.icmp6_code = 0,
-++			.icmp6_cksum = 0, // update
-++			.icmp6_dataun.u_echo = {
-++				.identifier = BR_MC_WAKEUP_ID,
-++				.sequence = 0,
-++			},
-++		},
-++	};
-++
-++	memcpy(&ip6_dst.s6_addr32[2], &eth_dst[0], ETH_ALEN / 2);
-++	memcpy(&ip6_dst.s6_addr[13], &eth_dst[3], ETH_ALEN / 2);
-++	ip6_dst.s6_addr[8] ^= 0x02;
-++	if (ipv6_dev_get_saddr(dev_net(br->dev), br->dev, &ip6_dst, 0,
-++			       &ip6_src))
-++		return NULL;
-++
-++	skb = netdev_alloc_skb_ip_align(br->dev, sizeof(*pkt));
-++	if (!skb)
-++		return NULL;
-++
-++	skb->protocol = htons(ETH_P_IPV6);
-++	skb->dev = port->dev;
-++
-++	pkt = (struct wakeupcall_pkt *)skb->data;
-++	*pkt = __pkt_template;
-++
-++	ether_addr_copy(pkt->ethhdr.h_source, br->dev->dev_addr);
-++	ether_addr_copy(pkt->ethhdr.h_dest, eth_dst);
-++
-++	pkt->ip6hdr.saddr = ip6_src;
-++	pkt->ip6hdr.daddr = ip6_dst;
-++
-++	csum_part = csum_partial(&pkt->echohdr, sizeof(pkt->echohdr), 0);
-++	csum = csum_ipv6_magic(&ip6_src, &ip6_dst, sizeof(pkt->echohdr),
-++			       IPPROTO_ICMPV6, csum_part);
-++	pkt->echohdr.icmp6_cksum = csum;
-++
-++	skb_reset_mac_header(skb);
-++	skb_set_network_header(skb, offsetof(struct wakeupcall_pkt, ip6hdr));
-++	skb_set_transport_header(skb, offsetof(struct wakeupcall_pkt, echohdr));
-++	skb_put(skb, sizeof(*pkt));
-++	__skb_pull(skb, sizeof(pkt->ethhdr));
-++
-++	return skb;
-++}
-++
-++void br_multicast_send_wakeupcall(struct timer_list *t)
-++{
-++	struct net_bridge_fdb_entry *fdb = from_timer(fdb, t, wakeupcall_timer);
-++	struct net_bridge_port *port = fdb->dst;
-++	struct net_bridge *br = port->br;
-++	struct sk_buff *skb, *skb0;
-++	int i;
-++
-++	skb0 = br_multicast_alloc_wakeupcall(br, port, fdb->addr.addr);
-++	if (!skb0)
-++		return;
-++
-++	for (i = port->wakeupcall_num_rings; i > 0; i--) {
-++		if (i > 1) {
-++			skb = skb_clone(skb0, GFP_ATOMIC);
-++			if (!skb) {
-++				kfree_skb(skb0);
-++				break;
-++			}
-++		} else {
-++			skb = skb0;
-++		}
-++
-++		NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT,
-++			dev_net(port->dev), NULL, skb, NULL, skb->dev,
-++			br_dev_queue_push_xmit);
-++	}
-++}
-++
-++static void br_multicast_schedule_wakeupcalls(struct net_bridge *br,
-++					      struct net_bridge_port *port,
-++					      const struct in6_addr *group)
-++{
-++	struct net_bridge_fdb_entry *fdb;
-++	unsigned long delay;
-++	int i;
-++
-++	rcu_read_lock();
-++	for (i = 0; i < BR_HASH_SIZE; i++) {
-++		hlist_for_each_entry_rcu(fdb, &br->hash[i], hlist) {
-++			if (!fdb->dst || fdb->dst->dev != port->dev)
-++				continue;
-++
-++			/* Wake-up calls to VLANs unsupported for now */
-++			if (fdb->vlan_id)
-++				continue;
-++
-++			/* Spread the ICMPv6 Echo Requests to avoid congestion.
-++			 * We then won't use a max response delay for the
-++			 * queries later, as that would be redundant. Spread
-++			 * randomly by a little less than max response delay to
-++			 * anticipate the extra round trip.
-++			 */
-++			delay =	ipv6_addr_any(group) ?
-++					br->multicast_query_response_interval :
-++					br->multicast_last_member_interval;
-++			delay = prandom_u32() % (3 * delay / 4);
-++
-++			timer_reduce(&fdb->wakeupcall_timer, jiffies + delay);
-++		}
-++	}
-++	rcu_read_unlock();
-++}
-++#endif /* CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS */
-++
-+ static void __br_multicast_send_query(struct net_bridge *br,
-+ 				      struct net_bridge_port *port,
-+ 				      struct br_ip *ip)
-+@@ -924,6 +1095,13 @@ static void __br_multicast_send_query(struct net_bridge *br,
-+ 		NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT,
-+ 			dev_net(port->dev), NULL, skb, NULL, skb->dev,
-+ 			br_dev_queue_push_xmit);
-++
-++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
-++		if (port->wakeupcall_num_rings &&
-++		    ip->proto == htons(ETH_P_IPV6))
-++			br_multicast_schedule_wakeupcalls(br, port,
-++							  &ip->u.ip6);
-++#endif
-+ 	} else {
-+ 		br_multicast_select_own_querier(br, ip, skb);
-+ 		br_multicast_count(br, port, skb, igmp_type,
-+@@ -1952,6 +2130,93 @@ int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,
-+ 	return ret;
-+ }
-+ 
-++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
-++
-++static bool br_multicast_wakeupcall_check(struct net_bridge *br,
-++					  struct net_bridge_port *port,
-++					  struct sk_buff *skb, u16 vid)
-++{
-++	struct ethhdr *eth = eth_hdr(skb);
-++	const struct ipv6hdr *ip6h;
-++	unsigned int offset, len;
-++	struct icmp6hdr *icmp6h;
-++
-++	/* Wake-up calls to VLANs unsupported for now */
-++	if (!port->wakeupcall_num_rings || vid ||
-++	    eth->h_proto != htons(ETH_P_IPV6))
-++		return false;
-++
-++	if (!ether_addr_equal(eth->h_dest, br->dev->dev_addr) ||
-++	    is_multicast_ether_addr(eth->h_source) ||
-++	    is_zero_ether_addr(eth->h_source))
-++		return false;
-++
-++	offset = skb_network_offset(skb) + sizeof(*ip6h);
-++	if (!pskb_may_pull(skb, offset))
-++		return false;
-++
-++	ip6h = ipv6_hdr(skb);
-++
-++	if (ip6h->version != 6)
-++		return false;
-++
-++	len = offset + ntohs(ip6h->payload_len);
-++	if (skb->len < len || len <= offset)
-++		return false;
-++
-++	if (ip6h->nexthdr != IPPROTO_ICMPV6)
-++		return false;
-++
-++	skb_set_transport_header(skb, offset);
-++
-++	if (ipv6_mc_check_icmpv6(skb) < 0)
-++		return false;
-++
-++	icmp6h = (struct icmp6hdr *)skb_transport_header(skb);
-++	if (icmp6h->icmp6_type != ICMPV6_ECHO_REPLY ||
-++	    icmp6h->icmp6_dataun.u_echo.identifier != BR_MC_WAKEUP_ID)
-++		return false;
-++
-++	return true;
-++}
-++
-++static void br_multicast_wakeupcall_send_mldq(struct net_bridge *br,
-++					      struct net_bridge_port *port,
-++					      const u8 *eth_dst)
-++{
-++	const struct in6_addr grp = BR_MC_IN6_ZERO;
-++	struct sk_buff *skb;
-++	u8 igmp_type;
-++
-++	/* we might have been triggered by multicast-address-specific query
-++	 * but reply with a general MLD query for now to keep things simple
-++	 */
-++	skb = br_ip6_multicast_alloc_query(br, &grp, &igmp_type, false);
-++	if (!skb)
-++		return;
-++
-++	skb->dev = port->dev;
-++	ether_addr_copy(eth_hdr(skb)->h_dest, eth_dst);
-++
-++	br_multicast_count(br, port, skb, igmp_type,
-++			   BR_MCAST_DIR_TX);
-++	NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT,
-++		dev_net(port->dev), NULL, skb, NULL, skb->dev,
-++		br_dev_queue_push_xmit);
-++}
-++
-++void br_multicast_wakeupcall_rcv(struct net_bridge *br,
-++				 struct net_bridge_port *port,
-++				 struct sk_buff *skb, u16 vid)
-++{
-++	if (!br_multicast_wakeupcall_check(br, port, skb, vid))
-++		return;
-++
-++	br_multicast_wakeupcall_send_mldq(br, port, eth_hdr(skb)->h_source);
-++}
-++
-++#endif /* CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS */
-++
-+ static void br_multicast_query_expired(struct net_bridge *br,
-+ 				       struct bridge_mcast_own_query *query,
-+ 				       struct bridge_mcast_querier *querier)
-+@@ -2239,6 +2504,15 @@ int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val)
-+ 	return err;
-+ }
-+ 
-++int br_multicast_set_wakeupcall(struct net_bridge_port *p, unsigned long val)
-++{
-++	if (val > U8_MAX)
-++		return -EINVAL;
-++
-++	p->wakeupcall_num_rings = val;
-++	return 0;
-++}
-++
-+ static void br_multicast_start_querier(struct net_bridge *br,
-+ 				       struct bridge_mcast_own_query *query)
-+ {
-+diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
-+index 2bf371d9c6d9..85f44a15a97a 100644
-+--- a/net/bridge/br_netlink.c
-++++ b/net/bridge/br_netlink.c
-+@@ -152,6 +152,9 @@ static inline size_t br_port_info_size(void)
-+ 		+ nla_total_size_64bit(sizeof(u64)) /* IFLA_BRPORT_HOLD_TIMER */
-+ #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
-+ 		+ nla_total_size(sizeof(u8))	/* IFLA_BRPORT_MULTICAST_ROUTER */
-++#endif
-++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
-++		+ nla_total_size(sizeof(u8))	/* IFLA_BRPORT_MCAST_WAKEUPCALL */
-+ #endif
-+ 		+ 0;
-+ }
-+@@ -231,6 +234,11 @@ static int br_port_fill_attrs(struct sk_buff *skb,
-+ 		       p->multicast_router))
-+ 		return -EMSGSIZE;
-+ #endif
-++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
-++	if (nla_put_u8(skb, IFLA_BRPORT_MCAST_WAKEUPCALL,
-++		       p->wakeupcall_num_rings))
-++		return -EMSGSIZE;
-++#endif
-+ 
-+ 	return 0;
-+ }
-+@@ -637,6 +645,7 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = {
-+ 	[IFLA_BRPORT_PROXYARP_WIFI] = { .type = NLA_U8 },
-+ 	[IFLA_BRPORT_MULTICAST_ROUTER] = { .type = NLA_U8 },
-+ 	[IFLA_BRPORT_MCAST_TO_UCAST] = { .type = NLA_U8 },
-++	[IFLA_BRPORT_MCAST_WAKEUPCALL] = { .type = NLA_U8 },
-+ 	[IFLA_BRPORT_MCAST_FLOOD] = { .type = NLA_U8 },
-+ 	[IFLA_BRPORT_BCAST_FLOOD] = { .type = NLA_U8 },
-+ 	[IFLA_BRPORT_ISOLATED]	= { .type = NLA_U8 },
-+@@ -781,6 +790,16 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
-+ 	if (err)
-+ 		return err;
-+ 
-++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
-++	if (tb[IFLA_BRPORT_MCAST_WAKEUPCALL]) {
-++		u8 wakeupcall = nla_get_u8(tb[IFLA_BRPORT_MCAST_WAKEUPCALL]);
-++
-++		err = br_multicast_set_wakeupcall(p, wakeupcall);
-++		if (err)
-++			return err;
-++	}
-++#endif
-++
-+ 	br_port_flags_change(p, old_flags ^ p->flags);
-+ 	return 0;
-+ }
-+diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
-+index 32f0d61c1803..bbf7513c1d16 100644
-+--- a/net/bridge/br_private.h
-++++ b/net/bridge/br_private.h
-+@@ -178,6 +178,10 @@ struct net_bridge_fdb_entry {
-+ 	unsigned long			used;
-+ 
-+ 	struct rcu_head			rcu;
-++
-++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
-++	struct timer_list		wakeupcall_timer;
-++#endif
-+ };
-+ 
-+ #define MDB_PG_FLAGS_PERMANENT	BIT(0)
-+@@ -256,6 +260,7 @@ struct net_bridge_port {
-+ 	struct timer_list		multicast_router_timer;
-+ 	struct hlist_head		mglist;
-+ 	struct hlist_node		rlist;
-++	u8				wakeupcall_num_rings;
-+ #endif
-+ 
-+ #ifdef CONFIG_SYSFS
-+@@ -790,6 +795,20 @@ static inline int br_multicast_igmp_type(const struct sk_buff *skb)
-+ }
-+ #endif
-+ 
-++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
-++void br_multicast_wakeupcall_rcv(struct net_bridge *br,
-++				 struct net_bridge_port *port,
-++				 struct sk_buff *skb, u16 vid);
-++void br_multicast_send_wakeupcall(struct timer_list *t);
-++int br_multicast_set_wakeupcall(struct net_bridge_port *p, unsigned long val);
-++#else
-++static inline void br_multicast_wakeupcall_rcv(struct net_bridge *br,
-++					       struct net_bridge_port *port,
-++					       struct sk_buff *skb, u16 vid)
-++{
-++}
-++#endif /* CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS */
-++
-+ /* br_vlan.c */
-+ #ifdef CONFIG_BRIDGE_VLAN_FILTERING
-+ bool br_allowed_ingress(const struct net_bridge *br,
-+diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
-+index b51aefa636b6..e9f1f5ccec3e 100644
-+--- a/net/bridge/br_sysfs_if.c
-++++ b/net/bridge/br_sysfs_if.c
-+@@ -194,6 +194,21 @@ BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE);
-+ BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UNICAST);
-+ #endif
-+ 
-++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
-++static ssize_t show_multicast_wakeupcall(struct net_bridge_port *p, char *buf)
-++{
-++	return sprintf(buf, "%d\n", p->wakeupcall_num_rings);
-++}
-++
-++static int store_multicast_wakeupcall(struct net_bridge_port *p,
-++				      unsigned long v)
-++{
-++	return br_multicast_set_wakeupcall(p, v);
-++}
-++static BRPORT_ATTR(multicast_wakeupcall, 0644, show_multicast_wakeupcall,
-++		   store_multicast_wakeupcall);
-++#endif
-++
-+ static const struct brport_attribute *brport_attrs[] = {
-+ 	&brport_attr_path_cost,
-+ 	&brport_attr_priority,
-+@@ -219,6 +234,9 @@ static const struct brport_attribute *brport_attrs[] = {
-+ 	&brport_attr_multicast_router,
-+ 	&brport_attr_multicast_fast_leave,
-+ 	&brport_attr_multicast_to_unicast,
-++#endif
-++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
-++	&brport_attr_multicast_wakeupcall,
-+ #endif
-+ 	&brport_attr_proxyarp,
-+ 	&brport_attr_proxyarp_wifi,
-+-- 
-+2.28.0.rc1
-+
diff --git a/patches/openwrt/0016-ath79-Fix-fallback-to-bootloader-cmdline-on-empty-DT-bootargs.patch b/patches/openwrt/0016-ath79-Fix-fallback-to-bootloader-cmdline-on-empty-DT-bootargs.patch
deleted file mode 100644
index 5a3951c0a9e43f9ddf06b975f943191e7aa725c1..0000000000000000000000000000000000000000
--- a/patches/openwrt/0016-ath79-Fix-fallback-to-bootloader-cmdline-on-empty-DT-bootargs.patch
+++ /dev/null
@@ -1,431 +0,0 @@
-From: Sven Eckelmann <sven@narfation.org>
-Date: Mon, 23 Nov 2020 16:57:31 +0100
-Subject: ath79: Fix fallback to bootloader cmdline on empty DT bootargs
-
-The MIPS code is supposed to fall back to u-boots bootargs whenever the
-/chosen/bootargs property is missing. But this feature was accidentally
-disabled when the boot_command_line was initialized with an empty space
-just to work around problems with early_init_dt_scan_chosen.
-
-But this feature is necessary for some boards which have a dualboot
-mechanism and whose u-boot is calculating the correct partition at runtime
-without writing this information back to the u-boot-env.
-
-Signed-off-by: Sven Eckelmann <sven@narfation.org>
-Origin: backport, https://github.com/openwrt/openwrt/commit/727eebbad1b9dea91174ea675cb64ea13484f790
-
-diff --git a/target/linux/ath79/patches-4.14/0038-MIPS-Setup-boot_command_line-before-plat_mem_setup.patch b/target/linux/ath79/patches-4.14/0038-MIPS-Setup-boot_command_line-before-plat_mem_setup.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..90d2ca7a0cb16d3f1e71779bfa551f498fd59755
---- /dev/null
-+++ b/target/linux/ath79/patches-4.14/0038-MIPS-Setup-boot_command_line-before-plat_mem_setup.patch
-@@ -0,0 +1,82 @@
-+From: Paul Burton <paul.burton@mips.com>
-+Date: Tue, 16 Jan 2018 16:47:57 +0100
-+Subject: MIPS: Setup boot_command_line before plat_mem_setup
-+
-+Platforms using DT will typically call __dt_setup_arch from
-+plat_mem_setup. This in turn calls early_init_dt_scan. When
-+CONFIG_CMDLINE is set, this leads to its value being copied into
-+boot_command_line by early_init_dt_scan_chosen. If this happens before
-+the code setting up boot_command_line in arch_mem_init runs, that code
-+will go on to append CONFIG_CMDLINE (via builtin_cmdline) to
-+boot_command_line again, duplicating it. For some command line
-+parameters (eg. earlycon) this can be a problem. Set up
-+boot_command_line before early_init_dt_scan_chosen gets called such that
-+it will not write CONFIG_CMDLINE in this scenario & the arguments aren't
-+duplicated.
-+
-+Origin: upstream, https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8ce355cf2e38afdb364d03d12b23d9cf44c3b7f1
-+Signed-off-by: Paul Burton <paul.burton@mips.com>
-+Acked-by: Mathieu Malaterre <malat@debian.org>
-+Cc: Ralf Baechle <ralf@linux-mips.org>
-+Cc: Maarten ter Huurne <maarten@treewalker.org>
-+Cc: linux-mips@linux-mips.org
-+Patchwork: https://patchwork.linux-mips.org/patch/18483/
-+Signed-off-by: James Hogan <jhogan@kernel.org>
-+
-+diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
-+index abd7ee9e90ab0dd0d01d970c84d90a2c4edf609b..c0f51fd4e0b3970e4f019094091578504e2f56eb 100644
-+--- a/arch/mips/kernel/setup.c
-++++ b/arch/mips/kernel/setup.c
-+@@ -833,25 +833,6 @@ static void __init arch_mem_init(char **cmdline_p)
-+ 	struct memblock_region *reg;
-+ 	extern void plat_mem_setup(void);
-+ 
-+-	/* call board setup routine */
-+-	plat_mem_setup();
-+-
-+-	/*
-+-	 * Make sure all kernel memory is in the maps.  The "UP" and
-+-	 * "DOWN" are opposite for initdata since if it crosses over
-+-	 * into another memory section you don't want that to be
-+-	 * freed when the initdata is freed.
-+-	 */
-+-	arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
-+-			 PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
-+-			 BOOT_MEM_RAM);
-+-	arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
-+-			 PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
-+-			 BOOT_MEM_INIT_RAM);
-+-
-+-	pr_info("Determined physical RAM map:\n");
-+-	print_memory_map();
-+-
-+ #if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
-+ 	strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-+ #else
-+@@ -879,6 +860,26 @@ static void __init arch_mem_init(char **cmdline_p)
-+ 	}
-+ #endif
-+ #endif
-++
-++	/* call board setup routine */
-++	plat_mem_setup();
-++
-++	/*
-++	 * Make sure all kernel memory is in the maps.  The "UP" and
-++	 * "DOWN" are opposite for initdata since if it crosses over
-++	 * into another memory section you don't want that to be
-++	 * freed when the initdata is freed.
-++	 */
-++	arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
-++			 PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
-++			 BOOT_MEM_RAM);
-++	arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
-++			 PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
-++			 BOOT_MEM_INIT_RAM);
-++
-++	pr_info("Determined physical RAM map:\n");
-++	print_memory_map();
-++
-+ 	strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
-+ 
-+ 	*cmdline_p = command_line;
-diff --git a/target/linux/ath79/patches-4.14/0039-MIPS-Fix-CONFIG_CMDLINE-handling.patch b/target/linux/ath79/patches-4.14/0039-MIPS-Fix-CONFIG_CMDLINE-handling.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..ab040c459454b1670b08afa2082e06637280da52
---- /dev/null
-+++ b/target/linux/ath79/patches-4.14/0039-MIPS-Fix-CONFIG_CMDLINE-handling.patch
-@@ -0,0 +1,119 @@
-+From: Paul Burton <paul.burton@mips.com>
-+Date: Thu, 27 Sep 2018 22:59:18 +0000
-+Subject: MIPS: Fix CONFIG_CMDLINE handling
-+
-+Commit 8ce355cf2e38 ("MIPS: Setup boot_command_line before
-+plat_mem_setup") fixed a problem for systems which have
-+CONFIG_CMDLINE_BOOL=y & use a DT with a chosen node that has either no
-+bootargs property or an empty one. In this configuration
-+early_init_dt_scan_chosen() copies CONFIG_CMDLINE into
-+boot_command_line, but the MIPS code doesn't know this so it appends
-+CONFIG_CMDLINE (via builtin_cmdline) to boot_command_line again. The
-+result is that boot_command_line contains the arguments from
-+CONFIG_CMDLINE twice.
-+
-+That commit took the approach of simply setting up boot_command_line
-+from the MIPS code before early_init_dt_scan_chosen() runs, causing it
-+not to copy CONFIG_CMDLINE to boot_command_line if a chosen node with no
-+bootargs property is found.
-+
-+Unfortunately this is problematic for systems which do have a non-empty
-+bootargs property & CONFIG_CMDLINE_BOOL=y. There
-+early_init_dt_scan_chosen() will overwrite boot_command_line with the
-+arguments from DT, which means we lose those from CONFIG_CMDLINE
-+entirely. This breaks CONFIG_MIPS_CMDLINE_DTB_EXTEND. If we have
-+CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER or
-+CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND selected and the DT has a bootargs
-+property which we should ignore, it will instead be honoured breaking
-+those configurations too.
-+
-+Fix this by reverting commit 8ce355cf2e38 ("MIPS: Setup
-+boot_command_line before plat_mem_setup") to restore the former
-+behaviour, and fixing the CONFIG_CMDLINE duplication issue by
-+initializing boot_command_line to a non-empty string that
-+early_init_dt_scan_chosen() will not overwrite with CONFIG_CMDLINE.
-+
-+This is a little ugly, but cleanup in this area is on its way. In the
-+meantime this is at least easy to backport & contains the ugliness
-+within arch/mips/.
-+
-+Origin: upstream, https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=951d223c6c16ed5d2a71a4d1f13c1e65d6882156
-+Signed-off-by: Paul Burton <paul.burton@mips.com>
-+Fixes: 8ce355cf2e38 ("MIPS: Setup boot_command_line before plat_mem_setup")
-+References: https://patchwork.linux-mips.org/patch/18804/
-+Patchwork: https://patchwork.linux-mips.org/patch/20813/
-+Cc: Frank Rowand <frowand.list@gmail.com>
-+Cc: Jaedon Shin <jaedon.shin@gmail.com>
-+Cc: Mathieu Malaterre <malat@debian.org>
-+Cc: Rob Herring <robh+dt@kernel.org>
-+Cc: devicetree@vger.kernel.org
-+Cc: linux-kernel@vger.kernel.org
-+Cc: linux-mips@linux-mips.org
-+Cc: stable@vger.kernel.org # v4.16+
-+
-+diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
-+index c0f51fd4e0b3970e4f019094091578504e2f56eb..71070ec8da136495d2efed0aa79dff44149d565f 100644
-+--- a/arch/mips/kernel/setup.c
-++++ b/arch/mips/kernel/setup.c
-+@@ -833,6 +833,34 @@ static void __init arch_mem_init(char **cmdline_p)
-+ 	struct memblock_region *reg;
-+ 	extern void plat_mem_setup(void);
-+ 
-++	/*
-++	 * Initialize boot_command_line to an innocuous but non-empty string in
-++	 * order to prevent early_init_dt_scan_chosen() from copying
-++	 * CONFIG_CMDLINE into it without our knowledge. We handle
-++	 * CONFIG_CMDLINE ourselves below & don't want to duplicate its
-++	 * content because repeating arguments can be problematic.
-++	 */
-++	strlcpy(boot_command_line, " ", COMMAND_LINE_SIZE);
-++
-++	/* call board setup routine */
-++	plat_mem_setup();
-++
-++	/*
-++	 * Make sure all kernel memory is in the maps.  The "UP" and
-++	 * "DOWN" are opposite for initdata since if it crosses over
-++	 * into another memory section you don't want that to be
-++	 * freed when the initdata is freed.
-++	 */
-++	arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
-++			 PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
-++			 BOOT_MEM_RAM);
-++	arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
-++			 PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
-++			 BOOT_MEM_INIT_RAM);
-++
-++	pr_info("Determined physical RAM map:\n");
-++	print_memory_map();
-++
-+ #if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
-+ 	strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-+ #else
-+@@ -860,26 +888,6 @@ static void __init arch_mem_init(char **cmdline_p)
-+ 	}
-+ #endif
-+ #endif
-+-
-+-	/* call board setup routine */
-+-	plat_mem_setup();
-+-
-+-	/*
-+-	 * Make sure all kernel memory is in the maps.  The "UP" and
-+-	 * "DOWN" are opposite for initdata since if it crosses over
-+-	 * into another memory section you don't want that to be
-+-	 * freed when the initdata is freed.
-+-	 */
-+-	arch_mem_addpart(PFN_DOWN(__pa_symbol(&_text)) << PAGE_SHIFT,
-+-			 PFN_UP(__pa_symbol(&_edata)) << PAGE_SHIFT,
-+-			 BOOT_MEM_RAM);
-+-	arch_mem_addpart(PFN_UP(__pa_symbol(&__init_begin)) << PAGE_SHIFT,
-+-			 PFN_DOWN(__pa_symbol(&__init_end)) << PAGE_SHIFT,
-+-			 BOOT_MEM_INIT_RAM);
-+-
-+-	pr_info("Determined physical RAM map:\n");
-+-	print_memory_map();
-+-
-+ 	strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
-+ 
-+ 	*cmdline_p = command_line;
-diff --git a/target/linux/ath79/patches-4.14/0040-MIPS-cmdline-Clean-up-boot_command_line-initializati.patch b/target/linux/ath79/patches-4.14/0040-MIPS-cmdline-Clean-up-boot_command_line-initializati.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..2cba97d5e85bb863ca95c0715110b69e4964ea51
---- /dev/null
-+++ b/target/linux/ath79/patches-4.14/0040-MIPS-cmdline-Clean-up-boot_command_line-initializati.patch
-@@ -0,0 +1,196 @@
-+From: Paul Burton <paul.burton@mips.com>
-+Date: Wed, 9 Oct 2019 23:09:45 +0000
-+Subject: MIPS: cmdline: Clean up boot_command_line initialization
-+
-+Our current code to initialize boot_command_line is a mess. Some of this
-+is due to the addition of too many options over the years, and some of
-+this is due to workarounds for early_init_dt_scan_chosen() performing
-+actions specific to options from other architectures that probably
-+shouldn't be in generic code.
-+
-+Clean this up by introducing a new bootcmdline_init() function that
-+simplifies the initialization somewhat. The major changes are:
-+
-+- Because bootcmdline_init() is a function it can return early in the
-+  CONFIG_CMDLINE_OVERRIDE case.
-+
-+- We clear boot_command_line rather than inheriting whatever
-+  early_init_dt_scan_chosen() may have left us. This means we no longer
-+  need to set boot_command_line to a space character in an attempt to
-+  prevent early_init_dt_scan_chosen() from copying CONFIG_CMDLINE into
-+  boot_command_line without us knowing about it.
-+
-+- Indirection via USE_PROM_CMDLINE, USE_DTB_CMDLINE, EXTEND_WITH_PROM &
-+  BUILTIN_EXTEND_WITH_PROM macros is removed; they seemingly served only
-+  to obfuscate the code.
-+
-+- The logic is cleaner, clearer & commented.
-+
-+Two minor drawbacks of this approach are:
-+
-+1) We call of_scan_flat_dt(), which means we scan through the DT again.
-+   The overhead is fairly minimal & shouldn't be noticeable.
-+
-+2) cmdline_scan_chosen() duplicates a small amount of the logic from
-+   early_init_dt_scan_chosen(). Alternatives might be to allow the
-+   generic FDT code to keep & expose a copy of the arguments taken from
-+   the /chosen node's bootargs property, or to introduce a function like
-+   early_init_dt_scan_chosen() that retrieves them without modification
-+   to handle CONFIG_CMDLINE. Neither of these sounds particularly
-+   cleaner though, and this way we at least keep the extra work in
-+   arch/mips.
-+
-+Origin: backport, https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7784cac697351f0cc0a4bb619594c0c99348c5aa
-+Signed-off-by: Paul Burton <paul.burton@mips.com>
-+Cc: linux-mips@vger.kernel.org
-+
-+diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
-+index 71070ec8da136495d2efed0aa79dff44149d565f..c2b659a2e2ce0f2074f4fc13cd24283d66ac5594 100644
-+--- a/arch/mips/kernel/setup.c
-++++ b/arch/mips/kernel/setup.c
-+@@ -822,26 +822,94 @@ static void __init request_crashkernel(struct resource *res)
-+ }
-+ #endif /* !defined(CONFIG_KEXEC)  */
-+ 
-+-#define USE_PROM_CMDLINE	IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER)
-+-#define USE_DTB_CMDLINE		IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB)
-+-#define EXTEND_WITH_PROM	IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND)
-+-#define BUILTIN_EXTEND_WITH_PROM	\
-+-	IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND)
-++static void __init bootcmdline_append(const char *s, size_t max)
-++{
-++	if (!s[0] || !max)
-++		return;
-++
-++	if (boot_command_line[0])
-++		strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
-++
-++	strlcat(boot_command_line, s, max);
-++}
-++
-++static int __init bootcmdline_scan_chosen(unsigned long node, const char *uname,
-++					  int depth, void *data)
-++{
-++	bool *dt_bootargs = data;
-++	const char *p;
-++	int l;
-++
-++	if (depth != 1 || !data ||
-++	    (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
-++		return 0;
-++
-++	p = of_get_flat_dt_prop(node, "bootargs", &l);
-++	if (p != NULL && l > 0) {
-++		bootcmdline_append(p, min(l, COMMAND_LINE_SIZE));
-++		*dt_bootargs = true;
-++	}
-++
-++	return 1;
-++}
-++
-++static void __init bootcmdline_init(char **cmdline_p)
-++{
-++	bool dt_bootargs = false;
-++
-++	/*
-++	 * If CMDLINE_OVERRIDE is enabled then initializing the command line is
-++	 * trivial - we simply use the built-in command line unconditionally &
-++	 * unmodified.
-++	 */
-++	if (IS_ENABLED(CONFIG_CMDLINE_OVERRIDE)) {
-++		strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-++		return;
-++	}
-++
-++	/*
-++	 * If the user specified a built-in command line &
-++	 * MIPS_CMDLINE_BUILTIN_EXTEND, then the built-in command line is
-++	 * prepended to arguments from the bootloader or DT so we'll copy them
-++	 * to the start of boot_command_line here. Otherwise, empty
-++	 * boot_command_line to undo anything early_init_dt_scan_chosen() did.
-++	 */
-++	if (IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND))
-++		strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-++	else
-++		boot_command_line[0] = 0;
-++
-++	/*
-++	 * If we're configured to take boot arguments from DT, look for those
-++	 * now.
-++	 */
-++	if (IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB))
-++		of_scan_flat_dt(bootcmdline_scan_chosen, &dt_bootargs);
-++
-++	/*
-++	 * If we didn't get any arguments from DT (regardless of whether that's
-++	 * because we weren't configured to look for them, or because we looked
-++	 * & found none) then we'll take arguments from the bootloader.
-++	 * plat_mem_setup() should have filled arcs_cmdline with arguments from
-++	 * the bootloader.
-++	 */
-++	if (IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND) || !dt_bootargs)
-++		bootcmdline_append(arcs_cmdline, COMMAND_LINE_SIZE);
-++
-++	/*
-++	 * If the user specified a built-in command line & we didn't already
-++	 * prepend it, we append it to boot_command_line here.
-++	 */
-++	if (IS_ENABLED(CONFIG_CMDLINE_BOOL) &&
-++	    !IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND))
-++		bootcmdline_append(builtin_cmdline, COMMAND_LINE_SIZE);
-++}
-+ 
-+ static void __init arch_mem_init(char **cmdline_p)
-+ {
-+ 	struct memblock_region *reg;
-+ 	extern void plat_mem_setup(void);
-+ 
-+-	/*
-+-	 * Initialize boot_command_line to an innocuous but non-empty string in
-+-	 * order to prevent early_init_dt_scan_chosen() from copying
-+-	 * CONFIG_CMDLINE into it without our knowledge. We handle
-+-	 * CONFIG_CMDLINE ourselves below & don't want to duplicate its
-+-	 * content because repeating arguments can be problematic.
-+-	 */
-+-	strlcpy(boot_command_line, " ", COMMAND_LINE_SIZE);
-+-
-+ 	/* call board setup routine */
-+ 	plat_mem_setup();
-+ 
-+@@ -861,35 +929,8 @@ static void __init arch_mem_init(char **cmdline_p)
-+ 	pr_info("Determined physical RAM map:\n");
-+ 	print_memory_map();
-+ 
-+-#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
-+-	strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-+-#else
-+-	if ((USE_PROM_CMDLINE && arcs_cmdline[0]) ||
-+-	    (USE_DTB_CMDLINE && !boot_command_line[0]))
-+-		strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
-+-
-+-	if (EXTEND_WITH_PROM && arcs_cmdline[0]) {
-+-		if (boot_command_line[0])
-+-			strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
-+-		strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
-+-	}
-+-
-+-#if defined(CONFIG_CMDLINE_BOOL)
-+-	if (builtin_cmdline[0]) {
-+-		if (boot_command_line[0])
-+-			strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
-+-		strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-+-	}
-+-
-+-	if (BUILTIN_EXTEND_WITH_PROM && arcs_cmdline[0]) {
-+-		if (boot_command_line[0])
-+-			strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
-+-		strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
-+-	}
-+-#endif
-+-#endif
-++	bootcmdline_init(cmdline_p);
-+ 	strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
-+-
-+ 	*cmdline_p = command_line;
-+ 
-+ 	parse_early_param();
diff --git a/patches/openwrt/0017-ath79-Add-support-for-Plasma-Cloud-PA300.patch b/patches/openwrt/0017-ath79-Add-support-for-Plasma-Cloud-PA300.patch
deleted file mode 100644
index fa3172531f0961c20dbb1a79d82810803f3f60f4..0000000000000000000000000000000000000000
--- a/patches/openwrt/0017-ath79-Add-support-for-Plasma-Cloud-PA300.patch
+++ /dev/null
@@ -1,408 +0,0 @@
-From: Sven Eckelmann <sven@narfation.org>
-Date: Mon, 23 Nov 2020 13:41:34 +0100
-Subject: ath79: Add support for Plasma Cloud PA300
-
-Device specifications:
-
-* Qualcomm/Atheros QCA9533 v2
-* 650/600/217 MHz (CPU/DDR/AHB)
-* 64 MB of RAM
-* 16 MB of SPI NOR flash (mx25l12805d)
-  - 2x 7 MB available; but one of the 7 MB regions is the recovery image
-* 2x 10/100 Mbps Ethernet
-* 2T2R 2.4 GHz Wi-Fi
-* multi-color LED (controlled via red/green/blue GPIOs)
-* 1x GPIO-button (reset)
-* external h/w watchdog (enabled by default)
-* TTL pins are on board (arrow points to VCC, then follows: GND, TX, RX)
-* 2x fast ethernet
-  - eth0
-    + Label: Ethernet 1
-    + 24V passive POE (mode B)
-    + used as WAN interface
-  - eth1
-    + Label: Ethernet 2
-    + 802.3af POE
-    + builtin switch port 2
-    + used as LAN interface
-* 12-24V 1A DC
-* internal antennas
-
-Flashing instructions:
-
-The tool ap51-flash (https://github.com/ap51-flash/ap51-flash) should be
-used to transfer the factory image to the u-boot when the device boots up.
-
-Signed-off-by: Sven Eckelmann <sven@narfation.org>
-Origin: backport, https://github.com/openwrt/openwrt/commit/8028debedbedb2640cf5fac230bce82453e34a7e
-
-diff --git a/package/boot/uboot-envtools/files/ath79 b/package/boot/uboot-envtools/files/ath79
-index b5afbc9b444a921f6aef9ae81e5dc4f2ef7f9910..8808e81682f70583c4b2a888f8ddca9448277919 100644
---- a/package/boot/uboot-envtools/files/ath79
-+++ b/package/boot/uboot-envtools/files/ath79
-@@ -39,6 +39,9 @@ netgear,wndr3700|\
- netgear,wndr3700-v2)
- 	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x10000"
- 	;;
-+plasmacloud,pa300)
-+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x40000" "0x40000"
-+	;;
- esac
- 
- config_load ubootenv
-diff --git a/scripts/om-fwupgradecfg-gen.sh b/scripts/om-fwupgradecfg-gen.sh
-index 4a7094055ff67aab83e796fc30f9913ae2c30fe2..e271fa0dacad837191eaab7683ad8880d183a75e 100755
---- a/scripts/om-fwupgradecfg-gen.sh
-+++ b/scripts/om-fwupgradecfg-gen.sh
-@@ -7,7 +7,7 @@
- #
- 
- usage() {
--	echo "Usage: $0 <OM2P|OM5P|OM5PAC|MR600|MR900|MR1750|A60|A42|A62> <out file path> <kernel path> <rootfs path>"
-+	echo "Usage: $0 <OM2P|OM5P|OM5PAC|MR600|MR900|MR1750|A60|A42|A62|PA300> <out file path> <kernel path> <rootfs path>"
- 	rm -f $CFG_OUT
- 	exit 1
- }
-@@ -20,6 +20,7 @@ KERNEL_PATH=$3
- ROOTFS_PATH=$4
- 
- case $CE_TYPE in
-+	PA300|\
- 	OM2P)
- 		MAX_PART_SIZE=7168
- 		KERNEL_FLASH_ADDR=0x1c0000
-diff --git a/target/linux/ath79/base-files/etc/board.d/02_network b/target/linux/ath79/base-files/etc/board.d/02_network
-index b8fac8816c9a2b2a87a5d1335b41127666afe2e4..846e2807ede8ec828a2f519f9b33c0d1dfdd5129 100755
---- a/target/linux/ath79/base-files/etc/board.d/02_network
-+++ b/target/linux/ath79/base-files/etc/board.d/02_network
-@@ -115,6 +115,7 @@ ath79_setup_interfaces()
- 		;;
- 	comfast,cf-e110n-v2|\
- 	comfast,cf-e120a-v3|\
-+	plasmacloud,pa300|\
- 	tplink,cpe220-v3|\
- 	ubnt,nanostation-m|\
- 	ubnt,routerstation)
-diff --git a/target/linux/ath79/base-files/lib/upgrade/dualboot_datachk.sh b/target/linux/ath79/base-files/lib/upgrade/dualboot_datachk.sh
-new file mode 100644
-index 0000000000000000000000000000000000000000..68733ccf154582e29b6416ad8daa7eb7a81bcc7e
---- /dev/null
-+++ b/target/linux/ath79/base-files/lib/upgrade/dualboot_datachk.sh
-@@ -0,0 +1,104 @@
-+# The U-Boot loader with the datachk patchset for dualbooting requires image
-+# sizes and checksums to be provided in the U-Boot environment.
-+# The devices come with 2 main partitions - while one is active
-+# sysupgrade will flash the other. The boot order is changed to boot the
-+# newly flashed partition. If the new partition can't be booted due to
-+# upgrade failures the previously used partition is loaded.
-+
-+platform_do_upgrade_dualboot_datachk() {
-+	local tar_file="$1"
-+	local restore_backup
-+	local primary_kernel_mtd
-+
-+	local setenv_script="/tmp/fw_env_upgrade"
-+
-+	local inactive_mtd="$(find_mtd_index $PART_NAME)"
-+	local inactive_offset="$(cat /sys/class/mtd/mtd${inactive_mtd}/offset)"
-+	local total_size="$(cat /sys/class/mtd/mtd${inactive_mtd}/size)"
-+	local flash_start_mem=0x9f000000
-+
-+	# detect to which flash region the new image is written to.
-+	#
-+	# 1. check what is the mtd index for the first flash region on this
-+	#    device
-+	# 2. check if the target partition ("inactive") has the mtd index of
-+	#    the first flash region
-+	#
-+	#    - when it is: the new bootseq will be 1,2 and the first region is
-+	#      modified
-+	#    - when it isnt: bootseq will be 2,1 and the second region is
-+	#      modified
-+	#
-+	# The detection has to be done via the hardcoded mtd partition because
-+	# the current boot might be done with the fallback region. Let us
-+	# assume that the current bootseq is 1,2. The bootloader detected that
-+	# the image in flash region 1 is corrupt and thus switches to flash
-+	# region 2. The bootseq in the u-boot-env is now still the same and
-+	# the sysupgrade code can now only rely on the actual mtd indexes and
-+	# not the bootseq variable to detect the currently booted flash
-+	# region/image.
-+	#
-+	# In the above example, an implementation which uses bootseq ("1,2") to
-+	# detect the currently booted image would assume that region 1 is booted
-+	# and then overwrite the variables for the wrong flash region (aka the
-+	# one which isn't modified). This could result in a device which doesn't
-+	# boot anymore to Linux until it was reflashed with ap51-flash.
-+	local next_boot_part="1"
-+	case "$(board_name)" in
-+	plasmacloud,pa300)
-+		primary_kernel_mtd=3
-+		;;
-+	*)
-+		echo "failed to detect primary kernel mtd partition for board"
-+		return 1
-+		;;
-+	esac
-+	[ "$inactive_mtd" = "$primary_kernel_mtd" ] || next_boot_part="2"
-+
-+	local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$')
-+	board_dir=${board_dir%/}
-+
-+	local kernel_length=$(tar xf $tar_file ${board_dir}/kernel -O | wc -c)
-+	local rootfs_length=$(tar xf $tar_file ${board_dir}/root -O | wc -c)
-+	# rootfs without EOF marker
-+	rootfs_length=$((rootfs_length-4))
-+
-+	local kernel_md5=$(tar xf $tar_file ${board_dir}/kernel -O | md5sum); kernel_md5="${kernel_md5%% *}"
-+	# md5 checksum of rootfs with EOF marker
-+	local rootfs_md5=$(tar xf $tar_file ${board_dir}/root -O | dd bs=1 count=$rootfs_length | md5sum); rootfs_md5="${rootfs_md5%% *}"
-+
-+	#
-+	# add tar support to get_image() to use default_do_upgrade() instead?
-+	#
-+
-+	# take care of restoring a saved config
-+	[ -n "$UPGRADE_BACKUP" ] && restore_backup="${MTD_CONFIG_ARGS} -j ${UPGRADE_BACKUP}"
-+
-+	mtd -q erase inactive
-+	tar xf $tar_file ${board_dir}/root -O | mtd -n -p $kernel_length $restore_backup write - $PART_NAME
-+	tar xf $tar_file ${board_dir}/kernel -O | mtd -n write - $PART_NAME
-+
-+	# prepare new u-boot env
-+	if [ "$next_boot_part" = "1" ]; then
-+		echo "bootseq 1,2" > $setenv_script
-+	else
-+		echo "bootseq 2,1" > $setenv_script
-+	fi
-+
-+	printf "kernel_size_%i %i\n" $next_boot_part $((kernel_length / 1024)) >> $setenv_script
-+	printf "vmlinux_start_addr 0x%08x\n" $((flash_start_mem + inactive_offset)) >> $setenv_script
-+	printf "vmlinux_size 0x%08x\n" ${kernel_length} >> $setenv_script
-+	printf "vmlinux_checksum %s\n" ${kernel_md5} >> $setenv_script
-+
-+	printf "rootfs_size_%i %i\n" $next_boot_part $(((total_size-kernel_length) / 1024)) >> $setenv_script
-+	printf "rootfs_start_addr 0x%08x\n" $((flash_start_mem+inactive_offset+kernel_length)) >> $setenv_script
-+	printf "rootfs_size 0x%08x\n" ${rootfs_length} >> $setenv_script
-+	printf "rootfs_checksum %s\n" ${rootfs_md5} >> $setenv_script
-+
-+	# store u-boot env changes
-+	mkdir -p /var/lock
-+	fw_setenv -s $setenv_script || {
-+		echo "failed to update U-Boot environment"
-+		return 1
-+	}
-+}
-diff --git a/target/linux/ath79/base-files/lib/upgrade/platform.sh b/target/linux/ath79/base-files/lib/upgrade/platform.sh
-index f3e19a5694f1f9c6132a42d0740873e522d0b8e3..c4f869932a02ef353e694b50496c3b2ed5d59f12 100644
---- a/target/linux/ath79/base-files/lib/upgrade/platform.sh
-+++ b/target/linux/ath79/base-files/lib/upgrade/platform.sh
-@@ -5,6 +5,9 @@
- PART_NAME=firmware
- REQUIRE_IMAGE_METADATA=1
- 
-+RAMFS_COPY_BIN='fw_printenv fw_setenv'
-+RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock'
-+
- redboot_fis_do_upgrade() {
- 	local append
- 	local sysup_file="$1"
-@@ -43,6 +46,10 @@ platform_do_upgrade() {
- 	jjplus,ja76pf2)
- 		redboot_fis_do_upgrade "$1" linux
- 		;;
-+	plasmacloud,pa300)
-+		PART_NAME="inactive"
-+		platform_do_upgrade_dualboot_datachk "$1"
-+		;;
- 	ubnt,routerstation|\
- 	ubnt,routerstation-pro)
- 		redboot_fis_do_upgrade "$1" kernel
-diff --git a/target/linux/ath79/dts/qca9533_plasmacloud_pa300.dts b/target/linux/ath79/dts/qca9533_plasmacloud_pa300.dts
-new file mode 100644
-index 0000000000000000000000000000000000000000..8de89292eaa2e655066342ebfac05dbeb6a3c4f3
---- /dev/null
-+++ b/target/linux/ath79/dts/qca9533_plasmacloud_pa300.dts
-@@ -0,0 +1,8 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-+
-+#include "qca9533_plasmacloud_pa300.dtsi"
-+
-+/ {
-+	compatible = "plasmacloud,pa300", "qca,qca9533";
-+	model = "Plasma Cloud PA300";
-+};
-diff --git a/target/linux/ath79/dts/qca9533_plasmacloud_pa300.dtsi b/target/linux/ath79/dts/qca9533_plasmacloud_pa300.dtsi
-new file mode 100644
-index 0000000000000000000000000000000000000000..d8fc78dc1edeb2d8677336f25fcae2a85e05ee3f
---- /dev/null
-+++ b/target/linux/ath79/dts/qca9533_plasmacloud_pa300.dtsi
-@@ -0,0 +1,140 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-+/dts-v1/;
-+#include "qca953x.dtsi"
-+
-+#include <dt-bindings/gpio/gpio.h>
-+#include <dt-bindings/input/input.h>
-+
-+/ {
-+	chosen {
-+		/delete-property/ bootargs;
-+	};
-+
-+	aliases {
-+		led-boot = &led_status_green;
-+		led-failsafe = &led_status_green;
-+		led-running = &led_status_green;
-+		led-upgrade = &led_status_green;
-+		label-mac-device = &eth0;
-+	};
-+
-+	keys {
-+		compatible = "gpio-keys";
-+
-+		pinctrl-names = "default";
-+
-+		reset {
-+			label = "reset";
-+			linux,code = <KEY_RESTART>;
-+			gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
-+		};
-+	};
-+
-+	leds {
-+		compatible = "gpio-leds";
-+
-+		status_red {
-+			label = "red:status";
-+			gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
-+		};
-+
-+		led_status_green: status_green {
-+			label = "green:status";
-+			gpios = <&gpio 2 GPIO_ACTIVE_HIGH>;
-+		};
-+
-+		status_blue {
-+			label = "blue:status";
-+			gpios = <&gpio 3 GPIO_ACTIVE_HIGH>;
-+		};
-+	};
-+
-+	watchdog {
-+		compatible = "linux,wdt-gpio";
-+		gpios = <&gpio 12 GPIO_ACTIVE_LOW>;
-+		hw_algo = "toggle";
-+		/* hw_margin_ms is actually 300s but driver limits it to 60s */
-+		hw_margin_ms = <60000>;
-+		always-running;
-+	};
-+};
-+
-+&uart {
-+	status = "okay";
-+};
-+
-+&spi {
-+	status = "okay";
-+
-+	flash@0 {
-+		compatible = "jedec,spi-nor";
-+		reg = <0>;
-+		spi-max-frequency = <25000000>;
-+
-+		/* partitions are passed via bootloader */
-+		partitions {
-+			compatible = "fixed-partitions";
-+			#address-cells = <1>;
-+			#size-cells = <1>;
-+
-+			partition@0 {
-+				label = "u-boot";
-+				reg = <0x000000 0x040000>;
-+				read-only;
-+			};
-+
-+			partition@40000 {
-+				label = "u-boot-env";
-+				reg = <0x040000 0x040000>;
-+			};
-+
-+			partition@80000 {
-+				label = "custom";
-+				reg = <0x080000 0x140000>;
-+				read-only;
-+			};
-+
-+			partition@1c0000 {
-+				label = "inactive";
-+				reg = <0x1c0000 0x700000>;
-+			};
-+
-+			partition@8c0000 {
-+				label = "inactive2";
-+				reg = <0x8c0000 0x700000>;
-+			};
-+
-+			art: partition@fc0000 {
-+				label = "ART";
-+				reg = <0xfc0000 0x040000>;
-+				read-only;
-+			};
-+		};
-+	};
-+};
-+
-+&eth0 {
-+	status = "okay";
-+
-+	phy-handle = <&swphy4>;
-+
-+	mtd-mac-address = <&art 0x0>;
-+};
-+
-+&eth1 {
-+	/* Workaround: keep the Ethernet interfaces order/mapping correct
-+	 * (GMAC0 -> eth0, GMAC1 -> eth1, same as in old ar71xx target)
-+	 */
-+	compatible = "qca,qca9530-eth", "syscon", "simple-mfd";
-+
-+	mtd-mac-address = <&art 0x0>;
-+	mtd-mac-address-increment = <1>;
-+};
-+
-+&wmac {
-+	status = "okay";
-+
-+	mtd-cal-data = <&art 0x1000>;
-+	mtd-mac-address = <&art 0x0>;
-+	mtd-mac-address-increment = <2>;
-+};
-diff --git a/target/linux/ath79/image/generic.mk b/target/linux/ath79/image/generic.mk
-index 892ef10f870e347c8a1509cecd35bce4b5e98bee..3c1db9b3204d6784580f87ea9adb7a2ba98d285b 100644
---- a/target/linux/ath79/image/generic.mk
-+++ b/target/linux/ath79/image/generic.mk
-@@ -646,6 +646,23 @@ define Device/pisen_wmm003n
- endef
- TARGET_DEVICES += pisen_wmm003n
- 
-+define Device/plasmacloud_pa300-common
-+  ATH_SOC := qca9533
-+  DEVICE_PACKAGES := uboot-envtools
-+  IMAGE_SIZE := 7168k
-+  BLOCKSIZE := 64k
-+  IMAGES += factory.bin
-+  KERNEL := kernel-bin | append-dtb | lzma | uImage lzma | pad-to $$(BLOCKSIZE)
-+  IMAGE/factory.bin := append-rootfs | pad-rootfs | openmesh-image ce_type=PA300
-+  IMAGE/sysupgrade.bin := append-rootfs | pad-rootfs | sysupgrade-tar rootfs=$$$$@ | append-metadata
-+endef
-+
-+define Device/plasmacloud_pa300
-+  $(Device/plasmacloud_pa300-common)
-+  DEVICE_TITLE := Plasma Cloud PA300
-+endef
-+TARGET_DEVICES += plasmacloud_pa300
-+
- define Device/netgear_wndr3800
-   $(Device/netgear_wndr3x00)
-   DEVICE_TITLE := NETGEAR WNDR3800
diff --git a/patches/openwrt/0018-ath79-Add-support-for-Plasma-Cloud-PA300E.patch b/patches/openwrt/0018-ath79-Add-support-for-Plasma-Cloud-PA300E.patch
deleted file mode 100644
index d2a4f8d8754e5efab186369250f707cad6875f81..0000000000000000000000000000000000000000
--- a/patches/openwrt/0018-ath79-Add-support-for-Plasma-Cloud-PA300E.patch
+++ /dev/null
@@ -1,123 +0,0 @@
-From: Sven Eckelmann <sven@narfation.org>
-Date: Mon, 23 Nov 2020 13:41:34 +0100
-Subject: ath79: Add support for Plasma Cloud PA300E
-
-Device specifications:
-
-* Qualcomm/Atheros QCA9533 v2
-* 650/600/217 MHz (CPU/DDR/AHB)
-* 64 MB of RAM
-* 16 MB of SPI NOR flash (mx25l12805d)
-  - 2x 7 MB available; but one of the 7 MB regions is the recovery image
-* 2x 10/100 Mbps Ethernet
-* 2T2R 2.4 GHz Wi-Fi
-* multi-color LED (controlled via red/green/blue GPIOs)
-* 1x GPIO-button (reset)
-* external h/w watchdog (enabled by default)
-* TTL pins are on board (arrow points to VCC, then follows: GND, TX, RX)
-* 2x fast ethernet
-  - eth0
-    + Label: Ethernet 1
-    + 24V passive POE (mode B)
-    + used as WAN interface
-  - eth1
-    + Label: Ethernet 2
-    + 802.3af POE
-    + builtin switch port 2
-    + used as LAN interface
-* 12-24V 1A DC
-* external antennas
-
-Flashing instructions:
-
-The tool ap51-flash (https://github.com/ap51-flash/ap51-flash) should be
-used to transfer the factory image to the u-boot when the device boots up.
-
-Signed-off-by: Sven Eckelmann <sven@narfation.org>
-Origin: backport, https://github.com/openwrt/openwrt/commit/ba6a387b9700bc1d486f2a73fbd4b88cfb5758f1
-
-diff --git a/package/boot/uboot-envtools/files/ath79 b/package/boot/uboot-envtools/files/ath79
-index 8808e81682f70583c4b2a888f8ddca9448277919..a5df255009919d62d580faa9baf2ef4fe45d36ec 100644
---- a/package/boot/uboot-envtools/files/ath79
-+++ b/package/boot/uboot-envtools/files/ath79
-@@ -39,7 +39,8 @@ netgear,wndr3700|\
- netgear,wndr3700-v2)
- 	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x10000"
- 	;;
--plasmacloud,pa300)
-+plasmacloud,pa300|\
-+plasmacloud,pa300e)
- 	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x40000" "0x40000"
- 	;;
- esac
-diff --git a/target/linux/ath79/base-files/etc/board.d/02_network b/target/linux/ath79/base-files/etc/board.d/02_network
-index 846e2807ede8ec828a2f519f9b33c0d1dfdd5129..57429fbc1c851b6d8a8a03096d7043f78a489549 100755
---- a/target/linux/ath79/base-files/etc/board.d/02_network
-+++ b/target/linux/ath79/base-files/etc/board.d/02_network
-@@ -116,6 +116,7 @@ ath79_setup_interfaces()
- 	comfast,cf-e110n-v2|\
- 	comfast,cf-e120a-v3|\
- 	plasmacloud,pa300|\
-+	plasmacloud,pa300e|\
- 	tplink,cpe220-v3|\
- 	ubnt,nanostation-m|\
- 	ubnt,routerstation)
-diff --git a/target/linux/ath79/base-files/lib/upgrade/dualboot_datachk.sh b/target/linux/ath79/base-files/lib/upgrade/dualboot_datachk.sh
-index 68733ccf154582e29b6416ad8daa7eb7a81bcc7e..002f5f9668978292615b19c3ba14b17afac709e2 100644
---- a/target/linux/ath79/base-files/lib/upgrade/dualboot_datachk.sh
-+++ b/target/linux/ath79/base-files/lib/upgrade/dualboot_datachk.sh
-@@ -45,7 +45,8 @@ platform_do_upgrade_dualboot_datachk() {
- 	# boot anymore to Linux until it was reflashed with ap51-flash.
- 	local next_boot_part="1"
- 	case "$(board_name)" in
--	plasmacloud,pa300)
-+	plasmacloud,pa300|\
-+	plasmacloud,pa300e)
- 		primary_kernel_mtd=3
- 		;;
- 	*)
-diff --git a/target/linux/ath79/base-files/lib/upgrade/platform.sh b/target/linux/ath79/base-files/lib/upgrade/platform.sh
-index c4f869932a02ef353e694b50496c3b2ed5d59f12..f1bbc24036d4f371c941f9736bc736be4903dec7 100644
---- a/target/linux/ath79/base-files/lib/upgrade/platform.sh
-+++ b/target/linux/ath79/base-files/lib/upgrade/platform.sh
-@@ -46,7 +46,8 @@ platform_do_upgrade() {
- 	jjplus,ja76pf2)
- 		redboot_fis_do_upgrade "$1" linux
- 		;;
--	plasmacloud,pa300)
-+	plasmacloud,pa300|\
-+	plasmacloud,pa300e)
- 		PART_NAME="inactive"
- 		platform_do_upgrade_dualboot_datachk "$1"
- 		;;
-diff --git a/target/linux/ath79/dts/qca9533_plasmacloud_pa300e.dts b/target/linux/ath79/dts/qca9533_plasmacloud_pa300e.dts
-new file mode 100644
-index 0000000000000000000000000000000000000000..1527a796bb63b7c33b60caaeb97438936daf727e
---- /dev/null
-+++ b/target/linux/ath79/dts/qca9533_plasmacloud_pa300e.dts
-@@ -0,0 +1,8 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-+
-+#include "qca9533_plasmacloud_pa300.dtsi"
-+
-+/ {
-+	compatible = "plasmacloud,pa300e", "qca,qca9533";
-+	model = "Plasma Cloud PA300E";
-+};
-diff --git a/target/linux/ath79/image/generic.mk b/target/linux/ath79/image/generic.mk
-index 3c1db9b3204d6784580f87ea9adb7a2ba98d285b..7159f9c6d2dabf0a80b4a107790471da32af97bc 100644
---- a/target/linux/ath79/image/generic.mk
-+++ b/target/linux/ath79/image/generic.mk
-@@ -663,6 +663,12 @@ define Device/plasmacloud_pa300
- endef
- TARGET_DEVICES += plasmacloud_pa300
- 
-+define Device/plasmacloud_pa300e
-+  $(Device/plasmacloud_pa300-common)
-+  DEVICE_TITLE := Plasma Cloud PA300E
-+endef
-+TARGET_DEVICES += plasmacloud_pa300e
-+
- define Device/netgear_wndr3800
-   $(Device/netgear_wndr3x00)
-   DEVICE_TITLE := NETGEAR WNDR3800
diff --git a/patches/openwrt/0019-ipq40xx-Change-name-for-openmesh.sh-to-vendor-free-name.patch b/patches/openwrt/0019-ipq40xx-Change-name-for-openmesh.sh-to-vendor-free-name.patch
deleted file mode 100644
index ebe4581a243995d903120dd2e0f5e6604255cf69..0000000000000000000000000000000000000000
--- a/patches/openwrt/0019-ipq40xx-Change-name-for-openmesh.sh-to-vendor-free-name.patch
+++ /dev/null
@@ -1,249 +0,0 @@
-From: Sven Eckelmann <sven@narfation.org>
-Date: Sat, 21 Nov 2020 22:27:11 +0100
-Subject: ipq40xx: Change name for openmesh.sh to vendor-free name
-
-Other vendors are using functionality similar to the ones OpenMesh used to
-implement two areas on the flash to store the default image and a fallback
-image. So just change the name to dualboot_datachk.sh to avoid duplicated
-code just to have the same script for different vendors.
-
-Signed-off-by: Sven Eckelmann <sven@narfation.org>
-Origin: backport, https://github.com/openwrt/openwrt/commit/8a891bfaa01d9592ea86c6b0cbbd5c04688c09f8
-
-diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/dualboot_datachk.sh b/target/linux/ipq40xx/base-files/lib/upgrade/dualboot_datachk.sh
-new file mode 100644
-index 0000000000000000000000000000000000000000..807a85d43ccd57642b52e7c1a7f92295cb6cd036
---- /dev/null
-+++ b/target/linux/ipq40xx/base-files/lib/upgrade/dualboot_datachk.sh
-@@ -0,0 +1,106 @@
-+# The U-Boot loader with the datachk patchset for dualbooting requires image
-+# sizes and checksums to be provided in the U-Boot environment.
-+# The devices come with 2 main partitions - while one is active
-+# sysupgrade will flash the other. The boot order is changed to boot the
-+# newly flashed partition. If the new partition can't be booted due to
-+# upgrade failures the previously used partition is loaded.
-+
-+platform_do_upgrade_dualboot_datachk() {
-+	local tar_file="$1"
-+	local restore_backup
-+	local primary_kernel_mtd
-+
-+	local setenv_script="/tmp/fw_env_upgrade"
-+
-+	local kernel_mtd="$(find_mtd_index $PART_NAME)"
-+	local kernel_offset="$(cat /sys/class/mtd/mtd${kernel_mtd}/offset)"
-+	local total_size="$(cat /sys/class/mtd/mtd${kernel_mtd}/size)"
-+
-+	# detect to which flash region the new image is written to.
-+	#
-+	# 1. check what is the mtd index for the first flash region on this
-+	#    device
-+	# 2. check if the target partition ("inactive") has the mtd index of
-+	#    the first flash region
-+	#
-+	#    - when it is: the new bootseq will be 1,2 and the first region is
-+	#      modified
-+	#    - when it isnt: bootseq will be 2,1 and the second region is
-+	#      modified
-+	#
-+	# The detection has to be done via the hardcoded mtd partition because
-+	# the current boot might be done with the fallback region. Let us
-+	# assume that the current bootseq is 1,2. The bootloader detected that
-+	# the image in flash region 1 is corrupt and thus switches to flash
-+	# region 2. The bootseq in the u-boot-env is now still the same and
-+	# the sysupgrade code can now only rely on the actual mtd indexes and
-+	# not the bootseq variable to detect the currently booted flash
-+	# region/image.
-+	#
-+	# In the above example, an implementation which uses bootseq ("1,2") to
-+	# detect the currently booted image would assume that region 1 is booted
-+	# and then overwrite the variables for the wrong flash region (aka the
-+	# one which isn't modified). This could result in a device which doesn't
-+	# boot anymore to Linux until it was reflashed with ap51-flash.
-+	local next_boot_part="1"
-+	case "$(board_name)" in
-+	openmesh,a42)
-+		primary_kernel_mtd=8
-+		;;
-+	openmesh,a62)
-+		primary_kernel_mtd=10
-+		;;
-+	*)
-+		echo "failed to detect primary kernel mtd partition for board"
-+		return 1
-+		;;
-+	esac
-+	[ "$kernel_mtd" = "$primary_kernel_mtd" ] || next_boot_part="2"
-+
-+	local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$')
-+	board_dir=${board_dir%/}
-+
-+	local kernel_length=$(tar xf $tar_file ${board_dir}/kernel -O | wc -c)
-+	local rootfs_length=$(tar xf $tar_file ${board_dir}/root -O | wc -c)
-+	# rootfs without EOF marker
-+	rootfs_length=$((rootfs_length-4))
-+
-+	local kernel_md5=$(tar xf $tar_file ${board_dir}/kernel -O | md5sum); kernel_md5="${kernel_md5%% *}"
-+	# md5 checksum of rootfs with EOF marker
-+	local rootfs_md5=$(tar xf $tar_file ${board_dir}/root -O | dd bs=1 count=$rootfs_length | md5sum); rootfs_md5="${rootfs_md5%% *}"
-+
-+	#
-+	# add tar support to get_image() to use default_do_upgrade() instead?
-+	#
-+
-+	# take care of restoring a saved config
-+	[ -n "$UPGRADE_BACKUP" ] && restore_backup="${MTD_CONFIG_ARGS} -j ${UPGRADE_BACKUP}"
-+
-+	mtd -q erase inactive
-+	tar xf $tar_file ${board_dir}/root -O | mtd -n -p $kernel_length $restore_backup write - $PART_NAME
-+	tar xf $tar_file ${board_dir}/kernel -O | mtd -n write - $PART_NAME
-+
-+	# prepare new u-boot env
-+	if [ "$next_boot_part" = "1" ]; then
-+		echo "bootseq 1,2" > $setenv_script
-+	else
-+		echo "bootseq 2,1" > $setenv_script
-+	fi
-+
-+	printf "kernel_size_%i 0x%08x\n" $next_boot_part $kernel_length >> $setenv_script
-+	printf "vmlinux_start_addr 0x%08x\n" ${kernel_offset} >> $setenv_script
-+	printf "vmlinux_size 0x%08x\n" ${kernel_length} >> $setenv_script
-+	printf "vmlinux_checksum %s\n" ${kernel_md5} >> $setenv_script
-+
-+	printf "rootfs_size_%i 0x%08x\n" $next_boot_part $((total_size-kernel_length)) >> $setenv_script
-+	printf "rootfs_start_addr 0x%08x\n" $((kernel_offset+kernel_length)) >> $setenv_script
-+	printf "rootfs_size 0x%08x\n" ${rootfs_length} >> $setenv_script
-+	printf "rootfs_checksum %s\n" ${rootfs_md5} >> $setenv_script
-+
-+	# store u-boot env changes
-+	mkdir -p /var/lock
-+	fw_setenv -s $setenv_script || {
-+		echo "failed to update U-Boot environment"
-+		return 1
-+	}
-+}
-diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/openmesh.sh b/target/linux/ipq40xx/base-files/lib/upgrade/openmesh.sh
-deleted file mode 100644
-index 8e02186eb81b17d56d0cb8ceba95dbe506e2984b..0000000000000000000000000000000000000000
---- a/target/linux/ipq40xx/base-files/lib/upgrade/openmesh.sh
-+++ /dev/null
-@@ -1,106 +0,0 @@
--# The U-Boot loader of the OpenMesh devices requires image sizes and
--# checksums to be provided in the U-Boot environment.
--# The OpenMesh devices come with 2 main partitions - while one is active
--# sysupgrade will flash the other. The boot order is changed to boot the
--# newly flashed partition. If the new partition can't be booted due to
--# upgrade failures the previously used partition is loaded.
--
--platform_do_upgrade_openmesh() {
--	local tar_file="$1"
--	local restore_backup
--	local primary_kernel_mtd
--
--	local setenv_script="/tmp/fw_env_upgrade"
--
--	local kernel_mtd="$(find_mtd_index $PART_NAME)"
--	local kernel_offset="$(cat /sys/class/mtd/mtd${kernel_mtd}/offset)"
--	local total_size="$(cat /sys/class/mtd/mtd${kernel_mtd}/size)"
--
--	# detect to which flash region the new image is written to.
--	#
--	# 1. check what is the mtd index for the first flash region on this
--	#    device
--	# 2. check if the target partition ("inactive") has the mtd index of
--	#    the first flash region
--	#
--	#    - when it is: the new bootseq will be 1,2 and the first region is
--	#      modified
--	#    - when it isnt: bootseq will be 2,1 and the second region is
--	#      modified
--	#
--	# The detection has to be done via the hardcoded mtd partition because
--	# the current boot might be done with the fallback region. Let us
--	# assume that the current bootseq is 1,2. The bootloader detected that
--	# the image in flash region 1 is corrupt and thus switches to flash
--	# region 2. The bootseq in the u-boot-env is now still the same and
--	# the sysupgrade code can now only rely on the actual mtd indexes and
--	# not the bootseq variable to detect the currently booted flash
--	# region/image.
--	#
--	# In the above example, an implementation which uses bootseq ("1,2") to
--	# detect the currently booted image would assume that region 1 is booted
--	# and then overwrite the variables for the wrong flash region (aka the
--	# one which isn't modified). This could result in a device which doesn't
--	# boot anymore to Linux until it was reflashed with ap51-flash.
--	local next_boot_part="1"
--	case "$(board_name)" in
--	openmesh,a42)
--		primary_kernel_mtd=8
--		;;
--	openmesh,a62)
--		primary_kernel_mtd=10
--		;;
--	*)
--		echo "failed to detect primary kernel mtd partition for board"
--		return 1
--		;;
--	esac
--	[ "$kernel_mtd" = "$primary_kernel_mtd" ] || next_boot_part="2"
--
--	local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$')
--	board_dir=${board_dir%/}
--
--	local kernel_length=$(tar xf $tar_file ${board_dir}/kernel -O | wc -c)
--	local rootfs_length=$(tar xf $tar_file ${board_dir}/root -O | wc -c)
--	# rootfs without EOF marker
--	rootfs_length=$((rootfs_length-4))
--
--	local kernel_md5=$(tar xf $tar_file ${board_dir}/kernel -O | md5sum); kernel_md5="${kernel_md5%% *}"
--	# md5 checksum of rootfs with EOF marker
--	local rootfs_md5=$(tar xf $tar_file ${board_dir}/root -O | dd bs=1 count=$rootfs_length | md5sum); rootfs_md5="${rootfs_md5%% *}"
--
--	#
--	# add tar support to get_image() to use default_do_upgrade() instead?
--	#
--
--	# take care of restoring a saved config
--	[ -n "$UPGRADE_BACKUP" ] && restore_backup="${MTD_CONFIG_ARGS} -j ${UPGRADE_BACKUP}"
--
--	mtd -q erase inactive
--	tar xf $tar_file ${board_dir}/root -O | mtd -n -p $kernel_length $restore_backup write - $PART_NAME
--	tar xf $tar_file ${board_dir}/kernel -O | mtd -n write - $PART_NAME
--
--	# prepare new u-boot env
--	if [ "$next_boot_part" = "1" ]; then
--		echo "bootseq 1,2" > $setenv_script
--	else
--		echo "bootseq 2,1" > $setenv_script
--	fi
--
--	printf "kernel_size_%i 0x%08x\n" $next_boot_part $kernel_length >> $setenv_script
--	printf "vmlinux_start_addr 0x%08x\n" ${kernel_offset} >> $setenv_script
--	printf "vmlinux_size 0x%08x\n" ${kernel_length} >> $setenv_script
--	printf "vmlinux_checksum %s\n" ${kernel_md5} >> $setenv_script
--
--	printf "rootfs_size_%i 0x%08x\n" $next_boot_part $((total_size-kernel_length)) >> $setenv_script
--	printf "rootfs_start_addr 0x%08x\n" $((kernel_offset+kernel_length)) >> $setenv_script
--	printf "rootfs_size 0x%08x\n" ${rootfs_length} >> $setenv_script
--	printf "rootfs_checksum %s\n" ${rootfs_md5} >> $setenv_script
--
--	# store u-boot env changes
--	mkdir -p /var/lock
--	fw_setenv -s $setenv_script || {
--		echo "failed to update U-Boot environment"
--		return 1
--	}
--}
-diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
-index 7253139497a8a8b9fab49cef3fce5eabe98d8002..66e23b77a7bb0a484e88a11eed9d526e4fc04b50 100644
---- a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
-+++ b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
-@@ -75,7 +75,7 @@ platform_do_upgrade() {
- 	openmesh,a42 |\
- 	openmesh,a62)
- 		PART_NAME="inactive"
--		platform_do_upgrade_openmesh "$1"
-+		platform_do_upgrade_dualboot_datachk "$1"
- 		;;
- 	zyxel,nbg6617)
- 		zyxel_do_upgrade "$1"
diff --git a/patches/openwrt/0020-ipq40xx-add-support-for-Plasma-Cloud-PA1200.patch b/patches/openwrt/0020-ipq40xx-add-support-for-Plasma-Cloud-PA1200.patch
deleted file mode 100644
index aec18d5122ba65e671f6f7cd1505447831715a4e..0000000000000000000000000000000000000000
--- a/patches/openwrt/0020-ipq40xx-add-support-for-Plasma-Cloud-PA1200.patch
+++ /dev/null
@@ -1,477 +0,0 @@
-From: Marek Lindner <marek.lindner@kaiwoo.ai>
-Date: Sun, 25 Nov 2018 21:46:54 +0800
-Subject: ipq40xx: add support for Plasma Cloud PA1200
-
-Device specifications:
-
-* QCA IPQ4018
-* 256 MB of RAM
-* 32 MB of SPI NOR flash (w25q256)
-  - 2x 15 MB available; but one of the 15 MB regions is the recovery image
-* 2T2R 2.4 GHz
-  - QCA4019 hw1.0 (SoC)
-  - requires special BDF in QCA4019/hw1.0/board-2.bin with
-    bus=ahb,bmi-chip-id=0,bmi-board-id=16,variant=PlasmaCloud-PA1200
-* 2T2R 5 GHz
-  - QCA4019 hw1.0 (SoC)
-  - requires special BDF in QCA4019/hw1.0/board-2.bin with
-    bus=ahb,bmi-chip-id=0,bmi-board-id=17,variant=PlasmaCloud-PA1200
-* 3x GPIO-LEDs for status (cyan, purple, yellow)
-* 1x GPIO-button (reset)
-* 1x USB (xHCI)
-* TTL pins are on board (arrow points to VCC, then follows: GND, TX, RX)
-* 2x gigabit ethernet
-  - phy@mdio4:
-    + Label: Ethernet 1
-    + gmac0 (ethaddr) in original firmware
-    + used as LAN interface
-  - phy@mdio3:
-    + Label: Ethernet 2
-    + gmac1 (eth1addr) in original firmware
-    + 802.3af/at POE(+)
-    + used as WAN interface
-* 12V/24V 1A DC
-
-Flashing instructions:
-
-The tool ap51-flash (https://github.com/ap51-flash/ap51-flash) should be
-used to transfer the factory image to the u-boot when the device boots up.
-
-Signed-off-by: Marek Lindner <marek.lindner@kaiwoo.ai>
-[sven@narfation.org: prepare commit message, rebase, use all LEDs, switch
-to dualboot_datachk upgrade script, use eth1 as designated WAN interface]
-Signed-off-by: Sven Eckelmann <sven@narfation.org>
-Origin: backport, https://github.com/openwrt/openwrt/commit/ea5bb6bbfee06f44f714aff40c8929505face221
-
-diff --git a/package/boot/uboot-envtools/files/ipq40xx b/package/boot/uboot-envtools/files/ipq40xx
-index 7bcad00b010bfef49790c2699995c00573ed53ad..3d31de8083b63516322ca33e9de792a592cf4bf1 100644
---- a/package/boot/uboot-envtools/files/ipq40xx
-+++ b/package/boot/uboot-envtools/files/ipq40xx
-@@ -34,7 +34,8 @@ case "$board" in
- alfa-network,ap120c-ac |\
- glinet,gl-b1300 |\
- openmesh,a42 |\
--openmesh,a62)
-+openmesh,a62 |\
-+plasmacloud,pa1200)
- 	ubootenv_add_uci_config "/dev/mtd5" "0x0" "0x10000" "0x10000"
- 	;;
- linksys,ea6350v3)
-diff --git a/package/firmware/ipq-wifi/Makefile b/package/firmware/ipq-wifi/Makefile
-index cc0505b97c6a04bafd88972cf6ce7890a637c33b..5e181f67437ec644d07d8fc4882908549d3d60ef 100644
---- a/package/firmware/ipq-wifi/Makefile
-+++ b/package/firmware/ipq-wifi/Makefile
-@@ -34,6 +34,7 @@ ALLWIFIBOARDS:= \
- 	engenius_ens620ext \
- 	linksys_ea6350v3 \
- 	linksys_ea8300 \
-+	plasmacloud_pa1200 \
- 	qxwlan_e2600ac
- 
- ALLWIFIPACKAGES:=$(foreach BOARD,$(ALLWIFIBOARDS),ipq-wifi-$(BOARD))
-@@ -107,6 +108,7 @@ $(eval $(call generate-ipq-wifi-package,engenius_eap1300,EnGenius EAP1300))
- $(eval $(call generate-ipq-wifi-package,engenius_ens620ext,EnGenius ENS620EXT))
- $(eval $(call generate-ipq-wifi-package,linksys_ea6350v3,Linksys EA6350v3))
- $(eval $(call generate-ipq-wifi-package,linksys_ea8300,Linksys EA8300))
-+$(eval $(call generate-ipq-wifi-package,plasmacloud_pa1200,Plasma Cloud PA1200))
- $(eval $(call generate-ipq-wifi-package,qxwlan_e2600ac,Qxwlan E2600AC))
- 
- $(foreach PACKAGE,$(ALLWIFIPACKAGES),$(eval $(call BuildPackage,$(PACKAGE))))
-diff --git a/package/firmware/ipq-wifi/board-plasmacloud_pa1200.qca4019 b/package/firmware/ipq-wifi/board-plasmacloud_pa1200.qca4019
-new file mode 100644
-index 0000000000000000000000000000000000000000..99d6df8c8c2bd6ed8058b290e00aef09d74dbfb8
-GIT binary patch
-literal 24324
-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
-
-literal 0
-HcmV?d00001
-
-diff --git a/scripts/om-fwupgradecfg-gen.sh b/scripts/om-fwupgradecfg-gen.sh
-index e271fa0dacad837191eaab7683ad8880d183a75e..552ed31f147df442926a39f7e2c8b3bd7b706571 100755
---- a/scripts/om-fwupgradecfg-gen.sh
-+++ b/scripts/om-fwupgradecfg-gen.sh
-@@ -7,7 +7,7 @@
- #
- 
- usage() {
--	echo "Usage: $0 <OM2P|OM5P|OM5PAC|MR600|MR900|MR1750|A60|A42|A62|PA300> <out file path> <kernel path> <rootfs path>"
-+	echo "Usage: $0 <OM2P|OM5P|OM5PAC|MR600|MR900|MR1750|A60|A42|A62|PA300|PA1200> <out file path> <kernel path> <rootfs path>"
- 	rm -f $CFG_OUT
- 	exit 1
- }
-@@ -37,7 +37,7 @@ case $CE_TYPE in
- 		SIZE_FACTOR=1
- 		SIZE_FORMAT="%d"
- 		;;
--	A42)
-+	A42|PA1200)
- 		MAX_PART_SIZE=15616
- 		KERNEL_FLASH_ADDR=0x180000
- 		FLASH_BS=65536
-diff --git a/target/linux/ipq40xx/base-files/etc/board.d/02_network b/target/linux/ipq40xx/base-files/etc/board.d/02_network
-index 49dd570242533068adf2c9df89e78560ba5f70eb..f446c04a00c863173c8fcb8242f7b2db1569acb3 100755
---- a/target/linux/ipq40xx/base-files/etc/board.d/02_network
-+++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network
-@@ -14,7 +14,8 @@ ipq40xx_setup_interfaces()
- 	case "$board" in
- 	8dev,jalapeno|\
- 	alfa-network,ap120c-ac|\
--	engenius,ens620ext)
-+	engenius,ens620ext|\
-+	plasmacloud,pa1200)
- 		ucidef_set_interfaces_lan_wan "eth0" "eth1"
- 		;;
- 	asus,map-ac2200|\
-diff --git a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
-index 15a2f2c09f8a92cc0accfbf9a977dbeb3355570d..28c34f6d0f9ebb47d0b2705e2edd5a55cc2e22eb 100644
---- a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
-+++ b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
-@@ -165,6 +165,7 @@ case "$FIRMWARE" in
- 	engenius,eap1300 |\
- 	openmesh,a42 |\
- 	openmesh,a62 |\
-+	plasmacloud,pa1200 |\
- 	qxwlan,e2600ac-c1 |\
- 	qxwlan,e2600ac-c2)
- 		ath10kcal_extract "0:ART" 4096 12064
-@@ -231,6 +232,7 @@ case "$FIRMWARE" in
- 	engenius,eap1300 |\
- 	openmesh,a42 |\
- 	openmesh,a62 |\
-+	plasmacloud,pa1200 |\
- 	qxwlan,e2600ac-c1 |\
- 	qxwlan,e2600ac-c2)
- 		ath10kcal_extract "0:ART" 20480 12064
-diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/dualboot_datachk.sh b/target/linux/ipq40xx/base-files/lib/upgrade/dualboot_datachk.sh
-index 807a85d43ccd57642b52e7c1a7f92295cb6cd036..60886071c9748407746ca9adfab52a1da9e524f2 100644
---- a/target/linux/ipq40xx/base-files/lib/upgrade/dualboot_datachk.sh
-+++ b/target/linux/ipq40xx/base-files/lib/upgrade/dualboot_datachk.sh
-@@ -44,6 +44,7 @@ platform_do_upgrade_dualboot_datachk() {
- 	# boot anymore to Linux until it was reflashed with ap51-flash.
- 	local next_boot_part="1"
- 	case "$(board_name)" in
-+	plasmacloud,pa1200|\
- 	openmesh,a42)
- 		primary_kernel_mtd=8
- 		;;
-diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
-index 66e23b77a7bb0a484e88a11eed9d526e4fc04b50..6ec538cfd4cced656130169522cac1622a3b4ef2 100644
---- a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
-+++ b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
-@@ -73,7 +73,8 @@ platform_do_upgrade() {
- 		nand_do_upgrade "$1"
- 		;;
- 	openmesh,a42 |\
--	openmesh,a62)
-+	openmesh,a62 |\
-+	plasmacloud,pa1200)
- 		PART_NAME="inactive"
- 		platform_do_upgrade_dualboot_datachk "$1"
- 		;;
-diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-pa1200.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-pa1200.dts
-new file mode 100644
-index 0000000000000000000000000000000000000000..bcb9552ce777d1d522c7642649e22ec26f04d7d2
---- /dev/null
-+++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4018-pa1200.dts
-@@ -0,0 +1,197 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-+/* Copyright (c) 2017-2020, Sven Eckelmann <sven@narfation.org>
-+ * Copyright (c) 2018, Marek Lindner <marek.lindner@kaiwoo.ai>
-+ */
-+
-+#include "qcom-ipq4019.dtsi"
-+#include <dt-bindings/gpio/gpio.h>
-+#include <dt-bindings/input/input.h>
-+#include <dt-bindings/soc/qcom,tcsr.h>
-+
-+/ {
-+	model = "Plasma Cloud PA1200";
-+	compatible = "plasmacloud,pa1200";
-+
-+	soc {
-+		rng@22000 {
-+			status = "okay";
-+		};
-+
-+		mdio@90000 {
-+			status = "okay";
-+		};
-+
-+		ess-psgmii@98000 {
-+			status = "okay";
-+		};
-+
-+		tcsr@194b000 {
-+			/* select hostmode */
-+			compatible = "qcom,tcsr";
-+			reg = <0x194b000 0x100>;
-+			qcom,usb-hsphy-mode-select = <TCSR_USB_HSPHY_HOST_MODE>;
-+			status = "okay";
-+		};
-+
-+		tcsr@1949000 {
-+			compatible = "qcom,tcsr";
-+			reg = <0x1949000 0x100>;
-+			qcom,wifi_glb_cfg = <TCSR_WIFI_GLB_CFG>;
-+		};
-+
-+		ess_tcsr@1953000 {
-+			compatible = "qcom,tcsr";
-+			reg = <0x1953000 0x1000>;
-+			qcom,ess-interface-select = <TCSR_ESS_PSGMII>;
-+		};
-+
-+		tcsr@1957000 {
-+			compatible = "qcom,tcsr";
-+			reg = <0x1957000 0x100>;
-+			qcom,wifi_noc_memtype_m0_m2 = <TCSR_WIFI_NOC_MEMTYPE_M0_M2>;
-+		};
-+
-+		usb2: usb2@60f8800 {
-+			status = "okay";
-+		};
-+
-+		crypto@8e3a000 {
-+			status = "okay";
-+		};
-+
-+		watchdog@b017000 {
-+			status = "okay";
-+		};
-+
-+		ess-switch@c000000 {
-+			status = "okay";
-+		};
-+
-+		edma@c080000 {
-+			status = "okay";
-+		};
-+	};
-+
-+	keys {
-+		compatible = "gpio-keys";
-+
-+		reset {
-+			label = "reset";
-+			gpios = <&tlmm 59 GPIO_ACTIVE_LOW>;
-+			linux,code = <KEY_RESTART>;
-+		};
-+	};
-+
-+	aliases {
-+		led-boot = &led_status_purple;
-+		led-failsafe = &led_status_yellow;
-+		led-running = &led_status_cyan;
-+		led-upgrade = &led_status_yellow;
-+	};
-+
-+	leds {
-+		compatible = "gpio-leds";
-+
-+		led_status_cyan: status_cyan {
-+			label = "cyan:status";
-+			gpios = <&tlmm 0 GPIO_ACTIVE_HIGH>;
-+		};
-+
-+		led_status_purple: status_purple {
-+			label = "purple:status";
-+			gpios = <&tlmm 1 GPIO_ACTIVE_HIGH>;
-+		};
-+
-+		led_status_yellow: status_yellow {
-+			label = "yellow:status";
-+			gpios = <&tlmm 2 GPIO_ACTIVE_HIGH>;
-+		};
-+	};
-+
-+};
-+
-+&tlmm {
-+	serial_pins: serial_pinmux {
-+		mux {
-+			pins = "gpio60", "gpio61";
-+			function = "blsp_uart0";
-+			bias-disable;
-+		};
-+	};
-+
-+	spi_0_pins: spi_0_pinmux {
-+		pin {
-+			function = "blsp_spi0";
-+			pins = "gpio55", "gpio56", "gpio57";
-+			drive-strength = <12>;
-+			bias-disable;
-+		};
-+		pin_cs {
-+			function = "gpio";
-+			pins = "gpio54";
-+			drive-strength = <2>;
-+			bias-disable;
-+			output-high;
-+		};
-+	};
-+};
-+
-+&blsp_dma {
-+	status = "okay";
-+};
-+
-+&blsp1_spi1 {
-+	pinctrl-0 = <&spi_0_pins>;
-+	pinctrl-names = "default";
-+	status = "okay";
-+	cs-gpios = <&tlmm 54 GPIO_ACTIVE_HIGH>;
-+
-+	flash@0 {
-+		#address-cells = <1>;
-+		#size-cells = <1>;
-+		compatible = "jedec,spi-nor";
-+		reg = <0>;
-+		spi-max-frequency = <24000000>;
-+		/* partitions are passed via bootloader */
-+	};
-+};
-+
-+&blsp1_uart1 {
-+	pinctrl-0 = <&serial_pins>;
-+	pinctrl-names = "default";
-+	status = "okay";
-+};
-+
-+&cryptobam {
-+	status = "okay";
-+};
-+
-+&gmac0 {
-+	qcom,phy_mdio_addr = <4>;
-+	qcom,poll_required = <1>;
-+	qcom,forced_speed = <1000>;
-+	qcom,forced_duplex = <1>;
-+	vlan_tag = <2 0x20>;
-+};
-+
-+&gmac1 {
-+	qcom,phy_mdio_addr = <3>;
-+	qcom,poll_required = <1>;
-+	qcom,forced_speed = <1000>;
-+	qcom,forced_duplex = <1>;
-+	vlan_tag = <1 0x10>;
-+};
-+
-+&usb2_hs_phy {
-+	status = "okay";
-+};
-+
-+&wifi0 {
-+	status = "okay";
-+	qcom,ath10k-calibration-variant = "PlasmaCloud-PA1200";
-+};
-+
-+&wifi1 {
-+	status = "okay";
-+	qcom,ath10k-calibration-variant = "PlasmaCloud-PA1200";
-+};
-diff --git a/target/linux/ipq40xx/image/Makefile b/target/linux/ipq40xx/image/Makefile
-index 68dcbc59a42f6d8360b87c7b4e74cd34f697b465..e14d00ad08b8caf2dae935d573f0ba7bb0433c23 100644
---- a/target/linux/ipq40xx/image/Makefile
-+++ b/target/linux/ipq40xx/image/Makefile
-@@ -345,6 +345,21 @@ endef
- 
- TARGET_DEVICES += openmesh_a62
- 
-+define Device/plasmacloud_pa1200
-+	$(call Device/FitImageLzma)
-+	DEVICE_DTS := qcom-ipq4018-pa1200
-+	DEVICE_DTS_CONFIG := config@pc.pa1200
-+	BLOCKSIZE := 64k
-+	DEVICE_TITLE := Plasma Cloud PA1200
-+	KERNEL = kernel-bin | lzma | fit lzma $$(DTS_DIR)/$$(DEVICE_DTS).dtb | pad-to $$(BLOCKSIZE)
-+	IMAGE_SIZE := 15616k
-+	IMAGES = factory.bin sysupgrade.bin
-+	IMAGE/factory.bin := append-rootfs | pad-rootfs | openmesh-image ce_type=PA1200
-+	IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-rootfs | sysupgrade-tar rootfs=$$$$@ | append-metadata
-+	DEVICE_PACKAGES := uboot-envtools ipq-wifi-plasmacloud-pa1200
-+endef
-+TARGET_DEVICES += plasmacloud_pa1200
-+
- define Device/qcom_ap-dk01.1-c1
- 	DEVICE_TITLE := QCA AP-DK01.1-C1
- 	BOARD_NAME := ap-dk01.1-c1
-diff --git a/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch b/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch
-index fc8a88336491c2ac7c2a93fafb1f2b6fd38695be..cd0cd4164207f0a851d19a42fce07ad54fec8939 100644
---- a/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch
-+++ b/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch
-@@ -10,7 +10,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
- 
- --- a/arch/arm/boot/dts/Makefile
- +++ b/arch/arm/boot/dts/Makefile
--@@ -697,7 +697,32 @@ dtb-$(CONFIG_ARCH_QCOM) += \
-+@@ -697,7 +697,33 @@ dtb-$(CONFIG_ARCH_QCOM) += \
-  	qcom-apq8074-dragonboard.dtb \
-  	qcom-apq8084-ifc6540.dtb \
-  	qcom-apq8084-mtp.dtb \
-@@ -24,6 +24,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
- +	qcom-ipq4018-fritz4040.dtb \
- +	qcom-ipq4018-jalapeno.dtb \
- +	qcom-ipq4018-nbg6617.dtb \
-++	qcom-ipq4018-pa1200.dtb \
- +	qcom-ipq4018-rt-ac58u.dtb \
- +	qcom-ipq4018-wre6606.dtb \
-  	qcom-ipq4019-ap.dk01.1-c1.dtb \
diff --git a/patches/openwrt/0021-ipq40xx-add-support-for-Plasma-Cloud-PA2200.patch b/patches/openwrt/0021-ipq40xx-add-support-for-Plasma-Cloud-PA2200.patch
deleted file mode 100644
index b588f083ab8f97c9d9e0e44dfb49fb136cd0aad6..0000000000000000000000000000000000000000
--- a/patches/openwrt/0021-ipq40xx-add-support-for-Plasma-Cloud-PA2200.patch
+++ /dev/null
@@ -1,549 +0,0 @@
-From: Marek Lindner <marek.lindner@kaiwoo.ai>
-Date: Fri, 14 Dec 2018 23:46:53 +0800
-Subject: ipq40xx: add support for Plasma Cloud PA2200
-
-Device specifications:
-
-* QCA IPQ4019
-* 256 MB of RAM
-* 32 MB of SPI NOR flash (w25q256)
-  - 2x 15 MB available; but one of the 15 MB regions is the recovery image
-* 2T2R 2.4 GHz
-  - QCA4019 hw1.0 (SoC)
-  - requires special BDF in QCA4019/hw1.0/board-2.bin with
-    bus=ahb,bmi-chip-id=0,bmi-board-id=20,variant=PlasmaCloud-PA2200
-* 2T2R 5 GHz (channel 36-64)
-  - QCA9888 hw2.0 (PCI)
-  - requires special BDF in QCA9888/hw2.0/board-2.bin
-    bus=pci,bmi-chip-id=0,bmi-board-id=16,variant=PlasmaCloud-PA2200
-* 2T2R 5 GHz (channel 100-165)
-  - QCA4019 hw1.0 (SoC)
-  - requires special BDF in QCA4019/hw1.0/board-2.bin with
-    bus=ahb,bmi-chip-id=0,bmi-board-id=21,variant=PlasmaCloud-PA2200
-* GPIO-LEDs for 2.4GHz, 5GHz-SoC and 5GHz-PCIE
-* GPIO-LEDs for power (orange) and status (blue)
-* 1x GPIO-button (reset)
-* TTL pins are on board (arrow points to VCC, then follows: GND, TX, RX)
-* 2x gigabit ethernet
-  - phy@mdio3:
-    + Label: Ethernet 1
-    + gmac0 (ethaddr) in original firmware
-    + used as LAN interface
-  - phy@mdio4:
-    + Label: Ethernet 2
-    + gmac1 (eth1addr) in original firmware
-    + 802.3at POE+
-    + used as WAN interface
-* 12V 2A DC
-
-Flashing instructions:
-
-The tool ap51-flash (https://github.com/ap51-flash/ap51-flash) should be
-used to transfer the factory image to the u-boot when the device boots up.
-
-Signed-off-by: Marek Lindner <marek.lindner@kaiwoo.ai>
-[sven@narfation.org: prepare commit message, rebase, use all LEDs, switch
-to dualboot_datachk upgrade script, use eth1 as designated WAN interface]
-Signed-off-by: Sven Eckelmann <sven@narfation.org>
-Origin: backport, https://github.com/openwrt/openwrt/commit/4871fd2616acb03fefe69b068955dba36eb00770
-
-diff --git a/package/boot/uboot-envtools/files/ipq40xx b/package/boot/uboot-envtools/files/ipq40xx
-index 3d31de8083b63516322ca33e9de792a592cf4bf1..e30b58ec4bf2871b7f311de7fdbe54aecc9ba29a 100644
---- a/package/boot/uboot-envtools/files/ipq40xx
-+++ b/package/boot/uboot-envtools/files/ipq40xx
-@@ -35,7 +35,8 @@ alfa-network,ap120c-ac |\
- glinet,gl-b1300 |\
- openmesh,a42 |\
- openmesh,a62 |\
--plasmacloud,pa1200)
-+plasmacloud,pa1200 |\
-+plasmacloud,pa2200)
- 	ubootenv_add_uci_config "/dev/mtd5" "0x0" "0x10000" "0x10000"
- 	;;
- linksys,ea6350v3)
-diff --git a/package/firmware/ipq-wifi/Makefile b/package/firmware/ipq-wifi/Makefile
-index 5e181f67437ec644d07d8fc4882908549d3d60ef..6e0d840de247f3ee6e8f9a097a8649a8f3abf2d7 100644
---- a/package/firmware/ipq-wifi/Makefile
-+++ b/package/firmware/ipq-wifi/Makefile
-@@ -35,6 +35,7 @@ ALLWIFIBOARDS:= \
- 	linksys_ea6350v3 \
- 	linksys_ea8300 \
- 	plasmacloud_pa1200 \
-+	plasmacloud_pa2200 \
- 	qxwlan_e2600ac
- 
- ALLWIFIPACKAGES:=$(foreach BOARD,$(ALLWIFIBOARDS),ipq-wifi-$(BOARD))
-@@ -109,6 +110,7 @@ $(eval $(call generate-ipq-wifi-package,engenius_ens620ext,EnGenius ENS620EXT))
- $(eval $(call generate-ipq-wifi-package,linksys_ea6350v3,Linksys EA6350v3))
- $(eval $(call generate-ipq-wifi-package,linksys_ea8300,Linksys EA8300))
- $(eval $(call generate-ipq-wifi-package,plasmacloud_pa1200,Plasma Cloud PA1200))
-+$(eval $(call generate-ipq-wifi-package,plasmacloud_pa2200,Plasma Cloud PA2200))
- $(eval $(call generate-ipq-wifi-package,qxwlan_e2600ac,Qxwlan E2600AC))
- 
- $(foreach PACKAGE,$(ALLWIFIPACKAGES),$(eval $(call BuildPackage,$(PACKAGE))))
-diff --git a/package/firmware/ipq-wifi/board-plasmacloud_pa2200.qca4019 b/package/firmware/ipq-wifi/board-plasmacloud_pa2200.qca4019
-new file mode 100644
-index 0000000000000000000000000000000000000000..d1db0f5f4b8b734c0c43df38d9eedb0b84f72109
-GIT binary patch
-literal 24324
-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
-
-literal 0
-HcmV?d00001
-
-diff --git a/package/firmware/ipq-wifi/board-plasmacloud_pa2200.qca9888 b/package/firmware/ipq-wifi/board-plasmacloud_pa2200.qca9888
-new file mode 100644
-index 0000000000000000000000000000000000000000..6c3f083eb20775cf2a322aa5694c8a3e717ec71c
-GIT binary patch
-literal 12172
-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
-
-literal 0
-HcmV?d00001
-
-diff --git a/scripts/om-fwupgradecfg-gen.sh b/scripts/om-fwupgradecfg-gen.sh
-index 552ed31f147df442926a39f7e2c8b3bd7b706571..92d8df9de3d09f2ee2c6edd35750ad03c8f02d8a 100755
---- a/scripts/om-fwupgradecfg-gen.sh
-+++ b/scripts/om-fwupgradecfg-gen.sh
-@@ -7,7 +7,7 @@
- #
- 
- usage() {
--	echo "Usage: $0 <OM2P|OM5P|OM5PAC|MR600|MR900|MR1750|A60|A42|A62|PA300|PA1200> <out file path> <kernel path> <rootfs path>"
-+	echo "Usage: $0 <OM2P|OM5P|OM5PAC|MR600|MR900|MR1750|A60|A42|A62|PA300|PA1200|PA2200> <out file path> <kernel path> <rootfs path>"
- 	rm -f $CFG_OUT
- 	exit 1
- }
-@@ -45,7 +45,7 @@ case $CE_TYPE in
- 		SIZE_FACTOR=1024
- 		SIZE_FORMAT="0x%08x"
- 		;;
--	A62)
-+	A62|PA2200)
- 		MAX_PART_SIZE=15552
- 		KERNEL_FLASH_ADDR=0x1a0000
- 		FLASH_BS=65536
-diff --git a/target/linux/ipq40xx/base-files/etc/board.d/02_network b/target/linux/ipq40xx/base-files/etc/board.d/02_network
-index f446c04a00c863173c8fcb8242f7b2db1569acb3..aaada06e370591d43b59e756dd8b7acdef203d17 100755
---- a/target/linux/ipq40xx/base-files/etc/board.d/02_network
-+++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network
-@@ -15,7 +15,8 @@ ipq40xx_setup_interfaces()
- 	8dev,jalapeno|\
- 	alfa-network,ap120c-ac|\
- 	engenius,ens620ext|\
--	plasmacloud,pa1200)
-+	plasmacloud,pa1200|\
-+	plasmacloud,pa2200)
- 		ucidef_set_interfaces_lan_wan "eth0" "eth1"
- 		;;
- 	asus,map-ac2200|\
-diff --git a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
-index 28c34f6d0f9ebb47d0b2705e2edd5a55cc2e22eb..e0677371ea93f32c5ceb4b0b858e236f9c764863 100644
---- a/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
-+++ b/target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
-@@ -123,7 +123,8 @@ case "$FIRMWARE" in
- 		# OEM assigns 4 sequential MACs
- 		ath10kcal_patch_mac_crc $(macaddr_setbit_la $(macaddr_add "$(cat /sys/class/net/eth0/address)" 4))
- 		;;
--	openmesh,a62)
-+	openmesh,a62 |\
-+	plasmacloud,pa2200)
- 		ath10kcal_extract "0:ART" 36864 12064
- 		;;
- 	esac
-@@ -166,6 +167,7 @@ case "$FIRMWARE" in
- 	openmesh,a42 |\
- 	openmesh,a62 |\
- 	plasmacloud,pa1200 |\
-+	plasmacloud,pa2200 |\
- 	qxwlan,e2600ac-c1 |\
- 	qxwlan,e2600ac-c2)
- 		ath10kcal_extract "0:ART" 4096 12064
-@@ -233,6 +235,7 @@ case "$FIRMWARE" in
- 	openmesh,a42 |\
- 	openmesh,a62 |\
- 	plasmacloud,pa1200 |\
-+	plasmacloud,pa2200 |\
- 	qxwlan,e2600ac-c1 |\
- 	qxwlan,e2600ac-c2)
- 		ath10kcal_extract "0:ART" 20480 12064
-diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/dualboot_datachk.sh b/target/linux/ipq40xx/base-files/lib/upgrade/dualboot_datachk.sh
-index 60886071c9748407746ca9adfab52a1da9e524f2..81418fe0ba474bebd6f4a6defe730644b6aee76e 100644
---- a/target/linux/ipq40xx/base-files/lib/upgrade/dualboot_datachk.sh
-+++ b/target/linux/ipq40xx/base-files/lib/upgrade/dualboot_datachk.sh
-@@ -48,6 +48,7 @@ platform_do_upgrade_dualboot_datachk() {
- 	openmesh,a42)
- 		primary_kernel_mtd=8
- 		;;
-+	plasmacloud,pa2200|\
- 	openmesh,a62)
- 		primary_kernel_mtd=10
- 		;;
-diff --git a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
-index 6ec538cfd4cced656130169522cac1622a3b4ef2..e7336e8d14bc9b197c8a76585729a8c71355f903 100644
---- a/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
-+++ b/target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
-@@ -74,7 +74,8 @@ platform_do_upgrade() {
- 		;;
- 	openmesh,a42 |\
- 	openmesh,a62 |\
--	plasmacloud,pa1200)
-+	plasmacloud,pa1200 |\
-+	plasmacloud,pa2200)
- 		PART_NAME="inactive"
- 		platform_do_upgrade_dualboot_datachk "$1"
- 		;;
-diff --git a/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-pa2200.dts b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-pa2200.dts
-new file mode 100644
-index 0000000000000000000000000000000000000000..2d0655114b4e0749e0c878a3d16ece2ad2ab2223
---- /dev/null
-+++ b/target/linux/ipq40xx/files-4.14/arch/arm/boot/dts/qcom-ipq4019-pa2200.dts
-@@ -0,0 +1,210 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
-+/* Copyright (c) 2017-2020, Sven Eckelmann <sven@narfation.org>
-+ * Copyright (c) 2018, Marek Lindner <marek.lindner@kaiwoo.ai>
-+ */
-+
-+#include "qcom-ipq4019.dtsi"
-+#include <dt-bindings/gpio/gpio.h>
-+#include <dt-bindings/input/input.h>
-+#include <dt-bindings/soc/qcom,tcsr.h>
-+
-+/ {
-+	model = "Plasma Cloud PA2200";
-+	compatible = "plasmacloud,pa2200";
-+
-+	soc {
-+		rng@22000 {
-+			status = "okay";
-+		};
-+
-+		mdio@90000 {
-+			status = "okay";
-+		};
-+
-+		ess-psgmii@98000 {
-+			status = "okay";
-+		};
-+
-+		tcsr@1949000 {
-+			compatible = "qcom,tcsr";
-+			reg = <0x1949000 0x100>;
-+			qcom,wifi_glb_cfg = <TCSR_WIFI_GLB_CFG>;
-+		};
-+
-+		ess_tcsr@1953000 {
-+			compatible = "qcom,tcsr";
-+			reg = <0x1953000 0x1000>;
-+			qcom,ess-interface-select = <TCSR_ESS_PSGMII>;
-+		};
-+
-+		tcsr@1957000 {
-+			compatible = "qcom,tcsr";
-+			reg = <0x1957000 0x100>;
-+			qcom,wifi_noc_memtype_m0_m2 = <TCSR_WIFI_NOC_MEMTYPE_M0_M2>;
-+		};
-+
-+		crypto@8e3a000 {
-+			status = "okay";
-+		};
-+
-+		watchdog@b017000 {
-+			status = "okay";
-+		};
-+
-+		ess-switch@c000000 {
-+			switch_lan_bmp = <0x10>;
-+			switch_wan_bmp = <0x20>;
-+
-+			status = "okay";
-+		};
-+
-+		edma@c080000 {
-+			status = "okay";
-+		};
-+	};
-+
-+	keys {
-+		compatible = "gpio-keys";
-+
-+		reset {
-+			label = "reset";
-+			gpios = <&tlmm 18 GPIO_ACTIVE_LOW>;
-+			linux,code = <KEY_RESTART >;
-+		};
-+	};
-+
-+	aliases {
-+		led-boot = &led_power_orange;
-+		led-failsafe = &led_status_blue;
-+		led-running = &led_power_orange;
-+		led-upgrade = &led_status_blue;
-+	};
-+
-+	leds {
-+		compatible = "gpio-leds";
-+
-+		led_power_orange: power_orange {
-+			label = "orange:power";
-+			gpios = <&tlmm 43 GPIO_ACTIVE_LOW>;
-+		};
-+
-+		2g_blue {
-+			label = "blue:2g";
-+			gpios = <&tlmm 46 GPIO_ACTIVE_LOW>;
-+			linux,default-trigger = "phy1tpt";
-+		};
-+
-+		2g_green {
-+			label = "green:5g1";
-+			gpios = <&tlmm 47 GPIO_ACTIVE_LOW>;
-+			linux,default-trigger = "phy0tpt";
-+		};
-+
-+		5g2_green {
-+			label = "green:5g2";
-+			gpios = <&tlmm 48 GPIO_ACTIVE_LOW>;
-+			linux,default-trigger = "phy2tpt";
-+		};
-+
-+		led_status_blue: status_blue {
-+			label = "blue:status";
-+			gpios = <&tlmm 50 GPIO_ACTIVE_LOW>;
-+		};
-+	};
-+};
-+
-+&tlmm {
-+	serial_pins: serial_pinmux {
-+		mux {
-+			pins = "gpio16", "gpio17";
-+			function = "blsp_uart0";
-+			bias-disable;
-+		};
-+	};
-+
-+	spi_0_pins: spi_0_pinmux {
-+		pin {
-+			function = "blsp_spi0";
-+			pins = "gpio13", "gpio14", "gpio15";
-+			drive-strength = <12>;
-+			bias-disable;
-+		};
-+		pin_cs {
-+			function = "gpio";
-+			pins = "gpio12";
-+			drive-strength = <2>;
-+			bias-disable;
-+			output-high;
-+		};
-+	};
-+};
-+
-+&blsp_dma {
-+	status = "okay";
-+};
-+
-+&blsp1_spi1 {
-+	pinctrl-0 = <&spi_0_pins>;
-+	pinctrl-names = "default";
-+	status = "okay";
-+	cs-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>;
-+
-+	flash@0 {
-+		#address-cells = <1>;
-+		#size-cells = <1>;
-+		compatible = "jedec,spi-nor";
-+		reg = <0>;
-+		spi-max-frequency = <24000000>;
-+		/* partitions are passed via bootloader */
-+	};
-+};
-+
-+&blsp1_uart1 {
-+	pinctrl-0 = <&serial_pins>;
-+	pinctrl-names = "default";
-+	status = "okay";
-+};
-+
-+&cryptobam {
-+	status = "okay";
-+};
-+
-+&gmac0 {
-+	qcom,phy_mdio_addr = <3>;
-+	qcom,poll_required = <1>;
-+	qcom,forced_speed = <1000>;
-+	qcom,forced_duplex = <1>;
-+	vlan_tag = <1 0x10>;
-+};
-+
-+&pcie0 {
-+	status = "okay";
-+	perst-gpio = <&tlmm 38 GPIO_ACTIVE_LOW>;
-+	wake-gpio = <&tlmm 50 GPIO_ACTIVE_LOW>;
-+
-+	bridge@0,0 {
-+		reg = <0x00000000 0 0 0 0>;
-+		#address-cells = <3>;
-+		#size-cells = <2>;
-+		ranges;
-+
-+		wifi2: wifi@1,0 {
-+			compatible = "qcom,ath10k";
-+			status = "okay";
-+			reg = <0x00010000 0 0 0 0>;
-+			qcom,ath10k-calibration-variant = "PlasmaCloud-PA2200";
-+			ieee80211-freq-limit = <5170000 5350000>;
-+		};
-+	};
-+};
-+
-+&wifi0 {
-+	status = "okay";
-+	qcom,ath10k-calibration-variant = "PlasmaCloud-PA2200";
-+};
-+
-+&wifi1 {
-+	status = "okay";
-+	qcom,ath10k-calibration-variant = "PlasmaCloud-PA2200";
-+	ieee80211-freq-limit = <5470000 5875000>;
-+};
-diff --git a/target/linux/ipq40xx/image/Makefile b/target/linux/ipq40xx/image/Makefile
-index e14d00ad08b8caf2dae935d573f0ba7bb0433c23..9872d0c4abcbb9d607bb15c47f0f820e7cdea077 100644
---- a/target/linux/ipq40xx/image/Makefile
-+++ b/target/linux/ipq40xx/image/Makefile
-@@ -360,6 +360,21 @@ define Device/plasmacloud_pa1200
- endef
- TARGET_DEVICES += plasmacloud_pa1200
- 
-+define Device/plasmacloud_pa2200
-+	$(call Device/FitImageLzma)
-+	DEVICE_DTS := qcom-ipq4019-pa2200
-+	DEVICE_DTS_CONFIG := config@pc.pa2200
-+	BLOCKSIZE := 64k
-+	DEVICE_TITLE := Plasma Cloud PA2200
-+	KERNEL = kernel-bin | lzma | fit lzma $$(DTS_DIR)/$$(DEVICE_DTS).dtb | pad-to $$(BLOCKSIZE)
-+	IMAGE_SIZE := 15552k
-+	IMAGES = factory.bin sysupgrade.bin
-+	IMAGE/factory.bin := append-rootfs | pad-rootfs | openmesh-image ce_type=PA2200
-+	IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-rootfs | sysupgrade-tar rootfs=$$$$@ | append-metadata
-+	DEVICE_PACKAGES := ath10k-firmware-qca9888-ct ipq-wifi-plasmacloud-pa2200 uboot-envtools
-+endef
-+TARGET_DEVICES += plasmacloud_pa2200
-+
- define Device/qcom_ap-dk01.1-c1
- 	DEVICE_TITLE := QCA AP-DK01.1-C1
- 	BOARD_NAME := ap-dk01.1-c1
-diff --git a/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch b/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch
-index cd0cd4164207f0a851d19a42fce07ad54fec8939..22c9e2305740938b57802f3e8c8a37fda4d855d9 100644
---- a/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch
-+++ b/target/linux/ipq40xx/patches-4.14/901-arm-boot-add-dts-files.patch
-@@ -10,7 +10,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
- 
- --- a/arch/arm/boot/dts/Makefile
- +++ b/arch/arm/boot/dts/Makefile
--@@ -697,7 +697,33 @@ dtb-$(CONFIG_ARCH_QCOM) += \
-+@@ -697,7 +697,34 @@ dtb-$(CONFIG_ARCH_QCOM) += \
-  	qcom-apq8074-dragonboard.dtb \
-  	qcom-apq8084-ifc6540.dtb \
-  	qcom-apq8084-mtp.dtb \
-@@ -35,6 +35,7 @@ Signed-off-by: John Crispin <john@phrozen.org>
- +	qcom-ipq4019-fritzrepeater-3000.dtb \
- +	qcom-ipq4019-linksys_ea8300.dtb \
- +	qcom-ipq4019-map-ac2200.dtb \
-++	qcom-ipq4019-pa2200.dtb \
- +	qcom-ipq4019-qxwlan-e2600ac-c1.dtb \
- +	qcom-ipq4019-qxwlan-e2600ac-c2.dtb \
- +	qcom-ipq4028-wpj428.dtb \
diff --git a/patches/openwrt/0022-kernel-bridge-Fix-a-deadlock-when-enabling-multicast-snooping.patch b/patches/openwrt/0022-kernel-bridge-Fix-a-deadlock-when-enabling-multicast-snooping.patch
deleted file mode 100644
index ed867438fd9937ca3e77bc530c3c4f2ef7f148a7..0000000000000000000000000000000000000000
--- a/patches/openwrt/0022-kernel-bridge-Fix-a-deadlock-when-enabling-multicast-snooping.patch
+++ /dev/null
@@ -1,275 +0,0 @@
-From: Linus Lüssing <linus.luessing@c0d3.blue>
-Date: Mon, 25 Jan 2021 01:38:19 +0100
-Subject: kernel: bridge: Fix a deadlock when enabling multicast snooping
-
-[ Upstream commit 851d0a73c90e6c8c63fef106c6c1e73df7e05d9d ]
-
-From: Joseph Huang <Joseph.Huang@garmin.com>
-
-When enabling multicast snooping, bridge module deadlocks on multicast_lock
-if 1) IPv6 is enabled, and 2) there is an existing querier on the same L2
-network.
-
-The deadlock was caused by the following sequence: While holding the lock,
-br_multicast_open calls br_multicast_join_snoopers, which eventually causes
-IP stack to (attempt to) send out a Listener Report (in igmp6_join_group).
-Since the destination Ethernet address is a multicast address, br_dev_xmit
-feeds the packet back to the bridge via br_multicast_rcv, which in turn
-calls br_multicast_add_group, which then deadlocks on multicast_lock.
-
-The fix is to move the call br_multicast_join_snoopers outside of the
-critical section. This works since br_multicast_join_snoopers only deals
-with IP and does not modify any multicast data structures of the bridge,
-so there's no need to hold the lock.
-
-Steps to reproduce:
-1. sysctl net.ipv6.conf.all.force_mld_version=1
-2. have another querier
-3. ip link set dev bridge type bridge mcast_snooping 0 && \
-   ip link set dev bridge type bridge mcast_snooping 1 < deadlock >
-
-A typical call trace looks like the following:
-
-[  936.251495]  _raw_spin_lock+0x5c/0x68
-[  936.255221]  br_multicast_add_group+0x40/0x170 [bridge]
-[  936.260491]  br_multicast_rcv+0x7ac/0xe30 [bridge]
-[  936.265322]  br_dev_xmit+0x140/0x368 [bridge]
-[  936.269689]  dev_hard_start_xmit+0x94/0x158
-[  936.273876]  __dev_queue_xmit+0x5ac/0x7f8
-[  936.277890]  dev_queue_xmit+0x10/0x18
-[  936.281563]  neigh_resolve_output+0xec/0x198
-[  936.285845]  ip6_finish_output2+0x240/0x710
-[  936.290039]  __ip6_finish_output+0x130/0x170
-[  936.294318]  ip6_output+0x6c/0x1c8
-[  936.297731]  NF_HOOK.constprop.0+0xd8/0xe8
-[  936.301834]  igmp6_send+0x358/0x558
-[  936.305326]  igmp6_join_group.part.0+0x30/0xf0
-[  936.309774]  igmp6_group_added+0xfc/0x110
-[  936.313787]  __ipv6_dev_mc_inc+0x1a4/0x290
-[  936.317885]  ipv6_dev_mc_inc+0x10/0x18
-[  936.321677]  br_multicast_open+0xbc/0x110 [bridge]
-[  936.326506]  br_multicast_toggle+0xec/0x140 [bridge]
-
-Fixes: 4effd28c1245 ("bridge: join all-snoopers multicast address")
-Signed-off-by: Joseph Huang <Joseph.Huang@garmin.com>
-Acked-by: Nikolay Aleksandrov <nikolay@nvidia.com>
-Link: https://lore.kernel.org/r/20201204235628.50653-1-Joseph.Huang@garmin.com
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-[linus.luessing@c0d3.blue: backported to 4.4]
-
-diff --git a/target/linux/generic/backport-4.14/120-bridge-Fix-a-deadlock-when-enabling-multicast-snoopi.patch b/target/linux/generic/backport-4.14/120-bridge-Fix-a-deadlock-when-enabling-multicast-snoopi.patch
-new file mode 100644
-index 0000000000000000000000000000000000000000..e89d9e3eb2063b1f478c0217aaa3c89d14880043
---- /dev/null
-+++ b/target/linux/generic/backport-4.14/120-bridge-Fix-a-deadlock-when-enabling-multicast-snoopi.patch
-@@ -0,0 +1,209 @@
-+From 0e125bd346d3b9d6997e525b263834f6b650cf60 Mon Sep 17 00:00:00 2001
-+From: Joseph Huang <Joseph.Huang@garmin.com>
-+Date: Fri, 4 Dec 2020 18:56:28 -0500
-+Subject: [PATCH] bridge: Fix a deadlock when enabling multicast snooping
-+
-+[ Upstream commit 851d0a73c90e6c8c63fef106c6c1e73df7e05d9d ]
-+
-+When enabling multicast snooping, bridge module deadlocks on multicast_lock
-+if 1) IPv6 is enabled, and 2) there is an existing querier on the same L2
-+network.
-+
-+The deadlock was caused by the following sequence: While holding the lock,
-+br_multicast_open calls br_multicast_join_snoopers, which eventually causes
-+IP stack to (attempt to) send out a Listener Report (in igmp6_join_group).
-+Since the destination Ethernet address is a multicast address, br_dev_xmit
-+feeds the packet back to the bridge via br_multicast_rcv, which in turn
-+calls br_multicast_add_group, which then deadlocks on multicast_lock.
-+
-+The fix is to move the call br_multicast_join_snoopers outside of the
-+critical section. This works since br_multicast_join_snoopers only deals
-+with IP and does not modify any multicast data structures of the bridge,
-+so there's no need to hold the lock.
-+
-+Steps to reproduce:
-+1. sysctl net.ipv6.conf.all.force_mld_version=1
-+2. have another querier
-+3. ip link set dev bridge type bridge mcast_snooping 0 && \
-+   ip link set dev bridge type bridge mcast_snooping 1 < deadlock >
-+
-+A typical call trace looks like the following:
-+
-+[  936.251495]  _raw_spin_lock+0x5c/0x68
-+[  936.255221]  br_multicast_add_group+0x40/0x170 [bridge]
-+[  936.260491]  br_multicast_rcv+0x7ac/0xe30 [bridge]
-+[  936.265322]  br_dev_xmit+0x140/0x368 [bridge]
-+[  936.269689]  dev_hard_start_xmit+0x94/0x158
-+[  936.273876]  __dev_queue_xmit+0x5ac/0x7f8
-+[  936.277890]  dev_queue_xmit+0x10/0x18
-+[  936.281563]  neigh_resolve_output+0xec/0x198
-+[  936.285845]  ip6_finish_output2+0x240/0x710
-+[  936.290039]  __ip6_finish_output+0x130/0x170
-+[  936.294318]  ip6_output+0x6c/0x1c8
-+[  936.297731]  NF_HOOK.constprop.0+0xd8/0xe8
-+[  936.301834]  igmp6_send+0x358/0x558
-+[  936.305326]  igmp6_join_group.part.0+0x30/0xf0
-+[  936.309774]  igmp6_group_added+0xfc/0x110
-+[  936.313787]  __ipv6_dev_mc_inc+0x1a4/0x290
-+[  936.317885]  ipv6_dev_mc_inc+0x10/0x18
-+[  936.321677]  br_multicast_open+0xbc/0x110 [bridge]
-+[  936.326506]  br_multicast_toggle+0xec/0x140 [bridge]
-+
-+Fixes: 4effd28c1245 ("bridge: join all-snoopers multicast address")
-+Signed-off-by: Joseph Huang <Joseph.Huang@garmin.com>
-+Acked-by: Nikolay Aleksandrov <nikolay@nvidia.com>
-+Link: https://lore.kernel.org/r/20201204235628.50653-1-Joseph.Huang@garmin.com
-+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-+[linus.luessing@c0d3.blue: backported to 4.4]
-+---
-+ net/bridge/br_device.c    |  6 ++++++
-+ net/bridge/br_multicast.c | 34 +++++++++++++++++++++++++---------
-+ net/bridge/br_private.h   | 10 ++++++++++
-+ 3 files changed, 41 insertions(+), 9 deletions(-)
-+
-+diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
-+index b7cc322acdc8..4bd8a7ba002a 100644
-+--- a/net/bridge/br_device.c
-++++ b/net/bridge/br_device.c
-+@@ -140,6 +140,9 @@ static int br_dev_open(struct net_device *dev)
-+ 	br_stp_enable_bridge(br);
-+ 	br_multicast_open(br);
-+ 
-++	if (!br->multicast_disabled)
-++		br_multicast_join_snoopers(br);
-++
-+ 	return 0;
-+ }
-+ 
-+@@ -160,6 +163,9 @@ static int br_dev_stop(struct net_device *dev)
-+ 	br_stp_disable_bridge(br);
-+ 	br_multicast_stop(br);
-+ 
-++	if (!br->multicast_disabled)
-++		br_multicast_leave_snoopers(br);
-++
-+ 	netif_stop_queue(dev);
-+ 
-+ 	return 0;
-+diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
-+index 6d8d1cf2ddc6..1b1d06549583 100644
-+--- a/net/bridge/br_multicast.c
-++++ b/net/bridge/br_multicast.c
-+@@ -2314,7 +2314,7 @@ static inline void br_ip6_multicast_join_snoopers(struct net_bridge *br)
-+ }
-+ #endif
-+ 
-+-static void br_multicast_join_snoopers(struct net_bridge *br)
-++void br_multicast_join_snoopers(struct net_bridge *br)
-+ {
-+ 	br_ip4_multicast_join_snoopers(br);
-+ 	br_ip6_multicast_join_snoopers(br);
-+@@ -2345,7 +2345,7 @@ static inline void br_ip6_multicast_leave_snoopers(struct net_bridge *br)
-+ }
-+ #endif
-+ 
-+-static void br_multicast_leave_snoopers(struct net_bridge *br)
-++void br_multicast_leave_snoopers(struct net_bridge *br)
-+ {
-+ 	br_ip4_multicast_leave_snoopers(br);
-+ 	br_ip6_multicast_leave_snoopers(br);
-+@@ -2364,9 +2364,6 @@ static void __br_multicast_open(struct net_bridge *br,
-+ 
-+ void br_multicast_open(struct net_bridge *br)
-+ {
-+-	if (!br->multicast_disabled)
-+-		br_multicast_join_snoopers(br);
-+-
-+ 	__br_multicast_open(br, &br->ip4_own_query);
-+ #if IS_ENABLED(CONFIG_IPV6)
-+ 	__br_multicast_open(br, &br->ip6_own_query);
-+@@ -2382,9 +2379,6 @@ void br_multicast_stop(struct net_bridge *br)
-+ 	del_timer_sync(&br->ip6_other_query.timer);
-+ 	del_timer_sync(&br->ip6_own_query.timer);
-+ #endif
-+-
-+-	if (!br->multicast_disabled)
-+-		br_multicast_leave_snoopers(br);
-+ }
-+ 
-+ void br_multicast_dev_del(struct net_bridge *br)
-+@@ -2540,6 +2534,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
-+ {
-+ 	struct net_bridge_mdb_htable *mdb;
-+ 	struct net_bridge_port *port;
-++	bool change_snoopers = false;
-+ 	int err = 0;
-+ 
-+ 	spin_lock_bh(&br->multicast_lock);
-+@@ -2549,7 +2544,7 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
-+ 	br_mc_disabled_update(br->dev, !val);
-+ 	br->multicast_disabled = !val;
-+ 	if (br->multicast_disabled) {
-+-		br_multicast_leave_snoopers(br);
-++		change_snoopers = true;
-+ 		goto unlock;
-+ 	}
-+ 
-+@@ -2575,9 +2570,30 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
-+ 	list_for_each_entry(port, &br->port_list, list)
-+ 		__br_multicast_enable_port(port);
-+ 
-++	change_snoopers = true;
-++
-+ unlock:
-+ 	spin_unlock_bh(&br->multicast_lock);
-+ 
-++	/* br_multicast_join_snoopers has the potential to cause
-++	 * an MLD Report/Leave to be delivered to br_multicast_rcv,
-++	 * which would in turn call br_multicast_add_group, which would
-++	 * attempt to acquire multicast_lock. This function should be
-++	 * called after the lock has been released to avoid deadlocks on
-++	 * multicast_lock.
-++	 *
-++	 * br_multicast_leave_snoopers does not have the problem since
-++	 * br_multicast_rcv first checks BROPT_MULTICAST_ENABLED, and
-++	 * returns without calling br_multicast_ipv4/6_rcv if it's not
-++	 * enabled. Moved both functions out just for symmetry.
-++	 */
-++	if (change_snoopers) {
-++		if (!br->multicast_disabled)
-++			br_multicast_join_snoopers(br);
-++		else
-++			br_multicast_leave_snoopers(br);
-++	}
-++
-+ 	return err;
-+ }
-+ 
-+diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
-+index bbf7513c1d16..cb701c31199d 100644
-+--- a/net/bridge/br_private.h
-++++ b/net/bridge/br_private.h
-+@@ -611,6 +611,8 @@ void br_multicast_del_port(struct net_bridge_port *port);
-+ void br_multicast_enable_port(struct net_bridge_port *port);
-+ void br_multicast_disable_port(struct net_bridge_port *port);
-+ void br_multicast_init(struct net_bridge *br);
-++void br_multicast_join_snoopers(struct net_bridge *br);
-++void br_multicast_leave_snoopers(struct net_bridge *br);
-+ void br_multicast_open(struct net_bridge *br);
-+ void br_multicast_stop(struct net_bridge *br);
-+ void br_multicast_dev_del(struct net_bridge *br);
-+@@ -736,6 +738,14 @@ static inline void br_multicast_init(struct net_bridge *br)
-+ {
-+ }
-+ 
-++static inline void br_multicast_join_snoopers(struct net_bridge *br)
-++{
-++}
-++
-++static inline void br_multicast_leave_snoopers(struct net_bridge *br)
-++{
-++}
-++
-+ static inline void br_multicast_open(struct net_bridge *br)
-+ {
-+ }
-+-- 
-+2.29.2
-+
diff --git a/patches/packages/packages/0001-fastd-update-to-v19.patch b/patches/packages/packages/0001-fastd-update-to-v19.patch
deleted file mode 100644
index 8f35f4780c12ce4f801fd6acb32e1388f836f94b..0000000000000000000000000000000000000000
--- a/patches/packages/packages/0001-fastd-update-to-v19.patch
+++ /dev/null
@@ -1,164 +0,0 @@
-From: Matthias Schiffer <mschiffer@universe-factory.net>
-Date: Fri, 22 May 2020 21:09:21 +0200
-Subject: fastd: update to v19
-
-Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
-
-diff --git a/net/fastd/Config.in b/net/fastd/Config.in
-index 3350eb3099a26c870d70373c0712a8b59881ee5c..e6440075e561093c86543943cb982d010a4ef0e0 100644
---- a/net/fastd/Config.in
-+++ b/net/fastd/Config.in
-@@ -36,16 +36,6 @@ config FASTD_ENABLE_METHOD_NULL
- 	depends on PACKAGE_fastd
- 	default y
- 
--config FASTD_ENABLE_METHOD_XSALSA20_POLY1305
--	bool "Enable xsalsa20-poly1305 method"
--	depends on PACKAGE_fastd
--	default n
--
--
--config FASTD_ENABLE_CIPHER_AES128_CTR
--	bool "Enable the AES128-CTR cipher"
--	depends on PACKAGE_fastd
--	default n
- 
- config FASTD_ENABLE_CIPHER_NULL
- 	bool "Enable the null cipher"
-diff --git a/net/fastd/Makefile b/net/fastd/Makefile
-index f4890b56931a75849229d25fe78720e19d493383..7483e7b003041fb59991d72d0ccfcc8a28bb17a3 100644
---- a/net/fastd/Makefile
-+++ b/net/fastd/Makefile
-@@ -8,13 +8,13 @@
- include $(TOPDIR)/rules.mk
- 
- PKG_NAME:=fastd
--PKG_VERSION:=18
--PKG_RELEASE:=5
-+PKG_VERSION:=19
-+PKG_RELEASE:=2
- 
- PKG_MAINTAINER:=Matthias Schiffer <mschiffer@universe-factory.net>
- PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
- PKG_SOURCE_URL:=https://github.com/NeoRaider/fastd/releases/download/v$(PKG_VERSION)
--PKG_HASH:=714ff09d7bd75f79783f744f6f8c5af2fe456c8cf876feaa704c205a73e043c9
-+PKG_HASH:=6054608e2103b634c9d19ecd1ae058d4ec694747047130719db180578729783a
- 
- PKG_LICENSE:=BSD-2-Clause
- PKG_LICENSE_FILES:=COPYRIGHT
-@@ -27,8 +27,6 @@ PKG_CONFIG_DEPENDS:=\
- 	CONFIG_FASTD_ENABLE_METHOD_GENERIC_POLY1305 \
- 	CONFIG_FASTD_ENABLE_METHOD_GENERIC_UMAC \
- 	CONFIG_FASTD_ENABLE_METHOD_NULL \
--	CONFIG_FASTD_ENABLE_METHOD_XSALSA20_POLY1305 \
--	CONFIG_FASTD_ENABLE_CIPHER_AES128_CTR \
- 	CONFIG_FASTD_ENABLE_CIPHER_NULL \
- 	CONFIG_FASTD_ENABLE_CIPHER_SALSA20 \
- 	CONFIG_FASTD_ENABLE_CIPHER_SALSA2012 \
-@@ -44,6 +42,7 @@ PKG_CONFIG_DEPENDS:=\
- 
- 
- PKG_BUILD_DEPENDS:=nacl
-+PKG_BUILD_PARALLEL:=1
- 
- include $(INCLUDE_DIR)/package.mk
- include $(INCLUDE_DIR)/cmake.mk
-@@ -73,7 +72,6 @@ CMAKE_OPTIONS += \
- 	-DWITH_METHOD_GENERIC_POLY1305:BOOL=FALSE \
- 	-DWITH_METHOD_GENERIC_UMAC:BOOL=FALSE \
- 	-DWITH_METHOD_NULL:BOOL=FALSE \
--	-DWITH_METHOD_XSALSA20_POLY1305:BOOL=FALSE \
- 	-DWITH_CIPHER_AES128_CTR:BOOL=FALSE \
- 	-DWITH_CIPHER_NULL:BOOL=FALSE \
- 	-DWITH_CIPHER_SALSA20:BOOL=FALSE \
-@@ -120,14 +118,6 @@ ifeq ($(CONFIG_FASTD_ENABLE_METHOD_NULL),y)
- CMAKE_OPTIONS += -DWITH_METHOD_NULL:BOOL=TRUE
- endif
- 
--ifeq ($(CONFIG_FASTD_ENABLE_METHOD_XSALSA20_POLY1305),y)
--CMAKE_OPTIONS += -DWITH_METHOD_XSALSA20_POLY1305:BOOL=TRUE
--endif
--
--
--ifeq ($(CONFIG_FASTD_ENABLE_CIPHER_AES128_CTR),y)
--CMAKE_OPTIONS += -DWITH_CIPHER_AES128_CTR:BOOL=TRUE
--endif
- 
- ifeq ($(CONFIG_FASTD_ENABLE_CIPHER_NULL),y)
- CMAKE_OPTIONS += -DWITH_CIPHER_NULL:BOOL=TRUE
-diff --git a/net/fastd/patches/0001-resolve-fix-segmentation-fault-with-musl-1.1.20.patch b/net/fastd/patches/0001-resolve-fix-segmentation-fault-with-musl-1.1.20.patch
-deleted file mode 100644
-index 52c19174083c29e5da02cabb2ddc02474cf11b37..0000000000000000000000000000000000000000
---- a/net/fastd/patches/0001-resolve-fix-segmentation-fault-with-musl-1.1.20.patch
-+++ /dev/null
-@@ -1,35 +0,0 @@
--From 9710132c04cd378bd36f16a2a3d98d9c4c5fdbac Mon Sep 17 00:00:00 2001
--From: David Bauer <mail@david-bauer.net>
--Date: Thu, 25 Jul 2019 18:51:25 +0200
--Subject: [PATCH] resolve: fix segmentation fault with musl >1.1.20
--
--When compiled with musl >1.1.20, fastd will crash in case it can't
--resolve a peers hostname. This is due to a changed implementation of
--freeaddrinfo in musl 1.1.21 onwards.
--
--This segfault is fixed by not calling freeaddrinfo in case the supplied
--pointer is null.
--
--Signed-off-by: David Bauer <mail@david-bauer.net>
-----
-- src/resolve.c | 4 +++-
-- 1 file changed, 3 insertions(+), 1 deletion(-)
--
--diff --git a/src/resolve.c b/src/resolve.c
--index 9bdfa1c..bfd2a59 100644
----- a/src/resolve.c
--+++ b/src/resolve.c
--@@ -104,7 +104,9 @@ static void * resolve_peer(void *varg) {
-- 
-- 	fastd_async_enqueue(ASYNC_TYPE_RESOLVE_RETURN, ret, sizeof(fastd_async_resolve_return_t) + n_addr*sizeof(fastd_peer_address_t));
-- 
---	freeaddrinfo(res);
--+	if (res)
--+		freeaddrinfo(res);
--+
-- 	free(arg->hostname);
-- 	free(arg);
-- 
---- 
--2.20.1
--
-diff --git a/net/fastd/patches/0002-doc-examples-openwrt-fix-init-script-wasn-t-working-.patch b/net/fastd/patches/0002-doc-examples-openwrt-fix-init-script-wasn-t-working-.patch
-deleted file mode 100644
-index b576a987369e93f3cd14fbc83f3c4bffe5cc97d1..0000000000000000000000000000000000000000
---- a/net/fastd/patches/0002-doc-examples-openwrt-fix-init-script-wasn-t-working-.patch
-+++ /dev/null
-@@ -1,29 +0,0 @@
--From c29b4b0e3cc5bf68129fd0f94f424950b7888deb Mon Sep 17 00:00:00 2001
--Message-Id: <c29b4b0e3cc5bf68129fd0f94f424950b7888deb.1567630068.git.mschiffer@universe-factory.net>
--From: Wilfried Klaebe <wklaebe@users.noreply.github.com>
--Date: Sat, 31 Aug 2019 21:44:13 +0200
--Subject: [PATCH] doc: examples/openwrt: fix init script, wasn't working with
-- two VPNs
--
--If two VPNs were configured via uci, the init script complained about
--the peer group of its peers not matching its net.
-----
-- doc/examples/openwrt/fastd.init | 2 +-
-- 1 file changed, 1 insertion(+), 1 deletion(-)
--
--diff --git a/doc/examples/openwrt/fastd.init b/doc/examples/openwrt/fastd.init
--index 15737b403ec2..4ba69ece9887 100644
----- a/doc/examples/openwrt/fastd.init
--+++ b/doc/examples/openwrt/fastd.init
--@@ -233,7 +233,7 @@ generate_peer_group_config() {
-- 	config_get group_parent "$group" parent
-- 	[ "$parent" = "$group_parent" ] || return 0
-- 
---	if [ "$net" != "$peer_net" ]; then
--+	if [ "$net" != "$group_net" ]; then
-- 		[ -z "$parent" ] || error "warning: the parent of peer group '$group' doesn't match its net, the peer group will be ignored"
-- 		return 0
-- 	fi
---- 
--2.23.0
--
diff --git a/patches/packages/packages/0002-fastd-update-to-v21.patch b/patches/packages/packages/0002-fastd-update-to-v21.patch
deleted file mode 100644
index 1d7fb9d75c8cd6e78d670deee3c09a502c829e4f..0000000000000000000000000000000000000000
--- a/patches/packages/packages/0002-fastd-update-to-v21.patch
+++ /dev/null
@@ -1,265 +0,0 @@
-From: Matthias Schiffer <mschiffer@universe-factory.net>
-Date: Sat, 10 Oct 2020 19:02:24 +0200
-Subject: fastd: update to v21
-
-Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
-
-diff --git a/net/fastd/Config.in b/net/fastd/Config.in
-index e6440075e561093c86543943cb982d010a4ef0e0..8302f7ee4dac874b1303ebeeb836551ef202c261 100644
---- a/net/fastd/Config.in
-+++ b/net/fastd/Config.in
-@@ -69,7 +69,6 @@ config FASTD_WITH_CAPABILITIES
- 	depends on PACKAGE_fastd
- 	default n
- 
--
- config FASTD_WITH_CMDLINE_USER
- 	bool "Include support for setting user/group related options on the command line"
- 	depends on PACKAGE_fastd
-@@ -91,7 +90,7 @@ config FASTD_WITH_CMDLINE_COMMANDS
- 	default n
- 
- config FASTD_WITH_DYNAMIC_PEERS
--	bool "Include support for on-verify handlers"
-+	bool "Include support for dynamic peers (using on-verify handlers)"
- 	depends on PACKAGE_fastd
- 	default n
- 
-@@ -100,5 +99,4 @@ config FASTD_WITH_STATUS_SOCKET
- 	depends on PACKAGE_fastd
- 	default y
- 
--
- endmenu
-diff --git a/net/fastd/Makefile b/net/fastd/Makefile
-index 7483e7b003041fb59991d72d0ccfcc8a28bb17a3..c7ab056a9ae005a75a75911658607e64d6228aac 100644
---- a/net/fastd/Makefile
-+++ b/net/fastd/Makefile
-@@ -8,13 +8,12 @@
- include $(TOPDIR)/rules.mk
- 
- PKG_NAME:=fastd
--PKG_VERSION:=19
--PKG_RELEASE:=2
-+PKG_VERSION:=21
- 
- PKG_MAINTAINER:=Matthias Schiffer <mschiffer@universe-factory.net>
- PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
- PKG_SOURCE_URL:=https://github.com/NeoRaider/fastd/releases/download/v$(PKG_VERSION)
--PKG_HASH:=6054608e2103b634c9d19ecd1ae058d4ec694747047130719db180578729783a
-+PKG_HASH:=942f33bcd794bcb8e19da4c30c875bdfd4d0f1c24ec4dcdf51237791bbfb0d4c
- 
- PKG_LICENSE:=BSD-2-Clause
- PKG_LICENSE_FILES:=COPYRIGHT
-@@ -41,16 +40,16 @@ PKG_CONFIG_DEPENDS:=\
- 	CONFIG_FASTD_WITH_STATUS_SOCKET
- 
- 
--PKG_BUILD_DEPENDS:=nacl
-+PKG_BUILD_DEPENDS:=meson/host nacl
- PKG_BUILD_PARALLEL:=1
- 
- include $(INCLUDE_DIR)/package.mk
--include $(INCLUDE_DIR)/cmake.mk
-+include ../../devel/meson/meson.mk
- 
- define Package/fastd
-   SECTION:=net
-   CATEGORY:=Network
--  DEPENDS:=+kmod-tun +librt +libpthread +libuecc +FASTD_WITH_STATUS_SOCKET:libjson-c +FASTD_WITH_CAPABILITIES:libcap
-+  DEPENDS:=+kmod-tun +libpthread +libuecc +FASTD_WITH_STATUS_SOCKET:libjson-c +FASTD_WITH_CAPABILITIES:libcap
-   TITLE:=Fast and Secure Tunneling Daemon
-   URL:=https://github.com/NeoRaider/fastd/
-   SUBMENU:=VPN
-@@ -60,116 +59,33 @@ define Package/fastd/config
-   source "$(SOURCE)/Config.in"
- endef
- 
--TARGET_CFLAGS += -ffunction-sections -fdata-sections
--TARGET_LDFLAGS += -Wl,--gc-sections
--
--CMAKE_OPTIONS += \
--	-DCMAKE_BUILD_TYPE:STRING=MINSIZEREL \
--	-DWITH_METHOD_CIPHER_TEST:BOOL=FALSE \
--	-DWITH_METHOD_COMPOSED_GMAC:BOOL=FALSE \
--	-DWITH_METHOD_COMPOSED_UMAC:BOOL=FALSE \
--	-DWITH_METHOD_GENERIC_GMAC:BOOL=FALSE \
--	-DWITH_METHOD_GENERIC_POLY1305:BOOL=FALSE \
--	-DWITH_METHOD_GENERIC_UMAC:BOOL=FALSE \
--	-DWITH_METHOD_NULL:BOOL=FALSE \
--	-DWITH_CIPHER_AES128_CTR:BOOL=FALSE \
--	-DWITH_CIPHER_NULL:BOOL=FALSE \
--	-DWITH_CIPHER_SALSA20:BOOL=FALSE \
--	-DWITH_CIPHER_SALSA2012:BOOL=FALSE \
--	-DWITH_MAC_GHASH:BOOL=FALSE \
--	-DWITH_MAC_UHASH:BOOL=FALSE \
--	-DWITH_CAPABILITIES:BOOL=FALSE \
--	-DWITH_CMDLINE_USER:BOOL=FALSE \
--	-DWITH_CMDLINE_LOGGING:BOOL=FALSE \
--	-DWITH_CMDLINE_OPERATION:BOOL=FALSE \
--	-DWITH_CMDLINE_COMMANDS:BOOL=FALSE \
--	-DWITH_DYNAMIC_PEERS:BOOL=FALSE \
--	-DWITH_STATUS_SOCKET:BOOL=FALSE \
--	-DENABLE_SYSTEMD:BOOL=FALSE \
--	-DENABLE_LIBSODIUM:BOOL=FALSE \
--	-DENABLE_LTO:BOOL=TRUE
--
--
--ifeq ($(CONFIG_FASTD_ENABLE_METHOD_CIPHER_TEST),y)
--CMAKE_OPTIONS += -DWITH_METHOD_CIPHER_TEST:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_ENABLE_METHOD_COMPOSED_GMAC),y)
--CMAKE_OPTIONS += -DWITH_METHOD_COMPOSED_GMAC:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_ENABLE_METHOD_COMPOSED_UMAC),y)
--CMAKE_OPTIONS += -DWITH_METHOD_COMPOSED_UMAC:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_ENABLE_METHOD_GENERIC_GMAC),y)
--CMAKE_OPTIONS += -DWITH_METHOD_GENERIC_GMAC:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_ENABLE_METHOD_GENERIC_POLY1305),y)
--CMAKE_OPTIONS += -DWITH_METHOD_GENERIC_POLY1305:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_ENABLE_METHOD_GENERIC_UMAC),y)
--CMAKE_OPTIONS += -DWITH_METHOD_GENERIC_UMAC:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_ENABLE_METHOD_NULL),y)
--CMAKE_OPTIONS += -DWITH_METHOD_NULL:BOOL=TRUE
--endif
--
--
--ifeq ($(CONFIG_FASTD_ENABLE_CIPHER_NULL),y)
--CMAKE_OPTIONS += -DWITH_CIPHER_NULL:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_ENABLE_CIPHER_SALSA20),y)
--CMAKE_OPTIONS += -DWITH_CIPHER_SALSA20:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_ENABLE_CIPHER_SALSA2012),y)
--CMAKE_OPTIONS += -DWITH_CIPHER_SALSA2012:BOOL=TRUE
--endif
--
--
--ifeq ($(CONFIG_FASTD_ENABLE_MAC_GHASH),y)
--CMAKE_OPTIONS += -DWITH_MAC_GHASH:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_ENABLE_MAC_UHASH),y)
--CMAKE_OPTIONS += -DWITH_MAC_UHASH:BOOL=TRUE
--endif
--
--
--ifeq ($(CONFIG_FASTD_WITH_CAPABILITIES),y)
--CMAKE_OPTIONS += -DWITH_CAPABILITIES:BOOL=TRUE
--endif
--
--
--ifeq ($(CONFIG_FASTD_WITH_CMDLINE_USER),y)
--CMAKE_OPTIONS += -DWITH_CMDLINE_USER:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_WITH_CMDLINE_LOGGING),y)
--CMAKE_OPTIONS += -DWITH_CMDLINE_LOGGING:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_WITH_CMDLINE_OPERATION),y)
--CMAKE_OPTIONS += -DWITH_CMDLINE_OPERATION:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_WITH_CMDLINE_COMMANDS),y)
--CMAKE_OPTIONS += -DWITH_CMDLINE_COMMANDS:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_WITH_DYNAMIC_PEERS),y)
--CMAKE_OPTIONS += -DWITH_DYNAMIC_PEERS:BOOL=TRUE
--endif
--
--ifeq ($(CONFIG_FASTD_WITH_STATUS_SOCKET),y)
--CMAKE_OPTIONS += -DWITH_STATUS_SOCKET:BOOL=TRUE
--endif
--
-+feature = $(if $(CONFIG_FASTD_$(1)),enabled,disabled)
-+
-+MESON_ARGS += \
-+	-Dcapabilities=$(call feature,WITH_CAPABILITIES) \
-+	-Dcipher_aes128-ctr=disabled \
-+	-Dcipher_null=$(call feature,ENABLE_CIPHER_NULL) \
-+	-Dcipher_salsa20=$(call feature,ENABLE_CIPHER_SALSA20) \
-+	-Dcipher_salsa2012=$(call feature,ENABLE_CIPHER_SALSA2012) \
-+	-Dcmdline_commands=$(call feature,WITH_CMDLINE_COMMANDS) \
-+	-Dcmdline_logging=$(call feature,WITH_CMDLINE_LOGGING) \
-+	-Dcmdline_operation=$(call feature,WITH_CMDLINE_OPERATION) \
-+	-Dcmdline_user=$(call feature,WITH_CMDLINE_USER) \
-+	-Ddynamic_peers=$(call feature,WITH_DYNAMIC_PEERS) \
-+	-Dmac_ghash=$(call feature,ENABLE_MAC_GHASH) \
-+	-Dmac_uhash=$(call feature,ENABLE_MAC_UHASH) \
-+	-Dmethod_cipher-test=$(call feature,ENABLE_METHOD_CIPHER_TEST) \
-+	-Dmethod_composed-gmac=$(call feature,ENABLE_METHOD_COMPOSED_GMAC) \
-+	-Dmethod_composed-umac=$(call feature,ENABLE_METHOD_COMPOSED_UMAC) \
-+	-Dmethod_generic-gmac=$(call feature,ENABLE_METHOD_GENERIC_GMAC) \
-+	-Dmethod_generic-poly1305=$(call feature,ENABLE_METHOD_GENERIC_POLY1305) \
-+	-Dmethod_generic-umac=$(call feature,ENABLE_METHOD_GENERIC_UMAC) \
-+	-Dmethod_null=$(call feature,ENABLE_METHOD_NULL) \
-+	-Dstatus_socket=$(call feature,WITH_STATUS_SOCKET) \
-+	-Dsystemd=disabled \
-+	-Duse_nacl=true \
-+	-Db_lto=true \
-+	-Dprefix=/usr
- 
- define Package/fastd/description
-  Fast and secure tunneling daemon, which is optimized on small code size and few dependencies
-diff --git a/net/fastd/patches/0003-receive-fix-buffer-leak-when-receiving-invalid-packe.patch b/net/fastd/patches/0003-receive-fix-buffer-leak-when-receiving-invalid-packe.patch
-deleted file mode 100644
-index b67a85c4e4f8ca1ef72d3216afa1ad4e9370cd02..0000000000000000000000000000000000000000
---- a/net/fastd/patches/0003-receive-fix-buffer-leak-when-receiving-invalid-packe.patch
-+++ /dev/null
-@@ -1,42 +0,0 @@
--From f6a2651fa91c472d04cb34264718f761669c8aa1 Mon Sep 17 00:00:00 2001
--Message-Id: <f6a2651fa91c472d04cb34264718f761669c8aa1.1603136280.git.mschiffer@universe-factory.net>
--From: Matthias Schiffer <mschiffer@universe-factory.net>
--Date: Mon, 19 Oct 2020 21:08:16 +0200
--Subject: [PATCH] receive: fix buffer leak when receiving invalid packets
--
--For fastd versions before v20, this was just a memory leak (which could
--still be used for DoS, as it's remotely triggerable). With the new
--buffer management of fastd v20, this will trigger an assertion failure
--instead as soon as the buffer pool is empty.
--
--(cherry picked from commit 737925113363b6130879729cdff9ccc46c33eaea)
-----
-- src/receive.c | 10 ++++++++++
-- 1 file changed, 10 insertions(+)
--
----- a/src/receive.c
--+++ b/src/receive.c
--@@ -186,6 +186,11 @@ static inline void handle_socket_receive
-- 
-- 	case PACKET_HANDSHAKE:
-- 		fastd_handshake_handle(sock, local_addr, remote_addr, peer, buffer);
--+		break;
--+
--+	default:
--+		fastd_buffer_free(buffer);
--+		pr_debug("received packet with invalid type from %P[%I]", peer, remote_addr);
-- 	}
-- }
-- 
--@@ -211,6 +216,11 @@ static inline void handle_socket_receive
-- 
-- 	case PACKET_HANDSHAKE:
-- 		fastd_handshake_handle(sock, local_addr, remote_addr, NULL, buffer);
--+		break;
--+
--+	default:
--+		fastd_buffer_free(buffer);
--+		pr_debug("received packet with invalid type from unknown address %I", remote_addr);
-- 	}
-- }
-- 
diff --git a/patches/packages/routing/0003-batman-adv-Introduce-no-noflood-mark.patch b/patches/packages/routing/0002-batman-adv-Introduce-no-noflood-mark.patch
similarity index 83%
rename from patches/packages/routing/0003-batman-adv-Introduce-no-noflood-mark.patch
rename to patches/packages/routing/0002-batman-adv-Introduce-no-noflood-mark.patch
index c6f13e63587e1e952d75d8164baedb5f3e9cee5f..60a56752cee416c30a5a5f5b624fa3eda05ccc68 100644
--- a/patches/packages/routing/0003-batman-adv-Introduce-no-noflood-mark.patch
+++ b/patches/packages/routing/0002-batman-adv-Introduce-no-noflood-mark.patch
@@ -14,10 +14,10 @@ Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
 
 diff --git a/batman-adv/patches/0034-batman-adv-Introduce-no-noflood-mark.patch b/batman-adv/patches/0034-batman-adv-Introduce-no-noflood-mark.patch
 new file mode 100644
-index 0000000000000000000000000000000000000000..2ccb6da270acf41e56f9a37801e23301e592b112
+index 0000000000000000000000000000000000000000..8dbde75343f04fb3a643e300856ecfac7dc23e32
 --- /dev/null
 +++ b/batman-adv/patches/0034-batman-adv-Introduce-no-noflood-mark.patch
-@@ -0,0 +1,167 @@
+@@ -0,0 +1,156 @@
 +From 25b21382238c783298c0d8defc8c739126c1b54d Mon Sep 17 00:00:00 2001
 +From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@c0d3.blue>
 +Date: Sat, 31 Mar 2018 03:36:19 +0200
@@ -51,11 +51,9 @@ index 0000000000000000000000000000000000000000..2ccb6da270acf41e56f9a37801e23301
 + net/batman-adv/types.h          | 12 ++++++++++++
 + 4 files changed, 66 insertions(+)
 +
-+diff --git a/include/uapi/linux/batman_adv.h b/include/uapi/linux/batman_adv.h
-+index 67f46367..6fabb7aa 100644
 +--- a/include/uapi/linux/batman_adv.h
 ++++ b/include/uapi/linux/batman_adv.h
-+@@ -480,6 +480,18 @@ enum batadv_nl_attrs {
++@@ -481,6 +481,18 @@ enum batadv_nl_attrs {
 + 	 */
 + 	BATADV_ATTR_MULTICAST_FANOUT,
 + 
@@ -74,11 +72,9 @@ index 0000000000000000000000000000000000000000..2ccb6da270acf41e56f9a37801e23301
 + 	/* add attributes above here, update the policy in netlink.c */
 + 
 + 	/**
-+diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
-+index e1978bc5..3d2c147a 100644
 +--- a/net/batman-adv/netlink.c
 ++++ b/net/batman-adv/netlink.c
-+@@ -134,6 +134,8 @@ static const struct nla_policy batadv_netlink_policy[NUM_BATADV_ATTR] = {
++@@ -134,6 +134,8 @@ static const struct nla_policy batadv_ne
 + 	[BATADV_ATTR_AP_ISOLATION_ENABLED]	= { .type = NLA_U8 },
 + 	[BATADV_ATTR_ISOLATION_MARK]		= { .type = NLA_U32 },
 + 	[BATADV_ATTR_ISOLATION_MASK]		= { .type = NLA_U32 },
@@ -87,7 +83,7 @@ index 0000000000000000000000000000000000000000..2ccb6da270acf41e56f9a37801e23301
 + 	[BATADV_ATTR_BONDING_ENABLED]		= { .type = NLA_U8 },
 + 	[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED]	= { .type = NLA_U8 },
 + 	[BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED]	= { .type = NLA_U8 },
-+@@ -286,6 +288,14 @@ static int batadv_netlink_mesh_fill(struct sk_buff *msg,
++@@ -286,6 +288,14 @@ static int batadv_netlink_mesh_fill(stru
 + 			bat_priv->isolation_mark_mask))
 + 		goto nla_put_failure;
 + 
@@ -102,7 +98,7 @@ index 0000000000000000000000000000000000000000..2ccb6da270acf41e56f9a37801e23301
 + 	if (nla_put_u8(msg, BATADV_ATTR_BONDING_ENABLED,
 + 		       !!atomic_read(&bat_priv->bonding)))
 + 		goto nla_put_failure;
-+@@ -466,6 +476,18 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info)
++@@ -466,6 +476,18 @@ static int batadv_netlink_set_mesh(struc
 + 		bat_priv->isolation_mark_mask = nla_get_u32(attr);
 + 	}
 + 
@@ -121,11 +117,9 @@ index 0000000000000000000000000000000000000000..2ccb6da270acf41e56f9a37801e23301
 + 	if (info->attrs[BATADV_ATTR_BONDING_ENABLED]) {
 + 		attr = info->attrs[BATADV_ATTR_BONDING_ENABLED];
 + 
-+diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
-+index c99facdb..4e71b9f3 100644
 +--- a/net/batman-adv/soft-interface.c
 ++++ b/net/batman-adv/soft-interface.c
-+@@ -176,6 +176,23 @@ static void batadv_interface_set_rx_mode(struct net_device *dev)
++@@ -175,6 +175,23 @@ static void batadv_interface_set_rx_mode
 + {
 + }
 + 
@@ -149,7 +143,7 @@ index 0000000000000000000000000000000000000000..2ccb6da270acf41e56f9a37801e23301
 + static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
 + 				       struct net_device *soft_iface)
 + {
-+@@ -326,6 +343,9 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
++@@ -325,6 +342,9 @@ send:
 + 		if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb))
 + 			brd_delay = msecs_to_jiffies(ARP_REQ_DELAY);
 + 
@@ -159,11 +153,9 @@ index 0000000000000000000000000000000000000000..2ccb6da270acf41e56f9a37801e23301
 + 		if (batadv_skb_head_push(skb, sizeof(*bcast_packet)) < 0)
 + 			goto dropped;
 + 
-+diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
-+index c0ded822..09c877fa 100644
 +--- a/net/batman-adv/types.h
 ++++ b/net/batman-adv/types.h
-+@@ -1599,6 +1599,18 @@ struct batadv_priv {
++@@ -1635,6 +1635,18 @@ struct batadv_priv {
 + 	 */
 + 	u32 isolation_mark_mask;
 + 
@@ -182,6 +174,3 @@ index 0000000000000000000000000000000000000000..2ccb6da270acf41e56f9a37801e23301
 + 	/** @bcast_seqno: last sent broadcast packet sequence number */
 + 	atomic_t bcast_seqno;
 + 
-+-- 
-+2.31.0
-+
diff --git a/patches/packages/routing/0002-batman-adv-compat-remove-ip_mc_check_igmp-ipv6_mc_check_mld.patch b/patches/packages/routing/0002-batman-adv-compat-remove-ip_mc_check_igmp-ipv6_mc_check_mld.patch
deleted file mode 100644
index 1114be8ece4125da04be704db4d0cb81f4d39199..0000000000000000000000000000000000000000
--- a/patches/packages/routing/0002-batman-adv-compat-remove-ip_mc_check_igmp-ipv6_mc_check_mld.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From: Linus Lüssing <linus.luessing@c0d3.blue>
-Date: Sun, 5 Jul 2020 04:02:17 +0200
-Subject: batman-adv: compat: remove ip_mc_check_igmp() + ipv6_mc_check_mld()
-
-The upstream Linux patches which reduced the number of arguments for
-these functions from two to one were added to OpenWrt. Therefore compat
-code for them is no more needed.
-
-Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
-
-diff --git a/batman-adv/src/compat-hacks.h b/batman-adv/src/compat-hacks.h
-index d8de483a10243c77b2c5f49720a39dedb1404f01..1cbcfcf070c7dd943574612c0d13f886c88ecc25 100644
---- a/batman-adv/src/compat-hacks.h
-+++ b/batman-adv/src/compat-hacks.h
-@@ -53,39 +53,12 @@ int ipv6_mc_check_mld(struct sk_buff *skb);
- 
- #elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 1, 0)
- 
-+#undef ip_mc_check_igmp
-+#undef ipv6_mc_check_mld
-+
- #include_next <linux/igmp.h>
- #include_next <net/addrconf.h>
- 
--static inline int batadv_ipv6_mc_check_mld1(struct sk_buff *skb)
--{
--	return ipv6_mc_check_mld(skb, NULL);
--}
--
--static inline int batadv_ipv6_mc_check_mld2(struct sk_buff *skb,
--					    struct sk_buff **skb_trimmed)
--{
--	return ipv6_mc_check_mld(skb, skb_trimmed);
--}
--
--#define ipv6_mc_check_mld_get(_1, _2, ipv6_mc_check_mld_name, ...) ipv6_mc_check_mld_name
--#define ipv6_mc_check_mld(...) \
--	ipv6_mc_check_mld_get(__VA_ARGS__, batadv_ipv6_mc_check_mld2, batadv_ipv6_mc_check_mld1)(__VA_ARGS__)
--
--static inline int batadv_ip_mc_check_igmp1(struct sk_buff *skb)
--{
--	return ip_mc_check_igmp(skb, NULL);
--}
--
--static inline int batadv_ip_mc_check_igmp2(struct sk_buff *skb,
--					   struct sk_buff **skb_trimmed)
--{
--	return ip_mc_check_igmp(skb, skb_trimmed);
--}
--
--#define ip_mc_check_igmp_get(_1, _2, ip_mc_check_igmp_name, ...) ip_mc_check_igmp_name
--#define ip_mc_check_igmp(...) \
--	ip_mc_check_igmp_get(__VA_ARGS__, batadv_ip_mc_check_igmp2, batadv_ip_mc_check_igmp1)(__VA_ARGS__)
--
- #endif /* < KERNEL_VERSION(4, 2, 0) */
- 
- #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0)
diff --git a/patches/packages/routing/0004-batctl-Add-noflood_mark-command.patch b/patches/packages/routing/0003-batctl-Add-noflood_mark-command.patch
similarity index 72%
rename from patches/packages/routing/0004-batctl-Add-noflood_mark-command.patch
rename to patches/packages/routing/0003-batctl-Add-noflood_mark-command.patch
index 83a4afc927b66f9de45d560aef98be079dd30506..6659bc3193d7db1e1e74bf817ab38fe9c26efd1d 100644
--- a/patches/packages/routing/0004-batctl-Add-noflood_mark-command.patch
+++ b/patches/packages/routing/0003-batctl-Add-noflood_mark-command.patch
@@ -8,10 +8,10 @@ Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
 
 diff --git a/batctl/patches/0012-batctl-Add-noflood_mark-command.patch b/batctl/patches/0012-batctl-Add-noflood_mark-command.patch
 new file mode 100644
-index 0000000000000000000000000000000000000000..296f3c51b79333a8e96c340d151ba00b8f457120
+index 0000000000000000000000000000000000000000..1234c56cc0be080de8142f3a563cf4e070c4840a
 --- /dev/null
 +++ b/batctl/patches/0012-batctl-Add-noflood_mark-command.patch
-@@ -0,0 +1,273 @@
+@@ -0,0 +1,226 @@
 +From c14abebbeb4af76600cd6eb508e5e4e38a436b2f Mon Sep 17 00:00:00 2001
 +From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@c0d3.blue>
 +Date: Fri, 26 Apr 2019 19:27:38 +0200
@@ -40,24 +40,20 @@ index 0000000000000000000000000000000000000000..296f3c51b79333a8e96c340d151ba00b
 + 5 files changed, 192 insertions(+)
 + create mode 100644 noflood_mark.c
 +
-+diff --git a/Makefile b/Makefile
-+index e3747a2..686de7e 100755
 +--- a/Makefile
 ++++ b/Makefile
-+@@ -61,6 +61,7 @@ $(eval $(call add_command,multicast_mode,y))
-+ $(eval $(call add_command,nc_nodes,y))
++@@ -69,6 +69,7 @@ $(eval $(call add_command,multicast_mode
 + $(eval $(call add_command,neighbors,y))
++ $(eval $(call add_command,neighbors_json,y))
 + $(eval $(call add_command,network_coding,y))
 ++$(eval $(call add_command,noflood_mark,y))
 + $(eval $(call add_command,orig_interval,y))
 + $(eval $(call add_command,originators,y))
-+ $(eval $(call add_command,ping,y))
-+diff --git a/README.rst b/README.rst
-+index 128f539..bc937d2 100644
++ $(eval $(call add_command,originators_json,y))
 +--- a/README.rst
 ++++ b/README.rst
-+@@ -582,6 +582,21 @@ Usage::
-+ * Example 4: ``batctl mark 0x0f``
++@@ -419,6 +419,21 @@ Example::
++ 
 + 
 + 
 ++batctl noflood_mark
@@ -76,13 +72,11 @@ index 0000000000000000000000000000000000000000..296f3c51b79333a8e96c340d151ba00b
 ++
 ++
 + batctl translocal
-+ =================
++ -----------------
 + 
-+diff --git a/batman_adv.h b/batman_adv.h
-+index 67f4636..6fabb7a 100644
 +--- a/batman_adv.h
 ++++ b/batman_adv.h
-+@@ -480,6 +480,18 @@ enum batadv_nl_attrs {
++@@ -481,6 +481,18 @@ enum batadv_nl_attrs {
 + 	 */
 + 	BATADV_ATTR_MULTICAST_FANOUT,
 + 
@@ -101,46 +95,9 @@ index 0000000000000000000000000000000000000000..296f3c51b79333a8e96c340d151ba00b
 + 	/* add attributes above here, update the policy in netlink.c */
 + 
 + 	/**
-+diff --git a/man/batctl.8 b/man/batctl.8
-+index d42b682..5489c2e 100644
-+--- a/man/batctl.8
-++++ b/man/batctl.8
-+@@ -124,6 +124,29 @@ If no parameter is given the current multicast fanout setting is displayed. Othe
-+ the multicast fanout. The multicast fanout defines the maximum number of packet copies that may be generated for a
-+ multicast-to-unicast conversion. Once this limit is exceeded distribution will fall back to broadcast.
-+ .br
-++.IP "\fBnoflood_mark\fP|\fBnf\fP"
-++If no parameter is given the current noflood mark value is displayed.
-++Otherwise the parameter is used to set or unset the noflood mark. The
-++noflood mark allows to prevent broadcast flooding of a frame which
-++was previously tagged via netfilter for instance. batman-adv will
-++then only forward a frame into the mesh if destined to a limited
-++number of destination nodes and drop the frame otherwise.
-++.br
-++The input is supposed to be of the form $value/$mask, where $value can be any
-++32bit long integer (expressed in decimal or hex base) and $mask is a generic
-++bitmask (expressed in hex base) that selects the bits to take into consideration
-++from $value. It is also possible to enter the input using only $value and in
-++this case the full bitmask is used by default.
-++
-++.br
-++.br
-++Example 1: 0x00000001/0xffffffff
-++.br
-++Example 2: 0x00040000/0xffff0000
-++.br
-++Example 3: 16 or 0x0F
-++.br
-++.br
-+ .IP "\fBloglevel\fP|\fBll\fP [\fBlevel\fP[ \fBlevel\fP[ \fBlevel\fP]] \fB...\fP]"
-+ If no parameter is given the current log level settings are displayed otherwise the parameter(s) is/are used to set the log
-+ level. Level 'none' disables all verbose logging. Level 'batman' enables messages related to routing / flooding / broadcasting.
-+diff --git a/noflood_mark.c b/noflood_mark.c
-+new file mode 100644
-+index 0000000..e89205c
 +--- /dev/null
 ++++ b/noflood_mark.c
-+@@ -0,0 +1,141 @@
++@@ -0,0 +1,140 @@
 ++// SPDX-License-Identifier: GPL-2.0
 ++/* Copyright (C) 2009-2019  B.A.T.M.A.N. contributors:
 ++ *
@@ -271,7 +228,6 @@ index 0000000000000000000000000000000000000000..296f3c51b79333a8e96c340d151ba00b
 ++}
 ++
 ++static struct settings_data batctl_settings_noflood_mark = {
-++	.sysfs_name = NULL,
 ++	.data = &noflood_mark,
 ++	.parse = parse_noflood_mark,
 ++	.netlink_get = get_noflood_mark,
@@ -282,6 +238,3 @@ index 0000000000000000000000000000000000000000..296f3c51b79333a8e96c340d151ba00b
 ++	      COMMAND_FLAG_MESH_IFACE | COMMAND_FLAG_NETLINK,
 ++	      &batctl_settings_noflood_mark,
 ++	      "[mark]            \tdisplay or modify noflood_mark setting");
-+-- 
-+2.31.0
-+
diff --git a/targets/ar71xx-generic b/targets/ar71xx-generic
deleted file mode 100644
index df7dbd9787f367da42b0dbddf2852a30b863a554..0000000000000000000000000000000000000000
--- a/targets/ar71xx-generic
+++ /dev/null
@@ -1,523 +0,0 @@
-config('GLUON_SPECIALIZE_KERNEL', true)
-config('TARGET_SQUASHFS_BLOCK_SIZE', 64)
-
-local ATH10K_PACKAGES = {
-	'kmod-ath10k',
-	'-kmod-ath10k-ct',
-	'-kmod-ath10k-ct-smallbuffers',
-	'ath10k-firmware-qca988x',
-	'-ath10k-firmware-qca988x-ct',
-}
-local ATH10K_PACKAGES_QCA9887 = {
-	'kmod-ath10k',
-	'-kmod-ath10k-ct',
-	'-kmod-ath10k-ct-smallbuffers',
-	'ath10k-firmware-qca9887',
-	'-ath10k-firmware-qca9887-ct',
-}
-local ATH10K_PACKAGES_QCA9888 = {
-	'kmod-ath10k',
-	'-kmod-ath10k-ct',
-	'-kmod-ath10k-ct-smallbuffers',
-	'ath10k-firmware-qca9888',
-	'-ath10k-firmware-qca9888-ct',
-}
-
-
--- 8devices
-
-device('8devices-carambola2-board', 'carambola2', {
-	factory = false,
-})
-
-
--- ALFA NETWORK
-
-device('alfa-network-ap121f', 'ap121f', {
-	factory = false,
-	class = 'tiny', -- 32M ath9k
-})
-
-
--- Allnet
-
-device('allnet-all0315n', 'all0315n', {
-	profile = 'ALL0315N',
-	factory = false,
-})
-
-
--- AVM
-
-device('avm-fritz-box-4020', 'fritz4020', {
-	factory = false,
-})
-
-device('avm-fritz-wlan-repeater-300e', 'fritz300e', {
-	factory = false,
-})
-
-device('avm-fritz-wlan-repeater-450e', 'fritz450e', {
-	factory = false,
-})
-
-
--- Buffalo
-
-device('buffalo-wzr-hp-g300nh', 'wzr-hp-g300nh', {
-	profile = 'WZRHPG300NH',
-})
-device('buffalo-wzr-hp-g300nh2', 'wzr-hp-g300nh2', {
-	profile = 'WZRHPG300NH2',
-})
-device('buffalo-wzr-hp-g450h', 'wzr-hp-g450h', {
-	profile = 'WZRHPG450H',
-})
-
-
-device('buffalo-wzr-hp-ag300h', 'wzr-hp-ag300h', {
-	profile = 'WZRHPAG300H',
-	sysupgrade = false,
-})
-device('buffalo-wzr-600dhp', 'wzr-600dhp', {
-	profile = 'WZR600DHP',
-	sysupgrade = false,
-})
-sysupgrade_image('buffalo-wzr-hp-ag300h-wzr-600dhp', 'wzr-hp-ag300h-squashfs-sysupgrade', '.bin')
-
-
--- D-Link
-
-device('d-link-dap-1330-rev-a1', 'dap-1330-a1', {
-	factory_ext = '.img',
-})
-
-device('d-link-dir-505-rev-a1', 'dir-505-a1', {
-	profile = 'DIR505A1',
-	aliases = {'d-link-dir-505-rev-a2'},
-})
-
-device('d-link-dir-825-rev-b1', 'dir-825-b1', {
-	profile = 'DIR825B1',
-	factory = false,
-	class = 'tiny', -- Only 6M of usable Firmware space
-})
-
-
--- GL.iNet
-
-device('gl-inet-6408a-v1', 'gl-inet-6408A-v1')
-
-device('gl-inet-6416a-v1', 'gl-inet-6416A-v1')
-
-device('gl.inet-gl-ar150', 'gl-ar150', {
-	factory = false,
-	manifest_aliases = {'gl-ar150'},
-})
-
-device('gl.inet-gl-ar300m', 'gl-ar300m', {
-	factory = false,
-	manifest_aliases = {'gl-ar300m'},
-})
-
-device('gl.inet-gl-ar750', 'gl-ar750', {
-	factory = false,
-	manifest_aliases = {'gl-ar750'},
-	packages = ATH10K_PACKAGES_QCA9887,
-})
-
-device('gl.inet-gl-usb150', 'gl-usb150', {
-	factory = false,
-})
-
-
--- Linksys by Cisco
-
-device('linksys-wrt160nl', 'wrt160nl', {
-	profile = 'WRT160NL',
-	class = 'tiny', -- 32M ath9k
-})
-
-
--- Meraki
-device('meraki-mr12', 'mr12', {
-	factory = false,
-	aliases = {'meraki-mr62'},
-	broken = true, -- MAC address uniqueness issues
-})
-
-device('meraki-mr16', 'mr16', {
-	factory = false,
-	aliases = {'meraki-mr66'},
-	broken = true, -- MAC address uniqueness issues
-})
-
-
--- Netgear
-
-device('netgear-wndr3700', 'wndr3700', {
-	factory_ext = '.img',
-})
-
-device('netgear-wndr3700v2', 'wndr3700v2', {
-	factory_ext = '.img',
-})
-
-device('netgear-wndr3800', 'wndr3800', {
-	aliases = {'netgear-wndr3800chmychart'},
-	factory_ext = '.img',
-})
-
-device('netgear-wndrmacv2', 'wndrmacv2', {
-	factory_ext = '.img',
-})
-
-device('netgear-wndrmac', 'wndrmac', {
-	factory_ext = '.img',
-	broken = true, -- untested
-})
-
--- BROKEN: Untested
-device('netgear-wnr2200', 'wnr2200', {
-	profile = 'WNR2200',
-	factory_ext = '.img',
-	broken = true, -- untested
-})
-
-
--- OCEDO
-
-device('ocedo-koala', 'koala', {
-	factory = false,
-	packages = ATH10K_PACKAGES,
-})
-
-
--- Onion
-
-device('onion-omega', 'onion-omega', {
-	broken = true, -- no Ethernet
-})
-
--- OpenMesh
-
-device('openmesh-a60', 'a60', {
-	profile = 'A60',
-	aliases = {'openmesh-a40'},
-	packages = ATH10K_PACKAGES,
-})
-
-device('openmesh-mr1750', 'mr1750', {
-	profile = 'MR1750',
-	aliases = {'openmesh-mr1750v2'},
-	packages = ATH10K_PACKAGES,
-})
-
-device('openmesh-mr600', 'mr600', {
-	profile = 'MR600',
-	aliases = {'openmesh-mr600v2'},
-})
-
-device('openmesh-mr900', 'mr900', {
-	profile = 'MR900',
-	aliases = {'openmesh-mr900v2'},
-})
-
-device('openmesh-om2p', 'om2p', {
-	profile = 'OM2P',
-	aliases = {
-		'openmesh-om2pv2',
-		'openmesh-om2pv4',
-		'openmesh-om2p-hs',
-		'openmesh-om2p-hsv2',
-		'openmesh-om2p-hsv3',
-		'openmesh-om2p-hsv4',
-		'openmesh-om2p-lc',
-	},
-})
-
-device('openmesh-om5p', 'om5p', {
-	profile = 'OM5P',
-	aliases = {'openmesh-om5p-an'},
-})
-
-device('openmesh-om5p-ac', 'om5pac', {
-	profile = 'OM5PAC',
-	aliases = {'openmesh-om5p-acv2'},
-	packages = ATH10K_PACKAGES,
-})
-
-
--- TP-Link
-
-local tplink_region_suffix = ''
-if (env.GLUON_REGION or '') ~= '' then
-	tplink_region_suffix = '-' .. env.GLUON_REGION
-end
-
-device('tp-link-cpe210-v1', 'cpe210-220-v1', {
-	aliases = {
-		'tp-link-cpe220-v1',
-	},
-	manifest_aliases = {
-		'tp-link-cpe210-v1.0',
-		'tp-link-cpe210-v1.1',
-		'tp-link-cpe220-v1.1',
-	},
-})
-device('tp-link-cpe210-v2', 'cpe210-v2', {
-	manifest_aliases = {
-		'tp-link-cpe210-v2.0',
-	},
-})
-device('tp-link-cpe210-v3', 'cpe210-v3', {
-	manifest_aliases = {
-		'tp-link-cpe210-v3.0',
-		'tp-link-cpe210-v3.1',
-		'tp-link-cpe210-v3.20',
-	},
-})
-
-device('tp-link-cpe510-v1', 'cpe510-520-v1', {
-	aliases = {
-		'tp-link-cpe520-v1',
-	},
-	manifest_aliases = {
-		'tp-link-cpe510-v1.0',
-		'tp-link-cpe510-v1.1',
-		'tp-link-cpe520-v1.1',
-	},
-})
-
-device('tp-link-wbs210-v1', 'wbs210-v1', {
-	manifest_aliases = {
-		'tp-link-wbs210-v1.20',
-	},
-})
-device('tp-link-wbs510-v1', 'wbs510-v1', {
-	manifest_aliases = {
-		'tp-link-wbs510-v1.20',
-	},
-})
-
-device('tp-link-tl-wr710n-v1', 'tl-wr710n-v1', {
-	class = 'tiny', -- 32M ath9k
-	packages = { 'zram-swap' },
-})
-device('tp-link-tl-wr710n-v2.1', 'tl-wr710n-v2.1', {
-	class = 'tiny', -- 32M ath9k
-	packages = { 'zram-swap' },
-})
-
-device('tp-link-tl-wr810n-v1', 'tl-wr810n-v1')
-
-device('tp-link-tl-wr842n-nd-v1', 'tl-wr842n-v1', {
-	class = 'tiny', -- 32M ath9k
-	packages = { 'zram-swap' },
-})
-device('tp-link-tl-wr842n-nd-v2', 'tl-wr842n-v2', {
-	class = 'tiny', -- 32M ath9k
-	packages = { 'zram-swap' },
-})
-device('tp-link-tl-wr842n-nd-v3', 'tl-wr842n-v3')
-
-device('tp-link-tl-wr1043n-nd-v1', 'tl-wr1043nd-v1', {
-	class = 'tiny', -- 32M ath9k
-	packages = { 'zram-swap' },
-})
-device('tp-link-tl-wr1043n-nd-v2', 'tl-wr1043nd-v2')
-device('tp-link-tl-wr1043n-nd-v3', 'tl-wr1043nd-v3')
-device('tp-link-tl-wr1043n-nd-v4', 'tl-wr1043nd-v4')
-device('tp-link-tl-wr1043n-v5', 'tl-wr1043n-v5')
-
-device('tp-link-tl-wdr3500-v1', 'tl-wdr3500-v1')
-device('tp-link-tl-wdr3600-v1', 'tl-wdr3600-v1')
-device('tp-link-tl-wdr4300-v1', 'tl-wdr4300-v1')
-
-device('tp-link-tl-wr2543n-nd-v1', 'tl-wr2543-v1')
-
-device('tp-link-archer-c5-v1', 'archer-c5-v1', {
-	packages = ATH10K_PACKAGES,
-})
-
-device('tp-link-archer-c7-v2', 'archer-c7-v2', {
-	packages = ATH10K_PACKAGES,
-	factory = '-squashfs-factory' .. tplink_region_suffix,
-})
-
-device('tp-link-archer-c7-v4', 'archer-c7-v4', {
-	packages = ATH10K_PACKAGES,
-})
-
-device('tp-link-archer-c7-v5', 'archer-c7-v5', {
-	packages = ATH10K_PACKAGES,
-})
-
-device('tp-link-archer-c25-v1', 'archer-c25-v1', {
-	packages = ATH10K_PACKAGES_QCA9887,
-	broken = true, -- OOM with 5GHz enabled in most environments
-	class = 'tiny', -- 64M ath9k + ath10k
-})
-
-device('tp-link-archer-c58-v1', 'archer-c58-v1', {
-	packages = ATH10K_PACKAGES_QCA9888,
-	broken = true, -- OOM with 5GHz enabled in most environments
-	class = 'tiny', -- 64M ath9k + ath10k
-})
-
-device('tp-link-archer-c59-v1', 'archer-c59-v1', {
-	packages = ATH10K_PACKAGES_QCA9888,
-})
-
-device('tp-link-archer-c60-v1', 'archer-c60-v1', {
-	packages = ATH10K_PACKAGES_QCA9888,
-	broken = true, -- OOM with 5GHz enabled in most environments
-	class = 'tiny', -- 64M ath9k + ath10k
-})
-
-device('tp-link-archer-c60-v2', 'archer-c60-v2', {
-	packages = ATH10K_PACKAGES_QCA9888,
-	broken = true, -- OOM with 5GHz enabled in most environments
-	class = 'tiny', -- 64M ath9k + ath10k
-})
-
-device('tp-link-re355', 're355-v1', {
-	packages = ATH10K_PACKAGES,
-	broken = true, -- OOM with 5GHz enabled in most environments if device is 64M RAM variant
-	class = 'tiny', -- Only 6M of usable Firmware space
-})
-
-device('tp-link-tl-wr902ac-v1', 'tl-wr902ac-v1', {
-	packages = ATH10K_PACKAGES_QCA9887,
-	broken = true, -- OOM due to insufficient RAM for ath10k expected
-	class = 'tiny', -- 64M ath9k + ath10k
-})
-
-device('tp-link-re450', 're450-v1', {
-	packages = ATH10K_PACKAGES,
-	class = 'tiny', -- Only 6M of usable Firmware space
-})
-
-
--- Ubiquiti
-
-device('ubiquiti-airgateway', 'ubnt-air-gateway', {
-	aliases = {'ubiquiti-airgateway-lr'},
-	class = 'tiny', -- 32M ath9k
-})
-
-device('ubiquiti-airgateway-pro', 'ubnt-air-gateway-pro', {
-	class = 'tiny', -- 32M ath9k
-})
-
-device('ubiquiti-airrouter', 'ubnt-airrouter', {
-	class = 'tiny', -- 32M ath9k
-})
-
-device('ubiquiti-bullet-m', 'ubnt-bullet-m', {
-	aliases = {
-		'ubiquiti-nanostation-loco-m2',
-		'ubiquiti-nanostation-loco-m5',
-		'ubiquiti-bullet-m2',
-		'ubiquiti-bullet-m5',
-		'ubiquiti-picostation-m2',
-	},
-	packages = { 'zram-swap' },
-	class = 'tiny', -- 32M ath9k
-})
-
-device('ubiquiti-rocket-m', 'ubnt-rocket-m', {
-	aliases = {'ubiquiti-rocket-m2'},
-	manifest_aliases = {'ubiquiti-rocket-m5'},
-})
-
-device('ubiquiti-nanostation-m', 'ubnt-nano-m', {
-	aliases = {
-		'ubiquiti-nanostation-m2',
-		'ubiquiti-nanostation-m5',
-	},
-	packages = { 'zram-swap' },
-	class = 'tiny', -- 32M ath9k
-})
-
-device('ubiquiti-loco-m-xw', 'ubnt-loco-m-xw', {
-	aliases = {
-		'ubiquiti-nanostation-loco-m2-xw',
-		'ubiquiti-nanostation-loco-m5-xw',
-		-- 'ubiquiti-nanobeam-m5', -- untested
-	},
-})
-
-device('ubiquiti-nanostation-m-xw', 'ubnt-nano-m-xw', {
-	aliases = {
-		'ubiquiti-nanostation-m2-xw',
-		'ubiquiti-nanostation-m5-xw',
-	},
-})
-
-device('ubiquiti-rocket-m-xw', 'ubnt-rocket-m-xw', {
-	aliases = {
-		'ubiquiti-rocket-m2-xw',
-		'ubiquiti-rocket-m5-xw',
-	},
-})
-
-device('ubiquiti-rocket-m-ti', 'ubnt-rocket-m-ti', {
-	aliases = {
-		'ubiquiti-rocket-m2-ti',
-		'ubiquiti-rocket-m5-ti',
-	},
-})
-
-device('ubiquiti-unifi', 'ubnt-unifi', {
-	aliases = {
-		'ubiquiti-unifi-ap',
-		'ubiquiti-unifi-ap-lr',
-	},
-})
-
-device('ubiquiti-unifi-ap-pro', 'ubnt-uap-pro')
-device('ubiquiti-unifiap-outdoor', 'ubnt-unifi-outdoor')
-device('ubiquiti-unifiap-outdoor+', 'ubnt-unifi-outdoor-plus')
-
-device('ubiquiti-ls-sr71', 'ubnt-ls-sr71', {
-	broken = true, -- untested
-	class = 'tiny', -- 32M ath9k
-})
-
-device('ubiquiti-unifi-ac-lite', 'ubnt-unifiac-lite', {
-	factory = false,
-	packages = ATH10K_PACKAGES,
-	aliases = {'ubiquiti-unifi-ac-lite-mesh'},
-})
-
-device('ubiquiti-unifi-ac-lr', 'ubnt-unifiac-lr', {
-	factory = false,
-	packages = ATH10K_PACKAGES,
-})
-
-device('ubiquiti-unifi-ac-pro', 'ubnt-unifiac-pro', {
-	factory = false,
-	packages = ATH10K_PACKAGES,
-})
-
-device('ubiquiti-unifi-ac-mesh', 'ubnt-unifiac-mesh', {
-	factory = false,
-	packages = ATH10K_PACKAGES,
-})
-
-device('ubiquiti-unifi-ac-mesh-pro', 'ubnt-unifiac-mesh-pro', {
-	factory = false,
-	packages = ATH10K_PACKAGES,
-})
-
-
--- Western Digital
-
-device('wd-my-net-n600', 'mynet-n600')
-device('wd-my-net-n750', 'mynet-n750')
-
--- ZyXEL
-device('zyxel-nbg6616', 'NBG6616', {
-	packages = ATH10K_PACKAGES,
-})
diff --git a/targets/ar71xx-mikrotik b/targets/ar71xx-mikrotik
deleted file mode 100644
index 81a053f21e330c7363be8069bd60cefc28642526..0000000000000000000000000000000000000000
--- a/targets/ar71xx-mikrotik
+++ /dev/null
@@ -1,12 +0,0 @@
-config('GLUON_SPECIALIZE_KERNEL', true)
-
-defaults {
-	factory = false,
-}
-
-device('mikrotik-rb-nor-flash-16M', 'rb-nor-flash-16M')
-device('mikrotik-rb-nor-flash-16M-ac', 'rb-nor-flash-16M-ac')
-
-device('mikrotik-nand-64m', 'nand-64m')
-device('mikrotik-nand-large', 'nand-large')
-device('mikrotik-nand-large-ac', 'nand-large-ac')
diff --git a/targets/ar71xx-nand b/targets/ar71xx-nand
deleted file mode 100644
index 89afd52cba522889eaa16ba3087bac1c0c6f5dfd..0000000000000000000000000000000000000000
--- a/targets/ar71xx-nand
+++ /dev/null
@@ -1,33 +0,0 @@
-config('GLUON_SPECIALIZE_KERNEL', true)
-
-local ATH10K_PACKAGES = {'kmod-ath10k', '-kmod-ath10k-ct', 'ath10k-firmware-qca988x', '-ath10k-firmware-qca988x-ct'}
-
-
-defaults {
-	sysupgrade_ext = '.tar',
-}
-
-
--- Aerohive
-
-device('aerohive-hiveap-121', 'hiveap-121')
-
-
--- Netgear
-
-device('netgear-wndr3700v4', 'wndr3700v4', {
-	profile = 'WNDR3700V4',
-	factory = '-ubi-factory',
-	factory_ext = '.img',
-})
-device('netgear-wndr4300', 'wndr4300', {
-	profile = 'WNDR4300V1',
-	factory = '-ubi-factory',
-	factory_ext = '.img',
-})
-
--- ZyXEL
-device('zyxel-nbg6716', 'nbg6716', {
-	profile = 'NBG6716',
-	packages = ATH10K_PACKAGES,
-})
diff --git a/targets/ar71xx-tiny b/targets/ar71xx-tiny
deleted file mode 100644
index a0a8d5108bf4c8948af73c1b6dc475ecb6c8460f..0000000000000000000000000000000000000000
--- a/targets/ar71xx-tiny
+++ /dev/null
@@ -1,133 +0,0 @@
-config('GLUON_SPECIALIZE_KERNEL', true)
-
-no_opkg()
-
-packages {
-	'-uboot-envtools',
-	'-kmod-usb-core',
-	'-kmod-usb-ohci',
-	'-kmod-usb2',
-	'-kmod-usb-ledtrig-usbport',
-}
-
-defaults {
-	deprecated = true, -- 4/32
-	class = 'tiny',
-}
-
-
--- D-Link
-
-device('d-link-dir-615-rev-c1', 'dir-615-c1', {
-	profile = 'DIR615C1',
-})
-
-
--- TP-Link
-
-local tplink_region_suffix = ''
-if (env.GLUON_REGION or '') ~= '' then
-	tplink_region_suffix = '-' .. env.GLUON_REGION
-end
-
-device('tp-link-tl-wa701n-nd-v1', 'tl-wa701nd-v1')
-device('tp-link-tl-wa701n-nd-v2', 'tl-wa701nd-v2')
-
-device('tp-link-tl-wa7210n-v2', 'tl-wa7210n-v2')
-device('tp-link-tl-wa7510n-v1', 'tl-wa7510n-v1')
-
-device('tp-link-tl-wr703n-v1', 'tl-wr703n-v1')
-
-device('tp-link-tl-wr710n-v2', 'tl-wr710n-v2')
-
-device('tp-link-tl-wr740n-nd-v1', 'tl-wr740n-v1')
-device('tp-link-tl-wr740n-nd-v3', 'tl-wr740n-v3')
-device('tp-link-tl-wr740n-nd-v4', 'tl-wr740n-v4')
-device('tp-link-tl-wr740n-nd-v5', 'tl-wr740n-v5')
-
-device('tp-link-tl-wr741n-nd-v1', 'tl-wr741nd-v1')
-device('tp-link-tl-wr741n-nd-v2', 'tl-wr741nd-v2')
-device('tp-link-tl-wr741n-nd-v4', 'tl-wr741nd-v4')
-device('tp-link-tl-wr741n-nd-v5', 'tl-wr741nd-v5')
-
-device('tp-link-tl-wr743n-nd-v1', 'tl-wr743nd-v1')
-device('tp-link-tl-wr743n-nd-v2', 'tl-wr743nd-v2')
-
-device('tp-link-tl-wa801n-nd-v1', 'tl-wa801nd-v1')
-device('tp-link-tl-wa801n-nd-v2', 'tl-wa801nd-v2')
-device('tp-link-tl-wa801n-nd-v3', 'tl-wa801nd-v3')
-
-device('tp-link-tl-wr802n-v1', 'tl-wr802n-v1', {
-	broken = true, -- untested
-})
-
-device('tp-link-tl-wr840n-v2', 'tl-wr840n-v2')
-
-device('tp-link-tl-wr841n-nd-v3', 'tl-wr841-v3')
-device('tp-link-tl-wr841n-nd-v5', 'tl-wr841-v5')
-device('tp-link-tl-wr841n-nd-v7', 'tl-wr841-v7')
-device('tp-link-tl-wr841n-nd-v8', 'tl-wr841-v8')
-device('tp-link-tl-wr841n-nd-v9', 'tl-wr841-v9')
-device('tp-link-tl-wr841n-nd-v10', 'tl-wr841-v10')
-device('tp-link-tl-wr841n-nd-v11', 'tl-wr841-v11', {
-	factory = '-squashfs-factory' .. tplink_region_suffix,
-})
-device('tp-link-tl-wr841n-nd-v12', 'tl-wr841-v12', {
-	factory = '-squashfs-factory' .. tplink_region_suffix,
-})
-
-device('tp-link-tl-wr843n-nd-v1', 'tl-wr843nd-v1')
-
-device('tp-link-tl-wr941n-nd-v2', 'tl-wr941nd-v2')
-device('tp-link-tl-wr941n-nd-v3', 'tl-wr941nd-v3')
-
-device('tp-link-tl-wr941n-nd-v4', 'tl-wr941nd-v4', {
-	aliases = {'tp-link-tl-wr940n-v1'},
-})
-
-device('tp-link-tl-wr941n-nd-v5', 'tl-wr941nd-v5', {
-	aliases = {'tp-link-tl-wr940n-v2'},
-})
-
-device('tp-link-tl-wr941n-nd-v6', 'tl-wr941nd-v6', {
-	aliases = {'tp-link-tl-wr940n-v3'},
-})
-
-device('tp-link-tl-wr940n-v4', 'tl-wr940n-v4', {
-	factory = '-squashfs-factory' .. tplink_region_suffix,
-	aliases = {'tp-link-tl-wr940n-v5'},
-})
-
-device('tp-link-tl-wr940n-v6', 'tl-wr940n-v6', {
-	factory = '-squashfs-factory' .. tplink_region_suffix,
-})
-
-device('tp-link-tl-wa730re-v1', 'tl-wa730re-v1')
-
-device('tp-link-tl-wa750re-v1', 'tl-wa750re-v1')
-
-device('tp-link-tl-wa830re-v1', 'tl-wa830re-v1')
-device('tp-link-tl-wa830re-v2', 'tl-wa830re-v2')
-
-device('tp-link-tl-wa850re-v1', 'tl-wa850re-v1')
-
-device('tp-link-tl-wa860re-v1', 'tl-wa860re-v1')
-
-device('tp-link-tl-wa901n-nd-v1', 'tl-wa901nd-v1')
-device('tp-link-tl-wa901n-nd-v2', 'tl-wa901nd-v2')
-device('tp-link-tl-wa901n-nd-v3', 'tl-wa901nd-v3')
-device('tp-link-tl-wa901n-nd-v4', 'tl-wa901nd-v4')
-device('tp-link-tl-wa901n-nd-v5', 'tl-wa901nd-v5')
-
-device('tp-link-tl-mr13u-v1', 'tl-mr13u-v1')
-
-device('tp-link-tl-mr3020-v1', 'tl-mr3020-v1')
-
-device('tp-link-tl-mr3040-v1', 'tl-mr3040-v1')
-device('tp-link-tl-mr3040-v2', 'tl-mr3040-v2')
-
-device('tp-link-tl-mr3220-v1', 'tl-mr3220-v1')
-device('tp-link-tl-mr3220-v2', 'tl-mr3220-v2')
-
-device('tp-link-tl-mr3420-v1', 'tl-mr3420-v1')
-device('tp-link-tl-mr3420-v2', 'tl-mr3420-v2')
diff --git a/targets/ath79-generic b/targets/ath79-generic
index 5537a7ea3f561541fc9c03e424d013c191dec214..f2c1a952005ef4904d3cd608536f810d429dbe13 100644
--- a/targets/ath79-generic
+++ b/targets/ath79-generic
@@ -60,11 +60,6 @@ device('gl.inet-gl-ar300m-lite', 'glinet_gl-ar300m-lite', {
 	factory = false,
 })
 
-device('gl.inet-gl-ar750s-nor', 'glinet_gl-ar750s', {
-	factory = false,
-	packages = ATH10K_PACKAGES_QCA9887,
-})
-
 -- OCEDO
 
 device('ocedo-raccoon', 'ocedo_raccoon', {
diff --git a/targets/ath79-nand b/targets/ath79-nand
new file mode 100644
index 0000000000000000000000000000000000000000..5fe844ea2c7b9fd9cb27fba93eb04e72c54c0188
--- /dev/null
+++ b/targets/ath79-nand
@@ -0,0 +1,13 @@
+local ATH10K_PACKAGES_QCA9887 = {
+	'kmod-ath10k',
+	'-kmod-ath10k-ct',
+	'-kmod-ath10k-ct-smallbuffers',
+	'ath10k-firmware-qca9887',
+	'-ath10k-firmware-qca9887-ct',
+}
+
+
+device('gl.inet-gl-ar750s-nor', 'glinet_gl-ar750s-nor', {
+	factory = false,
+	packages = ATH10K_PACKAGES_QCA9887,
+})
diff --git a/targets/brcm2708-bcm2708 b/targets/bcm27xx-bcm2708
similarity index 91%
rename from targets/brcm2708-bcm2708
rename to targets/bcm27xx-bcm2708
index 4d4068aba3c76cd85e1bad56a4a88fa009c9c36f..d35866ce8277869d556d4f95a82c2f1af16fe607 100644
--- a/targets/brcm2708-bcm2708
+++ b/targets/bcm27xx-bcm2708
@@ -1,4 +1,4 @@
-include 'brcm2708.inc'
+include 'bcm27xx.inc'
 
 device('raspberrypi-model-b', 'rpi', {
 	manifest_aliases = {
diff --git a/targets/brcm2708-bcm2709 b/targets/bcm27xx-bcm2709
similarity index 86%
rename from targets/brcm2708-bcm2709
rename to targets/bcm27xx-bcm2709
index e5af9c896fe01fedcc48b5ed374e12d1ec6a921f..5c9bd999ba9240cbc9a276c188ee39ce974b5a5b 100644
--- a/targets/brcm2708-bcm2709
+++ b/targets/bcm27xx-bcm2709
@@ -1,4 +1,4 @@
-include 'brcm2708.inc'
+include 'bcm27xx.inc'
 
 device('raspberrypi-2-model-b', 'rpi-2', {
 	manifest_aliases = {
diff --git a/targets/brcm2708-bcm2710 b/targets/bcm27xx-bcm2710
similarity index 88%
rename from targets/brcm2708-bcm2710
rename to targets/bcm27xx-bcm2710
index 1cf9ef3697fe3343c88bedab42d13d3e0442d659..9c641cd0f04663113eabe81e8978e7ed2761e196 100644
--- a/targets/brcm2708-bcm2710
+++ b/targets/bcm27xx-bcm2710
@@ -1,4 +1,4 @@
-include 'brcm2708.inc'
+include 'bcm27xx.inc'
 
 device('raspberrypi-3-model-b', 'rpi-3', {
 	manifest_aliases = {
diff --git a/targets/brcm2708.inc b/targets/bcm27xx.inc
similarity index 100%
rename from targets/brcm2708.inc
rename to targets/bcm27xx.inc
diff --git a/targets/generic b/targets/generic
index 8b1d484fff9e71398216c22ebf539eef184a891f..cd72112f745ce238a42cceb923283a6533a23f3e 100644
--- a/targets/generic
+++ b/targets/generic
@@ -39,9 +39,6 @@ config('ALL_NONSHARED', true)
 config('PACKAGE_usbip', false) -- fails to build
 config('PACKAGE_kmod-jool', false) -- fails to build
 
-config('BUSYBOX_CUSTOM', true)
-config('BUSYBOX_CONFIG_FEATURE_PREFER_IPV4_ADDRESS', false)
-
 try_config('PACKAGE_ATH_DEBUG', true)
 
 try_config('TARGET_SQUASHFS_BLOCK_SIZE', 256)
@@ -51,8 +48,8 @@ config('KERNEL_IPV6_MROUTE', false)
 
 config('COLLECT_KERNEL_DEBUG', true)
 
-try_config('TARGET_MULTI_PROFILE', true)
-try_config('TARGET_PER_DEVICE_ROOTFS', true)
+config('TARGET_MULTI_PROFILE', true)
+config('TARGET_PER_DEVICE_ROOTFS', true)
 
 config('GLUON_MULTIDOMAIN', istrue(env.GLUON_MULTIDOMAIN))
 
@@ -70,12 +67,16 @@ end
 config('GLUON_MINIFY', istrue(env.GLUON_MINIFY))
 
 packages {
+	'-ca-bundle',
 	'-kmod-ipt-offload',
+	'-libustream-wolfssl',
+	'-libwolfssl',
 	'-odhcpd-ipv6only',
 	'-ppp',
 	'-ppp-mod-pppoe',
 	'-wpad-mini',
 	'-wpad-basic',
+	'-wpad-basic-wolfssl',
 	'gluon-core',
 	'ip6tables',
 }
diff --git a/targets/mpc85xx-generic b/targets/mpc85xx-generic
deleted file mode 100644
index a806587b4ad26d1a3272614108acaa7729f932a8..0000000000000000000000000000000000000000
--- a/targets/mpc85xx-generic
+++ /dev/null
@@ -1 +0,0 @@
-device('tp-link-tl-wdr4900-v1', 'tl-wdr4900-v1')
diff --git a/targets/mpc85xx-p1010 b/targets/mpc85xx-p1010
new file mode 100644
index 0000000000000000000000000000000000000000..3335ac599c4f7d84ed8a1c5e25392212e7ae13b4
--- /dev/null
+++ b/targets/mpc85xx-p1010
@@ -0,0 +1 @@
+device('tp-link-tl-wdr4900-v1', 'tplink_tl-wdr4900-v1')
diff --git a/targets/mpc85xx-p1020 b/targets/mpc85xx-p1020
index 952b9998153ccd39de292c58d37a372e843d7549..b2887eb8956fcaad45a01fe2912fb70a168e8474 100644
--- a/targets/mpc85xx-p1020
+++ b/targets/mpc85xx-p1020
@@ -1,20 +1,20 @@
 -- Aerohive
 
-device('aerohive-hiveap-330', 'hiveap-330', {
+device('aerohive-hiveap-330', 'aerohive_hiveap-330', {
 	factory = false,
 })
 
 
 -- Enterasys
 
-device('enterasys-ws-ap3710i', 'ws-ap3710i', {
+device('enterasys-ws-ap3710i', 'enterasys_ws-ap3710i', {
 	factory = false,
 })
 
 
 -- OCEDO
 
-device('ocedo-panda', 'panda', {
+device('ocedo-panda', 'ocedo_panda', {
 	factory = false,
 })
 
diff --git a/targets/ramips-mt7620 b/targets/ramips-mt7620
index 1cb61e5f64b42612ecb7ce65d3100ee35edce021..347df37c98411081c269a325d592111ad7a328eb 100644
--- a/targets/ramips-mt7620
+++ b/targets/ramips-mt7620
@@ -1,6 +1,6 @@
 -- ASUS
 
-device('asus-rt-ac51u', 'rt-ac51u', {
+device('asus-rt-ac51u', 'asus_rt-ac51u', {
 	factory = false,
 	broken = true, -- no 5GHz usable, LEDs not fully supported
 })
@@ -8,21 +8,21 @@ device('asus-rt-ac51u', 'rt-ac51u', {
 
 -- GL.iNet
 
-device('gl-mt300a', 'gl-mt300a', {
+device('gl-mt300a', 'glinet_gl-mt300a', {
 	factory = false,
 })
 
-device('gl-mt300n', 'gl-mt300n', {
+device('gl-mt300n', 'glinet_gl-mt300n', {
 	factory = false,
 })
 
-device('gl-mt750', 'gl-mt750', {
+device('gl-mt750', 'glinet_gl-mt750', {
 	factory = false,
 })
 
 -- Netgear
 
-device('netgear-ex3700', 'ex3700-ex3800', {
+device('netgear-ex3700', 'netgear_ex3700', {
 	aliases = {
 		'netgear-ex3800',
 	},
@@ -32,7 +32,7 @@ device('netgear-ex3700', 'ex3700-ex3800', {
 
 -- Nexx
 
-device('nexx-wt3020-8m', 'wt3020-8M', {
+device('nexx-wt3020-8m', 'nexx_wt3020-8m', {
 	aliases = {
 		'nexx-wt3020ad',
 		'nexx-wt3020f',
@@ -47,23 +47,24 @@ if (env.GLUON_REGION or '') ~= '' then
 	tplink_region_suffix = '-' .. env.GLUON_REGION
 end
 
-device('tp-link-archer-c2-v1', 'tplink_c2-v1', {
+device('tp-link-archer-c2-v1', 'tplink_archer-c2-v1', {
 	factory = false,
 })
 
-device('tp-link-archer-c20-v1', 'tplink_c20-v1', {
+device('tp-link-archer-c20-v1', 'tplink_archer-c20-v1', {
 	factory = false,
 })
 
-device('tp-link-archer-c20i', 'ArcherC20i')
+device('tp-link-archer-c20i', 'tplink_archer-c20i')
 
-device('tp-link-archer-c50', 'ArcherC50v1', {
+device('tp-link-archer-c50-v1', 'tplink_archer-c50-v1', {
 	factory = '-squashfs-factory' .. tplink_region_suffix,
+	manifest_aliases = {'tp-link-archer-c50'},
 })
 
 
 -- Xiaomi
 
-device('xiaomi-miwifi-mini', 'miwifi-mini', {
+device('xiaomi-miwifi-mini', 'xiaomi_miwifi-mini', {
 	factory = false,
 })
diff --git a/targets/ramips-mt7621 b/targets/ramips-mt7621
index 978eb619f39f1db0d4218461cb68c7aad6c34596..528bd361042aa11a4855dbbaf20b0a2d8f140267 100644
--- a/targets/ramips-mt7621
+++ b/targets/ramips-mt7621
@@ -7,7 +7,7 @@ device('asus-rt-ac57u', 'asus_rt-ac57u', {
 
 -- D-Link
 
-device('d-link-dir-860l-b1', 'dir-860l-b1')
+device('d-link-dir-860l-b1', 'dlink_dir-860l-b1')
 
 
 -- Netgear
@@ -16,27 +16,35 @@ device('netgear-ex6150', 'netgear_ex6150', {
 	factory_ext = '.chk',
 })
 
-device('netgear-r6220', 'r6220', {
+device('netgear-r6220', 'netgear_r6220', {
 	factory_ext = '.img',
 })
 
-device('netgear-wndr3700v5', 'wndr3700v5', {
+device('netgear-wndr3700-v5', 'netgear_wndr3700-v5', {
 	factory = false,
 	broken = true, -- untested
+	manifest_aliases = {
+		'netgear-wndr3700v5',
+	},
 })
 
 
 -- ZBT
 
-device('zbt-wg3526-16m', 'zbt-wg3526-16M', {
+device('zbtlink-zbt-wg3526-16m', 'zbtlink_zbt-wg3526-16m', {
 	factory = false,
 	manifest_aliases = {
 		'zbt-wg3526',
+		'zbt-wg3526-16m',
 	},
 })
 
-device('zbt-wg3526-32m', 'zbt-wg3526-32M', {
+device('zbtlink-zbt-wg3526-32m', 'zbtlink_zbt-wg3526-32m', {
 	factory = false,
+	manifest_aliases = {
+		'zbt-wg3526-32m',
+	},
+
 })
 
 
@@ -44,12 +52,18 @@ device('zbt-wg3526-32m', 'zbt-wg3526-32M', {
 
 -- Ubiquiti
 
-device('ubnt-erx', 'ubnt-erx', {
+device('ubiquiti-edgerouter-x', 'ubnt_edgerouter-x', {
 	factory = false,
 	packages = {'-hostapd-mini'},
+	manifest_aliases = {
+		'ubnt-erx',
+	},
 })
 
-device('ubnt-erx-sfp', 'ubnt-erx-sfp', {
+device('ubiquiti-edgerouter-x-sfp', 'ubnt_edgerouter-x-sfp', {
 	factory = false,
 	packages = {'-hostapd-mini'},
+	manifest_aliases = {
+		'ubnt-erx-sfp',
+	},
 })
diff --git a/targets/ramips-mt76x8 b/targets/ramips-mt76x8
index 1af12e5cac9613f2752b531b041697a1cfb122f5..4a0bf711c68a5a6c79ae140da450b0b6c1999dc5 100644
--- a/targets/ramips-mt76x8
+++ b/targets/ramips-mt76x8
@@ -5,7 +5,7 @@ device('cudy-wr1000', 'cudy_wr1000')
 
 -- GL.iNet
 
-device('gl-mt300n-v2', 'gl-mt300n-v2', {
+device('gl-mt300n-v2', 'glinet_gl-mt300n-v2', {
 	factory = false,
 })
 
@@ -23,14 +23,14 @@ device('netgear-r6120', 'netgear_r6120', {
 
 -- TP-Link
 
-device('tp-link-archer-c50-v3', 'tplink_c50-v3', {
+device('tp-link-archer-c50-v3', 'tplink_archer-c50-v3', {
 	factory = false,
 	extra_images = {
 		{'-squashfs-tftp-recovery', '-bootloader', '.bin'},
 	},
 })
 
-device('tp-link-archer-c50-v4', 'tplink_c50-v4', {
+device('tp-link-archer-c50-v4', 'tplink_archer-c50-v4', {
 	factory = false,
 })
 
@@ -55,7 +55,7 @@ device('tp-link-tl-wa801nd-v5', 'tplink_tl-wa801nd-v5', {
 	},
 })
 
-device('tp-link-tl-wr841n-v13', 'tl-wr841n-v13', {
+device('tp-link-tl-wr841n-v13', 'tplink_tl-wr841n-v13', {
 	factory = false,
 	extra_images = {
 		{'-squashfs-tftp-recovery', '-bootloader', '.bin'},
@@ -71,13 +71,13 @@ device('tp-link-tl-wr902ac-v3', 'tplink_tl-wr902ac-v3', {
 
 -- VoCore 2
 
-device('vocore2', 'vocore2', {
+device('vocore2', 'vocore_vocore2', {
 	factory = false,
 })
 
 
 -- Xiaomi
 
-device('xiaomi-mi-router-4a-100m-edition', 'xiaomi_mir4a-100m', {
+device('xiaomi-mi-router-4a-100m-edition', 'xiaomi_mi-router-4a-100m', {
 	factory = false,
 })
diff --git a/targets/ramips-rt305x b/targets/ramips-rt305x
index 8678f12e12501853ada0f957885983b8e384a315..f8be18c772df2fb8c9557a7d182fd3fbb3a288a7 100644
--- a/targets/ramips-rt305x
+++ b/targets/ramips-rt305x
@@ -7,46 +7,12 @@ defaults {
 	class = 'tiny',  -- 32M RAM
 }
 
-local STRIP_USB_PACKAGES = {
-	'-kmod-usb-core',
-	'-kmod-usb-dwc2',
-	'-kmod-usb-ledtrig-usbport',
-}
-
-
--- A5
-
-device('a5-v11', 'a5-v11', {
-	deprecated = true, -- 4/32
-	packages = STRIP_USB_PACKAGES,
-})
-
-
--- D-Link
-
-device('d-link-dir-615-h1', 'dir-615-h1', {
-	deprecated = true, -- 4/32
-	packages = STRIP_USB_PACKAGES,
-})
-
-device('d-link-dir-615-d', 'dir-615-d', {
-	aliases = {
-		'd-link-dir-615-d1',
-		'd-link-dir-615-d2',
-		'd-link-dir-615-d3',
-		'd-link-dir-615-d4',
-	},
-	deprecated = true, -- 4/32
-	packages = STRIP_USB_PACKAGES,
-})
-
-
 -- VoCore
 
-device('vocore-8M', 'vocore-8M', {
+device('vocore-8M', 'vocore_vocore-8m', {
 	factory = false,
 })
 
-device('vocore-16M', 'vocore-16M', {
+device('vocore-16M', 'vocore_vocore-16m', {
 	factory = false,
 })
diff --git a/targets/sunxi-cortexa7 b/targets/sunxi-cortexa7
index 4946ed0b42987dd9695cc722d66093ae357c732c..f6f56248e4fb426925a7bc2f22212f730a691cc1 100644
--- a/targets/sunxi-cortexa7
+++ b/targets/sunxi-cortexa7
@@ -6,12 +6,12 @@ defaults {
 }
 
 
-device('lemaker-banana-pi', 'sun7i-a20-bananapi')
+device('lemaker-banana-pi', 'lemaker_bananapi')
 
-device('lemaker-banana-pro', 'sun7i-a20-bananapro', {
+device('lemaker-banana-pro', 'lemaker_bananapro', {
 	broken = true, -- WiFi chip not supported
 })
 
-device('lamobo-r1', 'sun7i-a20-lamobo-r1', {
+device('lamobo-r1', 'lamobo_lamobo-r1', {
 	broken = true, -- AP+11s not working
 })
diff --git a/targets/targets.mk b/targets/targets.mk
index 42a854fae67045775029c288dd64625d949013e0..c4e36a79236e50875e741fa43c6c47b3302243ec 100644
--- a/targets/targets.mk
+++ b/targets/targets.mk
@@ -1,16 +1,12 @@
-$(eval $(call GluonTarget,ar71xx,generic))
-ifneq ($(GLUON_DEPRECATED),0)
-$(eval $(call GluonTarget,ar71xx,tiny))
-endif
-$(eval $(call GluonTarget,ar71xx,nand))
 $(eval $(call GluonTarget,ath79,generic))
-$(eval $(call GluonTarget,brcm2708,bcm2708))
-$(eval $(call GluonTarget,brcm2708,bcm2709))
+$(eval $(call GluonTarget,ath79,nand))
+$(eval $(call GluonTarget,bcm27xx,bcm2708))
+$(eval $(call GluonTarget,bcm27xx,bcm2709))
 $(eval $(call GluonTarget,ipq40xx,generic))
 $(eval $(call GluonTarget,ipq806x,generic))
 $(eval $(call GluonTarget,lantiq,xrx200))
 $(eval $(call GluonTarget,lantiq,xway))
-$(eval $(call GluonTarget,mpc85xx,generic))
+$(eval $(call GluonTarget,mpc85xx,p1010))
 $(eval $(call GluonTarget,mpc85xx,p1020))
 $(eval $(call GluonTarget,ramips,mt7620))
 $(eval $(call GluonTarget,ramips,mt7621))
@@ -24,7 +20,6 @@ $(eval $(call GluonTarget,x86,64))
 
 
 ifneq ($(BROKEN),)
-$(eval $(call GluonTarget,ar71xx,mikrotik)) # BROKEN: no autoupdater due to missing libplatforminfo support
-$(eval $(call GluonTarget,brcm2708,bcm2710)) # BROKEN: Untested
+$(eval $(call GluonTarget,bcm27xx,bcm2710)) # BROKEN: Untested
 $(eval $(call GluonTarget,mvebu,cortexa9)) # BROKEN: No 11s support
 endif
diff --git a/targets/x86-64 b/targets/x86-64
index 3ef1251580a5e372fac26815b1232ce8c8ff2882..1ab9938da990bef76e1cbccab91d441d191ac0d5 100644
--- a/targets/x86-64
+++ b/targets/x86-64
@@ -1,6 +1,9 @@
 include 'x86.inc'
 
-factory_image('x86-64', 'combined-squashfs', '.img.gz')
-factory_image('x86-64', 'combined-squashfs', '.vdi')
-factory_image('x86-64', 'combined-squashfs', '.vmdk')
-sysupgrade_image('x86-64', 'combined-squashfs', '.img.gz')
+packages {
+        'kmod-gpio-nct5104d',
+        'kmod-leds-gpio',
+        'kmod-pcengines-apuv2',
+}
+
+device('x86-64', 'generic')
diff --git a/targets/x86-generic b/targets/x86-generic
index 57b55f4a090dcf1f29250bbd28e04cd4206d8d68..0e6d2b3940f3820846ba5e69631b5fee4a023543 100644
--- a/targets/x86-generic
+++ b/targets/x86-generic
@@ -1,9 +1,12 @@
 include 'x86.inc'
 
-factory_image('x86-generic', 'combined-squashfs', '.img.gz')
-factory_image('x86-generic', 'combined-squashfs', '.vdi')
-factory_image('x86-generic', 'combined-squashfs', '.vmdk')
-sysupgrade_image('x86-generic', 'combined-squashfs', '.img.gz', {
+packages {
+        'kmod-gpio-nct5104d',
+        'kmod-leds-gpio',
+        'kmod-pcengines-apuv2',
+}
+
+device('x86-generic', 'generic', {
 	manifest_aliases = {
 		'x86-kvm',
 		'x86-xen_domu',
diff --git a/targets/x86-geode b/targets/x86-geode
index 57519eb1b69d1f3cded0fb72bc1b171cc85e891b..146cfce9f4a2b9746e03a4687eb9ffb9f7d40890 100644
--- a/targets/x86-geode
+++ b/targets/x86-geode
@@ -18,5 +18,9 @@ packages {
 	'kmod-via-velocity',
 }
 
-factory_image('x86-geode', 'combined-squashfs', '.img.gz')
-sysupgrade_image('x86-geode', 'combined-squashfs', '.img.gz')
+device('x86-geode', 'generic', {
+	factory = '-squashfs-combined',
+	factory_ext = '.img.gz',
+	sysupgrade = '-squashfs-combined',
+	sysupgrade_ext = '.img.gz',
+})
diff --git a/targets/x86-legacy b/targets/x86-legacy
index 79667dad2a8cbb40a0b235ddd683b710181e5181..402d7e21950f72b032e4160456b0c7ebb1d37587 100644
--- a/targets/x86-legacy
+++ b/targets/x86-legacy
@@ -1,10 +1,3 @@
 include 'x86.inc'
 
-packages {
-        '-kmod-gpio-nct5104d',
-        '-kmod-leds-gpio',
-        '-kmod-leds-apu2',
-}
-
-factory_image('x86-legacy', 'combined-squashfs', '.img.gz')
-sysupgrade_image('x86-legacy', 'combined-squashfs', '.img.gz')
+device('x86-legacy', 'generic')
diff --git a/targets/x86.inc b/targets/x86.inc
index c6037c688f1fa683acc25e8dd927ce3a6b9987bf..ebefcbfac371dbcac2cd373256354ce72329c950 100644
--- a/targets/x86.inc
+++ b/targets/x86.inc
@@ -22,11 +22,8 @@ packages {
 	'kmod-via-velocity',
 	'kmod-ath9k',
 	'kmod-gpio-button-hotplug',
-	'kmod-gpio-nct5104d',
 	'kmod-hwmon-core',
-	'kmod-leds-gpio',
-	'kmod-leds-apu2',
-	'kmod-sp5100_tco',
+	'kmod-sp5100-tco',
 	'kmod-usb-core',
 	'kmod-usb-ohci',
 	'kmod-usb2',
@@ -42,3 +39,10 @@ packages {
 	'kmod-mt7603',
 	'kmod-mt7615e',
 }
+
+defaults {
+	factory = '-squashfs-combined',
+	factory_ext = {'.img.gz', '.vmdk', '.vdi'},
+	sysupgrade = '-squashfs-combined',
+	sysupgrade_ext = '.img.gz',
+}