Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 0x4A6F-master
  • 0x4A6F-rpi4
  • autinerd/experimental-openwrt-24.10
  • experimental
  • feature/addMikrotikwAP
  • master
  • nrb/airmax-test
  • nrb/ar9344-reset-sequence
  • nrb/ex400-remove-wps
  • nrb/gluon-master-cpe510
  • nrb/test-radv-filter
  • nrbffs/fastd-remove-delay
  • nrbffs/netgear-ex6120
  • v2018.2.2-ffs
  • v2018.2.3-ffs
  • v2019.1-ffs
  • v2019.1.1-ffs
  • v2019.1.2-ffs
  • v2020.1-ffs
  • v2020.1.1-ffs
  • v2020.1.3-ffs
  • v2020.2-ffs
  • v2020.2.1-ffs
  • v2020.2.2-ffs
  • v2020.2.3-ffs
  • v2021.1-ffs
  • v2021.1.1-ffs
  • v2021.1.2-ffs
  • v2022.1.1-ffs
  • v2022.1.3-ffs
  • v2022.1.4-ffs
  • v2023.1-ffs
  • v2023.2-ffs
  • v2023.2.2-ffs
  • v2023.2.3-ffs
  • v2023.2.4-ffs
  • v2023.2.5-ffs
  • experimental-2022-09-24
  • experimental-2022-09-24-base
  • experimental-2023-03-11
  • experimental-2023-03-11-base
  • experimental-2023-03-12
  • experimental-2023-03-12-base
  • experimental-2023-03-16
  • experimental-2023-03-16-base
  • experimental-2023-03-20
  • experimental-2023-03-20-base
  • experimental-2023-03-23
  • experimental-2023-03-23-base
  • experimental-2023-03-25
  • experimental-2023-03-25-base
  • experimental-2023-03-26
  • experimental-2023-03-26-base
  • experimental-2023-03-30
  • experimental-2023-03-30-base
  • experimental-2023-03-31
  • experimental-2023-03-31-base
  • experimental-2023-04-01
  • experimental-2023-04-01-base
  • experimental-2023-04-08
  • experimental-2023-04-08-base
  • experimental-2023-04-10
  • experimental-2023-04-10-base
  • experimental-2023-04-13
  • experimental-2023-04-13-base
  • experimental-2023-04-15
  • experimental-2023-04-15-base
  • experimental-2023-04-16
  • experimental-2023-04-16-base
  • experimental-2023-04-18
  • experimental-2023-04-18-base
  • experimental-2023-04-20
  • experimental-2023-04-20-base
  • experimental-2023-04-26
  • experimental-2023-04-26-base
  • experimental-2023-04-28
  • experimental-2023-04-28-base
  • experimental-2023-04-30
  • experimental-2023-04-30-base
  • experimental-2023-05-02
  • experimental-2023-05-02-base
  • experimental-2023-05-03
  • experimental-2023-05-03-base
  • experimental-2023-05-12
  • experimental-2023-05-12-base
  • experimental-2023-05-21
  • experimental-2023-05-21-base
  • experimental-2023-05-25
  • experimental-2023-05-25-base
  • experimental-2023-07-02
  • experimental-2023-07-02-base
  • experimental-2023-07-04
  • experimental-2023-07-04-base
  • experimental-2023-07-12
  • experimental-2023-07-12-base
  • experimental-2023-07-16
  • experimental-2023-07-16-base
  • experimental-2023-08-04
  • experimental-2023-08-04-base
  • experimental-2023-08-10
  • experimental-2023-08-10-base
  • experimental-2023-09-08
  • experimental-2023-09-08-base
  • experimental-2023-09-09
  • experimental-2023-09-09-base
  • experimental-2023-09-10
  • experimental-2023-09-10-base
  • experimental-2023-09-11
  • experimental-2023-09-11-base
  • experimental-2023-09-12
  • experimental-2023-09-12-base
  • experimental-2023-09-13
  • experimental-2023-09-13-base
  • experimental-2023-09-15
  • experimental-2023-09-15-base
  • experimental-2023-09-16
  • experimental-2023-09-16-base
  • experimental-2023-09-18
  • experimental-2023-09-18-base
  • experimental-2023-09-20
  • experimental-2023-09-20-base
  • experimental-2023-09-27
  • experimental-2023-09-27-base
  • experimental-2023-09-28
  • experimental-2023-09-28-base
  • experimental-2023-09-29
  • experimental-2023-09-29-base
  • experimental-2023-10-02
  • experimental-2023-10-02-base
  • experimental-2023-10-13
  • experimental-2023-10-13-base
  • experimental-2023-10-14
  • experimental-2023-10-14-base
  • experimental-2023-10-16
  • experimental-2023-10-16-base
  • experimental-2023-10-23
  • experimental-2023-10-23-base
137 results

Target

Select target project
  • firmware/gluon
  • 0x4A6F/gluon
  • patrick/gluon
3 results
Select Git revision
  • 0x4A6F-master
  • 0x4A6F-rpi4
  • 2014.3.x
  • 2014.4.x
  • babel
  • hoodselector
  • master
  • radv-filterd
  • v2015.1.x
  • v2016.1.x
  • v2016.2.4-batmanbug
  • v2016.2.x
  • v2018.2.2-ffs
  • v2018.2.x
  • v2014.1
  • v2014.2
  • v2014.3
  • v2014.3.1
  • v2014.4
  • v2015.1
  • v2015.1.1
  • v2015.1.2
  • v2016.1
  • v2016.1.1
  • v2016.1.2
  • v2016.1.3
  • v2016.1.4
  • v2016.1.5
  • v2016.1.6
  • v2016.2
  • v2016.2.1
  • v2016.2.2
  • v2016.2.3
  • v2016.2.4
  • v2016.2.5
  • v2016.2.6
  • v2016.2.7
  • v2017.1
  • v2017.1.1
  • v2017.1.2
  • v2017.1.3
  • v2017.1.4
  • v2017.1.5
  • v2017.1.6
  • v2017.1.7
  • v2017.1.8
  • v2018.1
  • v2018.1.1
  • v2018.1.2
  • v2018.1.3
  • v2018.1.4
  • v2018.2
  • v2018.2-ffs0.1
  • v2018.2.1
  • v2018.2.1-ffs0.1
  • v2018.2.2-ffs0.1
56 results
Show changes
Showing
with 1959 additions and 410 deletions
From: Adrian Schmutzler <freifunk@adrianschmutzler.de>
Date: Fri, 19 Jan 2018 14:45:42 +0100
Subject: ar71xx: Add support for TP-Link CPE210 v2
This PR adds support for a popular low-cost 2.4GHz N based AP
Specifications:
- SoC: Qualcomm Atheros QCA9533 (650MHz)
- RAM: 64MB
- Storage: 8 MB SPI NOR
- Wireless: 2.4GHz N based built into SoC 2x2
- Ethernet: 1x 100/10 Mbps, integrated into SoC, 24V POE IN
Installation:
Flash factory image through stock firmware WEB UI
or through TFTP
To get to TFTP recovery just hold reset button while powering on for
around 4-5 seconds and release.
Rename factory image to recovery.bin
Stock TFTP server IP:192.168.0.100
Stock device TFTP adress:192.168.0.254
Notes:
TP-Link does not use bootstrap registers so without this patch reference
clock detects as 40MHz while it is actually 25MHz.
This is due to messed up bootstrap resistor configuration on the PCB.
Provided GPL code just forces 25MHz reference clock.
That causes booting with completely wrong clocks, for example, CPU tries
to boot at 1040MHz while the stock is 650MHz.
So this PR depends on PR #672 to remove 40MHz reference clock.
Thanks to Sven Eckelmann <sven@narfation.org> for properly patching that.
Signed-off-by: Robert Marko <robimarko@gmail.com>
Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
Origin: backport, https://github.com/openwrt/openwrt/commit/5c5bf8b8658a588423f6ec445d7ef6a36f99a396
diff --git a/target/linux/ar71xx/base-files/etc/board.d/01_leds b/target/linux/ar71xx/base-files/etc/board.d/01_leds
index a742854bc9b0aa48c61b37e58288177bbb56d14d..54046dffc9a4d4ad0216dcda32bf98ee5d38b569 100755
--- a/target/linux/ar71xx/base-files/etc/board.d/01_leds
+++ b/target/linux/ar71xx/base-files/etc/board.d/01_leds
@@ -187,16 +187,25 @@ cf-e530n)
ucidef_set_led_netdev "wan" "WAN" "$board:blue:wan" "eth1"
;;
cpe210|\
+cpe210-v2|\
cpe510|\
wbs210|\
wbs510)
- ucidef_set_led_switch "lan0" "LAN0" "tp-link:green:lan0" "switch0" "0x20"
- ucidef_set_led_switch "lan1" "LAN1" "tp-link:green:lan1" "switch0" "0x10"
ucidef_set_rssimon "wlan0" "200000" "1"
ucidef_set_led_rssi "rssilow" "RSSILOW" "tp-link:green:link1" "wlan0" "1" "100" "0" "13"
ucidef_set_led_rssi "rssimediumlow" "RSSIMEDIUMLOW" "tp-link:green:link2" "wlan0" "26" "100" "-25" "13"
ucidef_set_led_rssi "rssimediumhigh" "RSSIMEDIUMHIGH" "tp-link:green:link3" "wlan0" "51" "100" "-50" "13"
ucidef_set_led_rssi "rssihigh" "RSSIHIGH" "tp-link:green:link4" "wlan0" "76" "100" "-75" "13"
+
+ case "$board" in
+ cpe210-v2)
+ ucidef_set_led_netdev "lan" "LAN" "tp-link:green:lan0" "eth0"
+ ;;
+ *)
+ ucidef_set_led_switch "lan0" "LAN0" "tp-link:green:lan0" "switch0" "0x20"
+ ucidef_set_led_switch "lan1" "LAN1" "tp-link:green:lan1" "switch0" "0x10"
+ ;;
+ esac
;;
cr3000)
ucidef_set_led_netdev "wan" "WAN" "pcs:blue:wan" "eth1"
diff --git a/target/linux/ar71xx/base-files/etc/board.d/02_network b/target/linux/ar71xx/base-files/etc/board.d/02_network
index 875a1a38ada9fb66503505d2f094310db1295a07..633d4e1b7415983f44164187ad3696311ec25621 100755
--- a/target/linux/ar71xx/base-files/etc/board.d/02_network
+++ b/target/linux/ar71xx/base-files/etc/board.d/02_network
@@ -67,6 +67,7 @@ ar71xx_setup_interfaces()
cap4200ag|\
cf-e380ac-v1|\
cf-e380ac-v2|\
+ cpe210-v2|\
eap120|\
eap300v2|\
eap7660d|\
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt b/target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt
index 2449a8d6bce17f0a703d8fc4f82dd38e1f861ae3..35532d86ac3ad32630592c79477c79783af4addb 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt
+++ b/target/linux/ar71xx/files/arch/mips/ath79/Kconfig.openwrt
@@ -1301,6 +1301,7 @@ config ATH79_MACH_ARCHER_C7
config ATH79_MACH_CPE510
bool "TP-LINK CPE510 support"
select SOC_AR934X
+ select SOC_QCA953X
select ATH79_DEV_ETH
select ATH79_DEV_GPIO_BUTTONS
select ATH79_DEV_LEDS_GPIO
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c
index d2dbed1fe286c44d3188262e984253faaee7edba..ceb1769ddd522d51014228fe65e2662f2f3e627c 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c
@@ -1,7 +1,8 @@
/*
- * TP-LINK CPE210/220/510/520 board support
+ * TP-LINK CPE210/210 v2/220/510/520 board support
*
* Copyright (C) 2014 Matthias Schiffer <mschiffer@universe-factory.net>
+ * Copyright (C) 2017 Robert Marko <robimarko@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
@@ -41,6 +42,8 @@
#define CPE510_KEYS_POLL_INTERVAL 20 /* msecs */
#define CPE510_KEYS_DEBOUNCE_INTERVAL (3 * CPE510_KEYS_POLL_INTERVAL)
+/* CPE210 v2 reset GPIO */
+#define CPE210_V2_GPIO_BTN_RESET 17
static struct gpio_led cpe510_leds_gpio[] __initdata = {
{
@@ -98,6 +101,30 @@ static struct gpio_led wbs510_leds_gpio[] __initdata = {
},
};
+static struct gpio_led cpe210_v2_leds_gpio[] __initdata = {
+ {
+ .name = "tp-link:green:lan0",
+ .gpio = CPE510_GPIO_LED_LAN0,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:link1",
+ .gpio = CPE510_GPIO_LED_L1,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:link2",
+ .gpio = CPE510_GPIO_LED_L2,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:link3",
+ .gpio = CPE510_GPIO_LED_L3,
+ .active_low = 1,
+ }, {
+ .name = "tp-link:green:link4",
+ .gpio = CPE510_GPIO_LED_L4,
+ .active_low = 1,
+ },
+};
+
static struct gpio_keys_button cpe510_gpio_keys[] __initdata = {
{
.desc = "Reset button",
@@ -109,6 +136,17 @@ static struct gpio_keys_button cpe510_gpio_keys[] __initdata = {
}
};
+static struct gpio_keys_button cpe210_v2_gpio_keys[] __initdata = {
+ {
+ .desc = "Reset button",
+ .type = EV_KEY,
+ .code = KEY_RESTART,
+ .debounce_interval = CPE510_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = CPE210_V2_GPIO_BTN_RESET,
+ .active_low = 1,
+ }
+};
+
static void __init cpe_setup(u8 *mac)
{
/* Disable JTAG, enabling GPIOs 0-3 */
@@ -171,9 +209,33 @@ static void __init wbs_setup(void)
ath79_register_wmac(ee, mac);
}
+static void __init cpe210_v2_setup(void)
+{
+ u8 *mac = (u8 *) KSEG1ADDR(0x1f830008);
+ u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(cpe210_v2_leds_gpio),
+ cpe210_v2_leds_gpio);
+ ath79_register_gpio_keys_polled(-1, CPE510_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(cpe210_v2_gpio_keys),
+ cpe210_v2_gpio_keys);
+ ath79_register_m25p80(NULL);
+ ath79_register_mdio(0, 0x0);
+ ath79_init_mac(ath79_eth0_data.mac_addr, mac, 0);
+ ath79_eth0_data.duplex = DUPLEX_FULL;
+ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+ ath79_eth0_data.speed = SPEED_100;
+ ath79_eth0_data.phy_mask = BIT(4);
+ ath79_register_eth(0);
+ ath79_register_wmac(ee, mac);
+}
+
MIPS_MACHINE(ATH79_MACH_CPE210, "CPE210", "TP-LINK CPE210/220",
cpe210_setup);
+MIPS_MACHINE(ATH79_MACH_CPE210_V2, "CPE210V2", "TP-LINK CPE210 v2",
+ cpe210_v2_setup);
+
MIPS_MACHINE(ATH79_MACH_CPE510, "CPE510", "TP-LINK CPE510/520",
cpe510_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/machtypes.h b/target/linux/ar71xx/files/arch/mips/ath79/machtypes.h
index a4c7f52fe94e17bc48bebfb460f12f3e5ac35afe..e7e7f94775a3122286dc39447f04b42f4863f313 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/machtypes.h
+++ b/target/linux/ar71xx/files/arch/mips/ath79/machtypes.h
@@ -64,7 +64,8 @@ enum ath79_mach_type {
ATH79_MACH_CF_E380AC_V2, /* COMFAST CF-E380AC v2 */
ATH79_MACH_CF_E520N, /* COMFAST CF-E520N */
ATH79_MACH_CF_E530N, /* COMFAST CF-E530N */
- ATH79_MACH_CPE210, /* TP-LINK CPE210 */
+ ATH79_MACH_CPE210, /* TP-LINK CPE210 v1 */
+ ATH79_MACH_CPE210_V2, /* TP-LINK CPE210 v2 */
ATH79_MACH_CPE510, /* TP-LINK CPE510 */
ATH79_MACH_CPE830, /* YunCore CPE830 */
ATH79_MACH_CPE870, /* YunCore CPE870 */
diff --git a/target/linux/ar71xx/image/tp-link.mk b/target/linux/ar71xx/image/tp-link.mk
index 6a3faef518ebfa4f36d3074ee9c102b801e04275..b61ef6dc78918dd8d040c0f2bfb6451e5e13ba92 100644
--- a/target/linux/ar71xx/image/tp-link.mk
+++ b/target/linux/ar71xx/image/tp-link.mk
@@ -164,22 +164,26 @@ define Device/archer-c60-v1
endef
TARGET_DEVICES += archer-c60-v1
-define Device/cpe510-520
- DEVICE_TITLE := TP-LINK CPE510/520
+define Device/cpexxx
DEVICE_PACKAGES := rssileds
MTDPARTS := spi0.0:128k(u-boot)ro,64k(partition-table)ro,64k(product-info)ro,1792k(kernel),5888k(rootfs),192k(config)ro,64k(ART)ro,7680k@0x40000(firmware)
IMAGE_SIZE := 7680k
- BOARDNAME := CPE510
- TPLINK_BOARD_NAME := CPE510
DEVICE_PROFILE := CPE510
LOADER_TYPE := elf
+ IMAGES := sysupgrade.bin factory.bin
+ IMAGE/sysupgrade.bin := append-rootfs | tplink-safeloader sysupgrade
+ IMAGE/factory.bin := append-rootfs | tplink-safeloader factory
+endef
+
+define Device/cpe510-520
+ $(Device/cpexxx)
+ DEVICE_TITLE := TP-LINK CPE510/520 v1
+ BOARDNAME := CPE510
+ TPLINK_BOARD_NAME := CPE510
LOADER_FLASH_OFFS := 0x43000
COMPILE := loader-$(1).elf
COMPILE/loader-$(1).elf := loader-okli-compile
KERNEL := kernel-bin | lzma | uImage lzma -M 0x4f4b4c49 | loader-okli $(1) 12288
- IMAGES := sysupgrade.bin factory.bin
- IMAGE/sysupgrade.bin := append-rootfs | tplink-safeloader sysupgrade
- IMAGE/factory.bin := append-rootfs | tplink-safeloader factory
endef
define Device/cpe210-220
@@ -190,6 +194,19 @@ $(Device/cpe510-520)
TPLINK_BOARD_NAME := CPE210
endef
+define Device/cpe210-v2
+ $(Device/cpexxx)
+ DEVICE_TITLE := TP-LINK CPE210 v2
+ BOARDNAME := CPE210V2
+ TPLINK_BOARD_NAME := CPE210V2
+ KERNEL := kernel-bin | patch-cmdline | lzma | mktplinkfw-combined
+ TPLINK_HWID := 0x0
+ TPLINK_HWREV := 0
+ TPLINK_HEADER_VERSION := 1
+ TPLINK_FLASHLAYOUT := 8Mlzma
+endef
+TARGET_DEVICES += cpe210-v2
+
define Device/wbs210
$(Device/cpe510-520)
DEVICE_TITLE := TP-LINK WBS210
diff --git a/tools/firmware-utils/src/tplink-safeloader.c b/tools/firmware-utils/src/tplink-safeloader.c
index 23b69f3bd0eb66aca650eb2ffd7d5cd2a7cb5194..e6ecc5b2c52c1627c8b998fa731b50ed39649f96 100644
--- a/tools/firmware-utils/src/tplink-safeloader.c
+++ b/tools/firmware-utils/src/tplink-safeloader.c
@@ -154,6 +154,48 @@ static struct device_info boards[] = {
.last_sysupgrade_partition = "support-list",
},
+ /** Firmware layout for the CPE210 V2 */
+ {
+ .id = "CPE210V2",
+ .vendor = "CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n",
+ .support_list =
+ "SupportList:\r\n"
+ "CPE210(TP-LINK|EU|N300-2|00000000):2.0\r\n"
+ "CPE210(TP-LINK|EU|N300-2|45550000):2.0\r\n"
+ "CPE210(TP-LINK|EU|N300-2|55530000):2.0\r\n"
+ "CPE210(TP-LINK|UN|N300-2|00000000):2.0\r\n"
+ "CPE210(TP-LINK|UN|N300-2|45550000):2.0\r\n"
+ "CPE210(TP-LINK|UN|N300-2|55530000):2.0\r\n"
+ "CPE210(TP-LINK|US|N300-2|55530000):2.0\r\n"
+ "CPE210(TP-LINK|UN|N300-2):2.0\r\n"
+ "CPE210(TP-LINK|EU|N300-2):2.0\r\n"
+ "CPE210(TP-LINK|US|N300-2):2.0\r\n",
+ .support_trail = '\xff',
+ .soft_ver = NULL,
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x20000},
+ {"partition-table", 0x20000, 0x02000},
+ {"default-mac", 0x30000, 0x00020},
+ {"product-info", 0x31100, 0x00100},
+ {"device-info", 0x31400, 0x00400},
+ {"signature", 0x32000, 0x00400},
+ {"device-id", 0x33000, 0x00100},
+ {"os-image", 0x40000, 0x1c0000},
+ {"file-system", 0x200000, 0x5b0000},
+ {"soft-version", 0x7b0000, 0x00100},
+ {"support-list", 0x7b1000, 0x01000},
+ {"user-config", 0x7c0000, 0x10000},
+ {"default-config", 0x7d0000, 0x10000},
+ {"log", 0x7e0000, 0x10000},
+ {"radio", 0x7f0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "support-list",
+ },
+
/** Firmware layout for the CPE510/520 */
{
.id = "CPE510",
From: David Bauer <mail@david-bauer.net>
Date: Fri, 8 Jun 2018 21:42:52 +0200
Subject: ar71xx: use Power-LED as Diag-LED on FRITZBox 4020
This commit makes use of the Power-LED as Diag-LED, allowing the LED to
work as a status indicator.
Signed-off-by: David Bauer <mail@david-bauer.net>
diff --git a/target/linux/ar71xx/base-files/etc/board.d/01_leds b/target/linux/ar71xx/base-files/etc/board.d/01_leds
index 54046dffc9a4d4ad0216dcda32bf98ee5d38b569..e163e3171a747c3756c376c4a92b1bc50baa8eaa 100755
--- a/target/linux/ar71xx/base-files/etc/board.d/01_leds
+++ b/target/linux/ar71xx/base-files/etc/board.d/01_leds
@@ -315,7 +315,6 @@ dlan-pro-1200-ac)
ucidef_set_led_gpio "plcr" "dLAN" "devolo:error:dlan" "16" "0"
;;
fritz4020)
- ucidef_set_led_default "power" "Power" "$board:green:power" "1"
ucidef_set_led_netdev "lan" "LAN" "$board:green:lan" "eth1"
ucidef_set_led_netdev "wan" "WAN" "$board:green:wan" "eth0"
ucidef_set_led_wlan "wlan" "WLAN" "$board:green:wlan" "phy0tpt"
diff --git a/target/linux/ar71xx/base-files/etc/diag.sh b/target/linux/ar71xx/base-files/etc/diag.sh
index f8d2eb314f7b57a1134b68c504c0dac202ed947c..8002e9702720a431dd38c598cb8f1f3284d3af1c 100644
--- a/target/linux/ar71xx/base-files/etc/diag.sh
+++ b/target/linux/ar71xx/base-files/etc/diag.sh
@@ -55,6 +55,7 @@ get_status_led() {
archer-c58-v1|\
archer-c59-v1|\
archer-c60-v1|\
+ fritz4020|\
mr12|\
mr16|\
nbg6616|\
......@@ -4,10 +4,10 @@ Subject: procd: add support for alternative rc.d directories
diff --git a/package/system/procd/patches/0001-Add-support-for-alternative-rc.d-directories.patch b/package/system/procd/patches/0001-Add-support-for-alternative-rc.d-directories.patch
new file mode 100644
index 0000000000000000000000000000000000000000..bc2434200364b46f1db4c2eec22c4e8b973844d5
index 0000000000000000000000000000000000000000..16d3179f05c64b7178f883745294c64a27127775
--- /dev/null
+++ b/package/system/procd/patches/0001-Add-support-for-alternative-rc.d-directories.patch
@@ -0,0 +1,97 @@
@@ -0,0 +1,80 @@
+From 03a2bc70e4260ec9f669391c47b9a7a9ecd0b75d Mon Sep 17 00:00:00 2001
+Message-Id: <03a2bc70e4260ec9f669391c47b9a7a9ecd0b75d.1407329621.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
......@@ -19,21 +19,10 @@ index 0000000000000000000000000000000000000000..bc2434200364b46f1db4c2eec22c4e8b
+ rcS.c | 2 +-
+ 2 files changed, 39 insertions(+), 1 deletion(-)
+
+diff --git a/initd/preinit.c b/initd/preinit.c
+index fb94527..8b832a7 100644
+--- a/initd/preinit.c
++++ b/initd/preinit.c
+@@ -12,6 +12,8 @@
+ * GNU General Public License for more details.
+ */
+
++#define _GNU_SOURCE
++
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ #include <sys/mount.h>
+@@ -46,6 +48,35 @@ check_dbglvl(void)
+ debug = lvl;
+@@ -87,12 +87,42 @@ fail:
+ free(command);
+ }
+
++static char*
......@@ -68,15 +57,14 @@ index 0000000000000000000000000000000000000000..bc2434200364b46f1db4c2eec22c4e8b
+ static void
+ spawn_procd(struct uloop_process *proc, int ret)
+ {
+@@ -53,6 +84,7 @@ spawn_procd(struct uloop_process *proc, int ret)
+ char *wdt_fd = watchdog_fd();
+ char *argv[] = { "/sbin/procd", NULL};
+ struct stat s;
+ char dbg[2];
++ char *rc_d_path;
+
+ if (plugd_proc.pid > 0)
+ kill(plugd_proc.pid, SIGKILL);
+@@ -72,6 +104,12 @@ spawn_procd(struct uloop_process *proc, int ret)
+@@ -112,6 +142,12 @@ spawn_procd(struct uloop_process *proc,
+ setenv("DBGLVL", dbg, 1);
+ }
+
......@@ -89,11 +77,9 @@ index 0000000000000000000000000000000000000000..bc2434200364b46f1db4c2eec22c4e8b
+ execvp(argv[0], argv);
+ }
+
+diff --git a/rcS.c b/rcS.c
+index 0e1b0ba..1b00831 100644
+--- a/rcS.c
++++ b/rcS.c
+@@ -150,7 +150,7 @@ int rcS(char *pattern, char *param, void (*q_empty)(struct runqueue *))
+@@ -184,7 +184,7 @@ int rcS(char *pattern, char *param, void
+ q.empty_cb = q_empty;
+ q.max_running_tasks = 1;
+
......@@ -102,6 +88,3 @@ index 0000000000000000000000000000000000000000..bc2434200364b46f1db4c2eec22c4e8b
+ }
+
+ int rc(const char *file, char *param)
+--
+2.0.4
+
......@@ -6,24 +6,13 @@ Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
diff --git a/package/network/services/dropbear/patches/700-failsafe-mode.patch b/package/network/services/dropbear/patches/700-failsafe-mode.patch
new file mode 100644
index 0000000000000000000000000000000000000000..d379da0d0a7890e0a25d87e227c2e065cd2750ee
index 0000000000000000000000000000000000000000..9b619ce80b2963c67ac62bcf95b33b28b505ad2a
--- /dev/null
+++ b/package/network/services/dropbear/patches/700-failsafe-mode.patch
@@ -0,0 +1,57 @@
+--- a/runopts.h
++++ b/runopts.h
+@@ -98,6 +98,8 @@ typedef struct svr_runopts {
+ int allowblankpass;
+ unsigned int maxauthtries;
+
++ int failsafe_mode;
++
+ #ifdef ENABLE_SVR_REMOTETCPFWD
+ int noremotetcp;
+ #endif
+--- a/svr-auth.c
++++ b/svr-auth.c
+@@ -149,10 +149,11 @@ void recv_msg_userauth_request() {
+--- a/src/svr-auth.c
++++ b/src/svr-auth.c
+@@ -124,10 +124,11 @@ void recv_msg_userauth_request() {
+ AUTH_METHOD_NONE_LEN) == 0) {
+ TRACE(("recv_msg_userauth_request: 'none' request"))
+ if (valid_user
......@@ -39,31 +28,42 @@ index 0000000000000000000000000000000000000000..d379da0d0a7890e0a25d87e227c2e065
+ {
+ dropbear_log(LOG_NOTICE,
+ "Auth succeeded with blank password for '%s' from %s",
+--- a/svr-runopts.c
++++ b/svr-runopts.c
+@@ -72,6 +72,7 @@ static void printhelp(const char * progn
+--- a/src/svr-runopts.c
++++ b/src/svr-runopts.c
+@@ -82,6 +82,7 @@ static void printhelp(const char * progn
+ "-s Disable password logins\n"
+ "-g Disable password logins for root\n"
+ "-B Allow blank password logins\n"
++ "-f Failsafe mode: always allow password-less root login\n"
+ "-t Enable two-factor authentication (both password and public key required)\n"
+ #endif
+ "-T <1 to %d> Maximum authentication tries (default %d)\n"
+ #ifdef ENABLE_SVR_LOCALTCPFWD
+@@ -133,6 +134,7 @@ void svr_getopts(int argc, char ** argv)
+ "-T Maximum authentication tries (default %d)\n"
+@@ -166,6 +167,7 @@ void svr_getopts(int argc, char ** argv)
+ svr_opts.noauthpass = 0;
+ svr_opts.norootpass = 0;
+ svr_opts.allowblankpass = 0;
++ svr_opts.failsafe_mode = 0;
+ svr_opts.maxauthtries = DEFAULT_AUTH_TRIES;
+ svr_opts.multiauthmethod = 0;
+ svr_opts.maxauthtries = MAX_AUTH_TRIES;
+ svr_opts.inetdmode = 0;
+ svr_opts.portcount = 0;
+@@ -251,6 +253,9 @@ void svr_getopts(int argc, char ** argv)
+ case 'B':
+ svr_opts.allowblankpass = 1;
+@@ -263,6 +265,9 @@ void svr_getopts(int argc, char ** argv)
+ case '2':
+ next = &reexec_fd_arg;
+ break;
++ case 'f':
++ svr_opts.failsafe_mode = 1;
++ break;
+ #endif
+ case 'h':
+ printhelp(argv[0]);
+ case 'p':
+ nextisport = 1;
+--- a/src/runopts.h
++++ b/src/runopts.h
+@@ -110,6 +110,8 @@ typedef struct svr_runopts {
+ int multiauthmethod;
+ unsigned int maxauthtries;
+
++ int failsafe_mode;
++
+ #if DROPBEAR_SVR_REMOTETCPFWD
+ int noremotetcp;
+ #endif
From: Matthias Schiffer <mschiffer@universe-factory.net>
Date: Sun, 30 Mar 2025 13:16:02 +0200
Subject: HACK: opkg: do not preserve opkg keys on upgrades by default
Custom keys can still be preserved by listing them in sysupgrade.conf.
Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
diff --git a/package/system/opkg/Makefile b/package/system/opkg/Makefile
index e7c45e3523135a6cc35385a81c65cf2831b842bb..fc5ec6a7ed1eb559a478b00b03102fbccd543c57 100644
--- a/package/system/opkg/Makefile
+++ b/package/system/opkg/Makefile
@@ -56,7 +56,6 @@ endef
define Package/opkg/conffiles
/etc/opkg.conf
-/etc/opkg/keys/
/etc/opkg/customfeeds.conf
endef
From: Linus Lüssing <linus.luessing@c0d3.blue>
Date: Sat, 1 Jan 2022 10:09:13 +0100
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..077a563b6066cd1d3aee4b1e82328e8cc5e042ea
--- /dev/null
+++ b/package/network/config/netifd/patches/0001-bridge-Add-multicast_wakeupcall-option.patch
@@ -0,0 +1,142 @@
+From d23a49e6542dc068b12fbc7b6a4520f9fb3626f9 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 | 3 +++
+ system-linux.c | 13 +++++++++++++
+ 3 files changed, 25 insertions(+)
+
+--- a/device.c
++++ b/device.c
+@@ -49,6 +49,7 @@ static const struct blobmsg_policy dev_a
+ [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 },
+@@ -275,6 +276,7 @@ device_merge_settings(struct device *dev
+ 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;
+@@ -449,6 +451,11 @@ device_init_settings(struct device *dev,
+ 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)
+@@ -1372,6 +1379,8 @@ device_dump_status(struct blob_buf *b, s
+ 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)
+--- a/device.h
++++ b/device.h
+@@ -44,6 +44,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,
+@@ -144,6 +145,7 @@ enum {
+ DEV_OPT_GRO = (1ULL << 37),
+ DEV_OPT_MASTER = (1ULL << 38),
+ DEV_OPT_EEE = (1ULL << 39),
++ DEV_OPT_MULTICAST_WAKEUPCALL = (1ULL << 63),
+ };
+
+ /* events broadcasted to all users of a device */
+@@ -205,6 +207,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;
+--- a/system-linux.c
++++ b/system-linux.c
+@@ -536,6 +536,11 @@ static void system_bridge_set_multicast_
+ system_set_dev_sysfs("brport/multicast_to_unicast", dev->ifname, val);
+ }
+
++static void system_bridge_set_multicast_wakeupcall(struct device *dev, const char *val)
++{
++ system_set_dev_sysfs("brport/multicast_wakeupcall", dev->ifname, val);
++}
++
+ static void system_bridge_set_multicast_fast_leave(struct device *dev, const char *val)
+ {
+ system_set_dev_sysfs("brport/multicast_fast_leave", dev->ifname, val);
+@@ -923,8 +928,10 @@ static char *system_get_bridge(const cha
+ 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;
++ char buf[64];
+
+ if (dev->settings.flags & DEV_OPT_MULTICAST_TO_UNICAST)
+ mcast_to_ucast = dev->settings.multicast_to_unicast;
+@@ -939,6 +946,12 @@ system_bridge_set_wireless(struct device
+ system_bridge_set_multicast_to_unicast(dev, mcast_to_ucast ? "1" : "0");
+ system_bridge_set_hairpin_mode(dev, hairpin ? "1" : "0");
+ system_bridge_set_proxyarp_wifi(dev, dev->wireless_proxyarp ? "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)
diff --git a/target/linux/generic/config-6.6 b/target/linux/generic/config-6.6
index 46283ac3bd818d3b39ad8c57262bba101efff753..da3956c0fa55bd0b9c8ae3edacd28286066f357e 100644
--- a/target/linux/generic/config-6.6
+++ b/target/linux/generic/config-6.6
@@ -716,6 +716,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_MRP is not set
# CONFIG_BRIDGE_NETFILTER is not set
# CONFIG_BRIDGE_NF_EBTABLES is not set
diff --git a/target/linux/generic/hack-6.6/602-bridge-Implement-MLD-Querier-wake-up-calls-Android-b.patch b/target/linux/generic/hack-6.6/602-bridge-Implement-MLD-Querier-wake-up-calls-Android-b.patch
new file mode 100644
index 0000000000000000000000000000000000000000..5a54131fab24f9cfaa9c51d51b3163bd2ecaf4c3
--- /dev/null
+++ b/target/linux/generic/hack-6.6/602-bridge-Implement-MLD-Querier-wake-up-calls-Android-b.patch
@@ -0,0 +1,690 @@
+From 9734fac17903cc0c67c63361525cc99f793fd6d7 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/net/addrconf.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 | 291 ++++++++++++++++++++++++++++++++++-
+ net/bridge/br_netlink.c | 19 +++
+ net/bridge/br_private.h | 20 +++
+ net/bridge/br_sysfs_if.c | 18 +++
+ net/core/rtnetlink.c | 2 +-
+ net/ipv6/mcast_snoop.c | 3 +-
+ 12 files changed, 386 insertions(+), 10 deletions(-)
+
+diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
+index cff03a1dfd68..70b6f74653d0 100644
+--- a/include/linux/if_bridge.h
++++ b/include/linux/if_bridge.h
+@@ -62,6 +62,7 @@ struct br_ip_list {
+ #define BR_PORT_MAB BIT(22)
+ #define BR_NEIGH_VLAN_SUPPRESS BIT(23)
+ #define BR_BPDU_FILTER BIT(24)
++#define BR_MULTICAST_WAKEUPCALL BIT(25)
+
+ #define BR_DEFAULT_AGEING_TIME (300 * HZ)
+
+diff --git a/include/net/addrconf.h b/include/net/addrconf.h
+index facb7a469efa..817a33d1c055 100644
+--- a/include/net/addrconf.h
++++ b/include/net/addrconf.h
+@@ -243,6 +243,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 sk_buff *skb, struct inet6_ifaddr *ifp);
+
+diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
+index b29417908271..88b1c8a19bb4 100644
+--- a/include/uapi/linux/if_link.h
++++ b/include/uapi/linux/if_link.h
+@@ -572,6 +572,7 @@ enum {
+ IFLA_BRPORT_NEIGH_VLAN_SUPPRESS,
+ IFLA_BRPORT_BACKUP_NHID,
+ IFLA_BRPORT_BPDU_FILTER,
++ 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 3c8ded7d3e84..1a11e22c7d51 100644
+--- a/net/bridge/Kconfig
++++ b/net/bridge/Kconfig
+@@ -48,6 +48,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 a6d8cd9a5807..b70426806d45 100644
+--- a/net/bridge/br_fdb.c
++++ b/net/bridge/br_fdb.c
+@@ -80,6 +80,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);
+ }
+
+@@ -400,6 +404,12 @@ static struct net_bridge_fdb_entry *fdb_create(struct net_bridge *br,
+ fdb->key.vlan_id = vid;
+ fdb->flags = flags;
+ fdb->updated = fdb->used = jiffies;
++
++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
++ timer_setup(&fdb->wakeupcall_timer,
++ br_multicast_send_wakeupcall, 0);
++#endif
++
+ err = rhashtable_lookup_insert_fast(&br->fdb_hash_tbl, &fdb->rhnode,
+ br_fdb_rht_params);
+ if (err) {
+diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
+index 4540c76d6079..d4644aab7dbf 100644
+--- a/net/bridge/br_input.c
++++ b/net/bridge/br_input.c
+@@ -204,8 +204,10 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
+ if (dst) {
+ unsigned long now = jiffies;
+
+- if (test_bit(BR_FDB_LOCAL, &dst->flags))
++ if (test_bit(BR_FDB_LOCAL, &dst->flags)) {
++ br_multicast_wakeupcall_rcv(brmctx, pmctx, skb, vid);
+ return br_pass_frame_up(skb, false);
++ }
+
+ if (now != dst->used)
+ dst->used = now;
+diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
+index c38244d60ff8..df3a4d4dbb8f 100644
+--- a/net/bridge/br_multicast.c
++++ b/net/bridge/br_multicast.c
+@@ -1076,15 +1076,16 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge_mcast *brm
+ const struct in6_addr *group,
+ bool with_srcs, bool over_llqt,
+ u8 sflag, u8 *igmp_type,
+- bool *need_rexmit)
++ bool *need_rexmit,
++ bool delay)
+ {
+ struct net_bridge_port *p = pg ? pg->key.port : NULL;
+ struct net_bridge_group_src *ent;
+ size_t pkt_size, mld_hdr_size;
+ unsigned long now = jiffies;
++ unsigned long interval = 0;
+ struct mld2_query *mld2q;
+ void *csum_start = NULL;
+- unsigned long interval;
+ __sum16 *csum = NULL;
+ struct ipv6hdr *ip6h;
+ struct mld_msg *mldq;
+@@ -1166,9 +1167,13 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge_mcast *brm
+
+ /* ICMPv6 */
+ skb_set_transport_header(skb, skb->len);
+- interval = ipv6_addr_any(group) ?
+- brmctx->multicast_query_response_interval :
+- brmctx->multicast_last_member_interval;
++ if (delay) {
++ interval = ipv6_addr_any(group) ?
++ brmctx->multicast_query_response_interval :
++ brmctx->multicast_last_member_interval;
++ interval = jiffies_to_msecs(interval);
++ }
++
+ *igmp_type = ICMPV6_MGM_QUERY;
+ switch (brmctx->multicast_mld_version) {
+ case 1:
+@@ -1176,7 +1181,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge_mcast *brm
+ 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 = *group;
+ csum = &mldq->mld_cksum;
+@@ -1267,7 +1272,7 @@ static struct sk_buff *br_multicast_alloc_query(struct net_bridge_mcast *brmctx,
+ &ip6_dst, &group->dst.ip6,
+ with_srcs, over_lmqt,
+ sflag, igmp_type,
+- need_rexmit);
++ need_rexmit, true);
+ }
+ #endif
+ }
+@@ -1777,6 +1782,169 @@ static void br_multicast_select_own_querier(struct net_bridge_mcast *brmctx,
+ #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->key.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_mcast *brmctx,
++ struct net_bridge_mcast_port *pmctx,
++ const struct in6_addr *group)
++{
++ struct net_bridge_fdb_entry *fdb;
++ unsigned long delay;
++
++ rcu_read_lock();
++ hlist_for_each_entry_rcu(fdb, &brmctx->br->fdb_list, fdb_node) {
++ if (!fdb->dst || fdb->dst->dev != pmctx->port->dev)
++ continue;
++
++ /* Wake-up calls to VLANs unsupported for now */
++ if (fdb->key.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) ?
++ brmctx->multicast_query_response_interval :
++ brmctx->multicast_last_member_interval;
++ delay = get_random_u32_below(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_mcast *brmctx,
+ struct net_bridge_mcast_port *pmctx,
+ struct net_bridge_port_group *pg,
+@@ -1809,6 +1977,13 @@ static void __br_multicast_send_query(struct net_bridge_mcast *brmctx,
+ dev_net(pmctx->port->dev), NULL, skb, NULL, skb->dev,
+ br_dev_queue_push_xmit);
+
++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
++ if (pmctx->port->wakeupcall_num_rings &&
++ group->proto == htons(ETH_P_IPV6))
++ br_multicast_schedule_wakeupcalls(brmctx, pmctx,
++ &group->dst.ip6);
++#endif
++
+ if (over_lmqt && with_srcs && sflag) {
+ over_lmqt = false;
+ goto again_under_lmqt;
+@@ -3976,6 +4151,99 @@ int br_multicast_rcv(struct net_bridge_mcast **brmctx,
+ 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_mcast *brmctx,
++ struct net_bridge_mcast_port *pmctx,
++ const u8 *eth_dst)
++{
++ const struct in6_addr group = BR_MC_IN6_ZERO;
++ struct in6_addr ip6_dst;
++ 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
++ */
++ ipv6_addr_set(&ip6_dst, htonl(0xff020000), 0, 0, htonl(1));
++
++ skb = br_ip6_multicast_alloc_query(brmctx, pmctx, NULL, &ip6_dst,
++ &group, false, false, false,
++ &igmp_type, NULL, false);
++ if (!skb)
++ return;
++
++ skb->dev = pmctx->port->dev;
++ ether_addr_copy(eth_hdr(skb)->h_dest, eth_dst);
++
++ br_multicast_count(brmctx->br, pmctx->port, skb, igmp_type,
++ BR_MCAST_DIR_TX);
++ NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT,
++ dev_net(pmctx->port->dev), NULL, skb, NULL, skb->dev,
++ br_dev_queue_push_xmit);
++}
++
++void br_multicast_wakeupcall_rcv(struct net_bridge_mcast *brmctx,
++ struct net_bridge_mcast_port *pmctx,
++ struct sk_buff *skb, u16 vid)
++{
++ if (!br_multicast_wakeupcall_check(brmctx->br, pmctx->port, skb, vid))
++ return;
++
++ br_multicast_wakeupcall_send_mldq(brmctx, pmctx,
++ eth_hdr(skb)->h_source);
++}
++
++#endif /* CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS */
++
+ static void br_multicast_query_expired(struct net_bridge_mcast *brmctx,
+ struct bridge_mcast_own_query *query,
+ struct bridge_mcast_querier *querier)
+@@ -4504,6 +4772,15 @@ int br_multicast_set_vlan_router(struct net_bridge_vlan *v, u8 mcast_router)
+ 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_mcast *brmctx,
+ struct bridge_mcast_own_query *query)
+ {
+diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
+index a760d5a5ad12..8fdabad8e10a 100644
+--- a/net/bridge/br_netlink.c
++++ b/net/bridge/br_netlink.c
+@@ -206,6 +206,9 @@ static inline size_t br_port_info_size(void)
+ + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MULTICAST_ROUTER */
+ + nla_total_size(sizeof(u32)) /* IFLA_BRPORT_MCAST_N_GROUPS */
+ + nla_total_size(sizeof(u32)) /* IFLA_BRPORT_MCAST_MAX_GROUPS */
++#endif
++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
++ + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MCAST_WAKEUPCALL */
+ #endif
+ + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_GROUP_FWD_MASK */
+ + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MRP_RING_OPEN */
+@@ -313,6 +316,11 @@ static int br_port_fill_attrs(struct sk_buff *skb,
+ br_multicast_ngroups_get_max(&p->multicast_ctx)))
+ 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
+
+ /* we might be called only with br->lock */
+ rcu_read_lock();
+@@ -890,6 +898,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_VLAN_TUNNEL] = { .type = NLA_U8 },
+@@ -1051,6 +1060,16 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[],
+ }
+ #endif
+
++#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
++
+ if (tb[IFLA_BRPORT_GROUP_FWD_MASK]) {
+ u16 fwd_mask = nla_get_u16(tb[IFLA_BRPORT_GROUP_FWD_MASK]);
+
+diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
+index 72d80fd943a8..b237c39edd35 100644
+--- a/net/bridge/br_private.h
++++ b/net/bridge/br_private.h
+@@ -294,6 +294,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
+ };
+
+ struct net_bridge_fdb_flush_desc {
+@@ -417,6 +421,7 @@ struct net_bridge_port {
+ u32 multicast_eht_hosts_limit;
+ u32 multicast_eht_hosts_cnt;
+ struct hlist_head mglist;
++ u8 wakeupcall_num_rings;
+ #endif
+
+ #ifdef CONFIG_SYSFS
+@@ -1504,6 +1509,21 @@ br_multicast_ctx_options_equal(const struct net_bridge_mcast *brmctx1,
+ }
+ #endif
+
++#ifdef CONFIG_BRIDGE_IGMP_SNOOPING_WAKEUPCALLS
++void br_multicast_wakeupcall_rcv(struct net_bridge_mcast *brmctx,
++ struct net_bridge_mcast_port *pmctx,
++ 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_mcast *brmctx,
++ struct net_bridge_mcast_port *pmctx,
++ 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 aee7c5902206..15ee27e1aa72 100644
+--- a/net/bridge/br_sysfs_if.c
++++ b/net/bridge/br_sysfs_if.c
+@@ -260,6 +260,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,
+@@ -285,6 +300,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,
+diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
+index 71797d44af4c..abe17f8c4939 100644
+--- a/net/core/rtnetlink.c
++++ b/net/core/rtnetlink.c
+@@ -61,7 +61,7 @@
+ #include "dev.h"
+
+ #define RTNL_MAX_TYPE 50
+-#define RTNL_SLAVE_MAX_TYPE 45
++#define RTNL_SLAVE_MAX_TYPE 46
+
+ struct rtnl_link {
+ rtnl_doit_func doit;
+diff --git a/net/ipv6/mcast_snoop.c b/net/ipv6/mcast_snoop.c
+index 04d5fcdfa6e0..9a5061edbaf3 100644
+--- a/net/ipv6/mcast_snoop.c
++++ b/net/ipv6/mcast_snoop.c
+@@ -131,7 +131,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);
+@@ -150,6 +150,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.45.2
+
From: David Bauer <mail@david-bauer.net>
Date: Thu, 18 Jan 2024 00:52:09 +0100
Subject: mac80211: silence warning for missing rate information
Silence warnings for missing rate information.
These warnings do not provide value. Instead, they might rotate more
crucial information out of the kernel message ringbuffer.
Link: https://github.com/freifunk-gluon/gluon/issues/3160
Signed-off-by: David Bauer <mail@david-bauer.net>
diff --git a/package/kernel/mac80211/patches/subsys/999-silence-missing-rate.patch b/package/kernel/mac80211/patches/subsys/999-silence-missing-rate.patch
new file mode 100644
index 0000000000000000000000000000000000000000..a34455f78960ded59b60d3d9600823b39fc7b7a2
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/999-silence-missing-rate.patch
@@ -0,0 +1,11 @@
+--- a/net/mac80211/mesh_hwmp.c
++++ b/net/mac80211/mesh_hwmp.c
+@@ -350,7 +350,7 @@ u32 airtime_link_metric_get(struct ieee8
+ return MAX_METRIC;
+
+ rate = ewma_mesh_tx_rate_avg_read(&sta->mesh->tx_rate_avg);
+- if (WARN_ON(!rate))
++ if (!rate)
+ return MAX_METRIC;
+
+ err = (fail_avg << ARITH_SHIFT) / 100;
From: David Bauer <mail@david-bauer.net>
Date: Mon, 6 Jan 2025 08:30:35 +0100
Subject: net: mac80211: override incompatible basic-rates for mesh
This is a dirty hack for Gluon.
We assume basic rate setup only affects the rate-controller on the TX
side. As all devices we support have at least a 802.11n radio and thus
cover 802.11b as well as 802.11g on 2.4 GHz, they are compatible with
each other.
As the basic rate was incorrectly set for mesh interfaces in the past,
connections between mesh neighbors would fail when altering the basic
rate.
This patch ignores mismatches in the basic-rate field. By doing so, we
avoid implementing some sort of scheduled switch between wireless
configurations.
Signed-off-by: David Bauer <mail@david-bauer.net>
diff --git a/package/kernel/mac80211/patches/subsys/995-net-mac80211-override-incompatible-basic-rates-for-m.patch b/package/kernel/mac80211/patches/subsys/995-net-mac80211-override-incompatible-basic-rates-for-m.patch
new file mode 100644
index 0000000000000000000000000000000000000000..efcf0b4f041bb21184e9cd997bc6caca4729a1fe
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/995-net-mac80211-override-incompatible-basic-rates-for-m.patch
@@ -0,0 +1,37 @@
+From 091e1eea9e34db7cbf84379021fcbff82887e09a Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Mon, 6 Jan 2025 08:23:54 +0100
+Subject: [PATCH] net: mac80211: override incompatible basic-rates for mesh
+
+This is a dirty hack for Gluon.
+
+We assume basic rate setup only affects the rate-controller on the TX
+side. As all devices we support have at least a 802.11n radio and thus
+cover 802.11b as well as 802.11g on 2.4 GHz, they are compatible with
+each other.
+
+As the basic rate was incorrectly set for mesh interfaces in the past,
+connections between mesh neighbors would fail when altering the basic
+rate.
+
+This patch ignores mismatches in the basic-rate field. By doing so, we
+avoid implementing some sort of scheduled switch between wireless
+configurations.
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+---
+ net/mac80211/mesh.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/net/mac80211/mesh.c
++++ b/net/mac80211/mesh.c
+@@ -94,9 +94,6 @@ bool mesh_matches_local(struct ieee80211
+ ieee80211_sta_get_rates(sdata, ie, sband->band,
+ &basic_rates);
+
+- if (sdata->vif.bss_conf.basic_rates != basic_rates)
+- return false;
+-
+ cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chanreq.oper.chan,
+ NL80211_CHAN_NO_HT);
+ ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def);
From: David Bauer <mail@david-bauer.net>
Date: Tue, 7 Jan 2025 00:49:41 +0100
Subject: net: mac80211: force backwards compatible basic rates
Force backwards-compatible basic-rates on the mesh interface.
This is required to maintain backwards-compatible with older
Gluon releases.
Signed-off-by: David Bauer <mail@david-bauer.net>
diff --git a/package/kernel/mac80211/patches/subsys/996-net-mac80211-always-pretend-1-Mbit-s-as-mesh-basic-r.patch b/package/kernel/mac80211/patches/subsys/996-net-mac80211-always-pretend-1-Mbit-s-as-mesh-basic-r.patch
new file mode 100644
index 0000000000000000000000000000000000000000..6af899c754dcc58df8e262c2db9be0bd9c347e5e
--- /dev/null
+++ b/package/kernel/mac80211/patches/subsys/996-net-mac80211-always-pretend-1-Mbit-s-as-mesh-basic-r.patch
@@ -0,0 +1,66 @@
+From 70c1812fa170ee35cdc576c886bed4bfaae1d23c Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Tue, 7 Jan 2025 00:47:33 +0100
+Subject: [PATCH] net: mac80211: force backwards compatible basic rates
+
+Force backwards-compatible basic-rates on the mesh interface.
+This is required to maintain backwards-compatible with older
+Gluon releases.
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+---
+ net/mac80211/util.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/net/mac80211/mesh.c
++++ b/net/mac80211/mesh.c
+@@ -954,6 +954,7 @@ ieee80211_mesh_build_beacon(struct ieee8
+ struct ieee80211_sub_if_data *sdata;
+ int hdr_len = offsetofend(struct ieee80211_mgmt, u.beacon);
+ u32 rate_flags;
++ u32 br_bitfield;
+
+ sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
+
+@@ -1086,8 +1087,16 @@ ieee80211_mesh_build_beacon(struct ieee8
+ }
+ rcu_read_unlock();
+
++ if (sband->band == NL80211_BAND_2GHZ) {
++ br_bitfield = BIT(0);
++ } else if (sband->band == NL80211_BAND_5GHZ) {
++ br_bitfield = BIT(0) | BIT(2) | BIT(4);
++ } else {
++ br_bitfield = sdata->vif.bss_conf.basic_rates;
++ }
++
+ if (ieee80211_put_srates_elem(skb, sband,
+- sdata->vif.bss_conf.basic_rates,
++ br_bitfield,
+ rate_flags, 0, WLAN_EID_SUPP_RATES) ||
+ mesh_add_ds_params_ie(sdata, skb))
+ goto out_free;
+@@ -1100,7 +1109,7 @@ ieee80211_mesh_build_beacon(struct ieee8
+ bcn->tail = bcn->head + bcn->head_len;
+
+ if (ieee80211_put_srates_elem(skb, sband,
+- sdata->vif.bss_conf.basic_rates,
++ br_bitfield,
+ rate_flags, 0, WLAN_EID_EXT_SUPP_RATES) ||
+ mesh_add_rsn_ie(sdata, skb) ||
+ mesh_add_ht_cap_ie(sdata, skb) ||
+--- a/net/mac80211/mesh_plink.c
++++ b/net/mac80211/mesh_plink.c
+@@ -284,6 +284,12 @@ static int mesh_plink_frame_tx(struct ie
+ ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chanreq.oper);
+ basic_rates = sdata->vif.bss_conf.basic_rates;
+
++ if (sband->band == NL80211_BAND_2GHZ) {
++ basic_rates = BIT(0); /* mandatory rate */
++ } else if (sband->band == NL80211_BAND_5GHZ) {
++ basic_rates = BIT(0) | BIT(2) | BIT(4); /* mandatory rate */
++ }
++
+ if (ieee80211_put_srates_elem(skb, sband, basic_rates,
+ rate_flags, 0,
+ WLAN_EID_SUPP_RATES) ||
From: David Bauer <mail@david-bauer.net>
Date: Fri, 7 Feb 2025 00:17:02 +0100
Subject: mt76: import MT7915 recovery fixes
diff --git a/package/kernel/mt76/patches/0003-mt7915-mcu-lower-default-timeout.patch b/package/kernel/mt76/patches/0003-mt7915-mcu-lower-default-timeout.patch
new file mode 100644
index 0000000000000000000000000000000000000000..2f55d42fbffba1d84bff3a89da3281b73f3668de
--- /dev/null
+++ b/package/kernel/mt76/patches/0003-mt7915-mcu-lower-default-timeout.patch
@@ -0,0 +1,32 @@
+From 74530440427abcbd20d071f00e25ab0e4c483ea2 Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Mon, 13 Jan 2025 08:48:41 +0100
+Subject: [PATCH 3/5] mt7915: mcu: lower default timeout
+
+The default timeout set in mt76_connac2_mcu_fill_message of 20 seconds
+leads to excessive stalling in case messages are lost.
+
+Testing showed that a smaller timeout of seconds is sufficient in
+normal operation.
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+---
+ mt7915/mcu.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index 9d790f23..51b6e480 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -197,6 +197,8 @@ mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
+ static void
+ mt7915_mcu_set_timeout(struct mt76_dev *mdev, int cmd)
+ {
++ mdev->mcu.timeout = 5 * HZ;
++
+ if ((cmd & __MCU_CMD_FIELD_ID) != MCU_CMD_EXT_CID)
+ return;
+
+--
+2.47.2
+
diff --git a/package/kernel/mt76/patches/0004-mt7915-mcu-increase-command-timeout.patch b/package/kernel/mt76/patches/0004-mt7915-mcu-increase-command-timeout.patch
new file mode 100644
index 0000000000000000000000000000000000000000..5368dcff6623681c40c938efeed171885805e3a9
--- /dev/null
+++ b/package/kernel/mt76/patches/0004-mt7915-mcu-increase-command-timeout.patch
@@ -0,0 +1,32 @@
+From 094105e471472e3ea44c4094857ad8a7c6973460 Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Mon, 13 Jan 2025 08:51:30 +0100
+Subject: [PATCH 4/5] mt7915: mcu: increase command timeout
+
+Increase the timeout for MCU_EXT_CMD_EFUSE_BUFFER_MODE command.
+
+Regular retries upon hardware-recovery have been observed. Increasing
+the timeout slightly remedies this problem.
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+---
+ mt7915/mcu.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index 51b6e480..cd9cb428 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -210,6 +210,9 @@ mt7915_mcu_set_timeout(struct mt76_dev *mdev, int cmd)
+ case MCU_EXT_CMD_BSS_INFO_UPDATE:
+ mdev->mcu.timeout = 2 * HZ;
+ return;
++ case MCU_EXT_CMD_EFUSE_BUFFER_MODE:
++ mdev->mcu.timeout = 10 * HZ;
++ return;
+ default:
+ break;
+ }
+--
+2.47.2
+
diff --git a/package/kernel/mt76/patches/0005-mt7915-mcu-re-init-MCU-before-loading-FW-patch.patch b/package/kernel/mt76/patches/0005-mt7915-mcu-re-init-MCU-before-loading-FW-patch.patch
new file mode 100644
index 0000000000000000000000000000000000000000..21b47b1c484edf8b29f3237fd4e02e075b368a31
--- /dev/null
+++ b/package/kernel/mt76/patches/0005-mt7915-mcu-re-init-MCU-before-loading-FW-patch.patch
@@ -0,0 +1,55 @@
+From 4e9e3cceea7ace91df52d795e4e45a7acb368a4c Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Sun, 12 Jan 2025 15:30:54 +0100
+Subject: [PATCH 5/5] mt7915: mcu: re-init MCU before loading FW patch
+
+Restart the MCU and release the patch semaphore before loading the MCU
+patch firmware from the host.
+
+This fixes failures upon error recovery in case the semaphore was
+previously taken and never released by the host.
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+---
+ mt7915/mcu.c | 25 +++++++++++++++----------
+ 1 file changed, 15 insertions(+), 10 deletions(-)
+
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index cd9cb428..4121b980 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -2097,16 +2097,21 @@ static int mt7915_load_firmware(struct mt7915_dev *dev)
+ {
+ int ret;
+
+- /* make sure fw is download state */
+- if (mt7915_firmware_state(dev, false)) {
+- /* restart firmware once */
+- mt76_connac_mcu_restart(&dev->mt76);
+- ret = mt7915_firmware_state(dev, false);
+- if (ret) {
+- dev_err(dev->mt76.dev,
+- "Firmware is not ready for download\n");
+- return ret;
+- }
++ /* Release Semaphore if taken by previous failed attempt */
++ ret = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false);
++ if (ret != PATCH_REL_SEM_SUCCESS) {
++ dev_err(dev->mt76.dev, "Could not release semaphore\n");
++ /* Continue anyways */
++ }
++
++ /* Always restart MCU firmware */
++ mt76_connac_mcu_restart(&dev->mt76);
++
++ /* Check if MCU is ready */
++ ret = mt7915_firmware_state(dev, false);
++ if (ret) {
++ dev_err(dev->mt76.dev, "Firmware did not enter download state\n");
++ return ret;
+ }
+
+ ret = mt76_connac2_load_patch(&dev->mt76, fw_name_var(dev, ROM_PATCH));
+--
+2.47.2
+
From: Nico <github@nicoboehr.de>
Date: Mon, 26 Apr 2021 14:12:43 +0000
Subject: fastd: remove random delay on inital handshake
When a peer limit is defined, fastd will by default randomly delay
the inital handshake. As our gateways delay their handshake to
better distribute their load, this is undesireable.
diff --git a/net/fastd/patches/0100-remove-random-delay-on-inital-handshake.patch b/net/fastd/patches/0100-remove-random-delay-on-inital-handshake.patch
new file mode 100644
index 0000000000000000000000000000000000000000..40ca26812bda65d8b08a1034e23d1b2335c77259
--- /dev/null
+++ b/net/fastd/patches/0100-remove-random-delay-on-inital-handshake.patch
@@ -0,0 +1,23 @@
+--- a/src/peer.c
++++ b/src/peer.c
+@@ -322,19 +322,11 @@ static void reset_peer(fastd_peer_t *pee
+
+ /**
+ Starts the first handshake with a newly setup peer
+-
+- If a peer group has a peer limit the handshakes will be delayed between 0 and 3 seconds
+- make the choice of peers random (it will be biased by the latency, which might or might not be
+- what a user wants)
+ */
+ static void init_handshake(fastd_peer_t *peer) {
+- unsigned delay = 0;
+- if (has_group_config_constraints(peer->group))
+- delay = fastd_rand(0, 3000);
+-
+ peer->state = STATE_HANDSHAKE;
+
+- fastd_peer_schedule_handshake(peer, delay);
++ fastd_peer_schedule_handshake(peer, 0);
+ }
+
+ /** Handles an asynchronous DNS resolve response */
From: Nico <github@nicoboehr.de>
Date: Fri, 29 Dec 2023 23:17:27 +0000
Subject: uradvd: add patch to announce prefix with preferred lifetime 0
diff --git a/net/uradvd/patches/001-uradvd-announce-with-pref-0.patch b/net/uradvd/patches/001-uradvd-announce-with-pref-0.patch
new file mode 100644
index 0000000000000000000000000000000000000000..7882639d1bfec0923460c93f55fe9f44e58212c1
--- /dev/null
+++ b/net/uradvd/patches/001-uradvd-announce-with-pref-0.patch
@@ -0,0 +1,11 @@
+--- a/uradvd.c
++++ b/uradvd.c
+@@ -43,7 +43,7 @@
+
+ /* These are in seconds */
+ #define AdvValidLifetime 86400u
+-#define AdvPreferredLifetime 14400u
++#define AdvPreferredLifetime 0u
+ #define AdvDefaultLifetime 0u
+ #define AdvCurHopLimit 64u
+ #define AdvRDNSSLifetime 1200u
From: Matthias Schiffer <mschiffer@universe-factory.net>
Date: Fri, 25 Apr 2025 02:06:17 +0200
Subject: perl: replace 910-miniperl-needs-inc-dot.patch with smaller scope fix
The patch was first introduced in commit 4a94479f9652 ("perl: update to
5.26.1") to fix the target build when the host perl has
default_inc_excludes_dot enabled. It just added back the `-I`. to every
call of miniperl; this solution is questionable however, as it adds `.` to
the beginning of the search path, not as a final fallback like perl did
before default_inc_excludes_dot (and like miniperl does).
It is also not necessary - only two scripts, write_buildcustomize.pl and
configpm, expect to be able to include a file from `.` (in both cases a
file the script just generated). Just fix the two scripts instead.
Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
diff --git a/lang/perl/patches/910-fix-default_inc_excludes_dot.patch b/lang/perl/patches/910-fix-default_inc_excludes_dot.patch
new file mode 100644
index 0000000000000000000000000000000000000000..ab3e6243bda314f137d1c328fbbf0e7f3bb34f36
--- /dev/null
+++ b/lang/perl/patches/910-fix-default_inc_excludes_dot.patch
@@ -0,0 +1,22 @@
+--- a/write_buildcustomize.pl
++++ b/write_buildcustomize.pl
+@@ -3,7 +3,7 @@
+ use strict;
+
+ my $osname = $^O;
+-my $file = 'lib/buildcustomize.pl';
++my $file = './lib/buildcustomize.pl';
+
+ if ( @ARGV % 2 ) {
+ my $dir = shift;
+--- a/configpm
++++ b/configpm
+@@ -129,7 +129,7 @@ if ($Opts{chdir}) {
+ my ($Config_SH, $Config_PM, $Config_heavy, $Config_POD);
+ my $Glossary = 'Porting/Glossary';
+
+-$Config_PM = "lib/Config.pm";
++$Config_PM = "./lib/Config.pm";
+ $Config_POD = "lib/Config.pod";
+ $Config_SH = "config.sh";
+
diff --git a/lang/perl/patches/910-miniperl-needs-inc-dot.patch b/lang/perl/patches/910-miniperl-needs-inc-dot.patch
deleted file mode 100644
index 6997f04d575e5bb92e78052cf693ae39bb464a20..0000000000000000000000000000000000000000
--- a/lang/perl/patches/910-miniperl-needs-inc-dot.patch
+++ /dev/null
@@ -1,38 +0,0 @@
---- a/Makefile.SH
-+++ b/Makefile.SH
-@@ -346,7 +346,7 @@ OBJ_EXT = $_o
- # Macros to invoke a copy of miniperl during the build. Targets which
- # are built using these macros should depend on \$(MINIPERL_EXE)
- MINIPERL_EXE = miniperl\$(EXE_EXT)
--MINIPERL = \$(LDLIBPTH) ./miniperl\$(EXE_EXT) -Ilib
-+MINIPERL = \$(LDLIBPTH) ./miniperl\$(EXE_EXT) -Ilib -I.
-
- # Macros to invoke sort the MANIFEST during build
- MANIFEST_SRT = MANIFEST.srt
-@@ -1001,7 +1001,7 @@ lib/buildcustomize.pl: $& $(miniperl_obj
- @$(RMS) miniperl.xok
- $(CC) $(CLDFLAGS) $(NAMESPACEFLAGS) -o $(MINIPERL_EXE) \
- $(miniperl_objs) $(libs)
-- $(LDLIBPTH) ./miniperl$(HOST_EXE_EXT) -w -Ilib -Idist/Exporter/lib -MExporter -e '<?>' || sh -c 'echo >&2 Failed to build miniperl. Please run make minitest; exit 1'
-+ $(LDLIBPTH) ./miniperl$(HOST_EXE_EXT) -w -Ilib -I. -Idist/Exporter/lib -MExporter -e '<?>' || sh -c 'echo >&2 Failed to build miniperl. Please run make minitest; exit 1'
- $(MINIPERL) -f write_buildcustomize.pl
- !NO!SUBS!
- ;;
-@@ -1012,7 +1012,7 @@ lib/buildcustomize.pl: \$& \$(miniperl_d
- @\$(RMS) miniperl.xok
- @\$(RMS) \$(MINIPERL_EXE)
- \$(LNS) \$(HOST_PERL) \$(MINIPERL_EXE)
-- \$(LDLIBPTH) ./miniperl\$(HOST_EXE_EXT) -w -Ilib -Idist/Exporter/lib -MExporter -e '<?>' || sh -c 'echo >&2 Failed to build miniperl. Please run make minitest; exit 1'
-+ \$(LDLIBPTH) ./miniperl\$(HOST_EXE_EXT) -w -Ilib -I. -Idist/Exporter/lib -MExporter -e '<?>' || sh -c 'echo >&2 Failed to build miniperl. Please run make minitest; exit 1'
- \$(MINIPERL) -f write_buildcustomize.pl 'osname' "$osname"
- !GROK!THIS!
- else
-@@ -1021,7 +1021,7 @@ lib/buildcustomize.pl: $& $(miniperl_dep
- @$(RMS) miniperl.xok
- $(CC) $(CLDFLAGS) -o $(MINIPERL_EXE) \
- $(miniperl_objs) $(libs)
-- $(LDLIBPTH) ./miniperl$(HOST_EXE_EXT) -w -Ilib -Idist/Exporter/lib -MExporter -e '<?>' || sh -c 'echo >&2 Failed to build miniperl. Please run make minitest; exit 1'
-+ $(LDLIBPTH) ./miniperl$(HOST_EXE_EXT) -w -Ilib -I. -Idist/Exporter/lib -MExporter -e '<?>' || sh -c 'echo >&2 Failed to build miniperl. Please run make minitest; exit 1'
- $(MINIPERL) -f write_buildcustomize.pl
- !NO!SUBS!
- fi
From: Matthias Schiffer <mschiffer@universe-factory.net>
Date: Fri, 25 Apr 2025 12:35:23 +0200
Subject: perl: drop 110-always_use_miniperl.patch
The patch was introduced in commit 4c57844f0f04 ("lang/perl: Add hack to
make perl always use miniperl during build"), but it is not actually
necessary. By setting $perl to a non-empty value (using 'perl' as is
common on desktop distros), the logic works as intended and selects the
correct perl binary for host and target builds.
As miniperl just symlinks to host perl for target builds, the main
effect of this change is not unconditionally passing `-Ilib -I.`
anymore. This seems like a good thing; host libraries should be used
with host perl by default.
Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
diff --git a/lang/perl/files/base.config b/lang/perl/files/base.config
index 67232b6d83e70505e7e85ad6893a2661f4571f7f..7d8b88b200f589b0efad7b301d26c6f9b77dfb33 100644
--- a/lang/perl/files/base.config
+++ b/lang/perl/files/base.config
@@ -864,7 +864,7 @@ package='perl5'
pager='/usr/bin/less'
passcat='cat /etc/passwd'
path_sep=':'
-perl=''
+perl='perl'
perl5=''
perl_patchlevel=''
perl_static_inline='static __inline__'
diff --git a/lang/perl/patches/110-always_use_miniperl.patch b/lang/perl/patches/110-always_use_miniperl.patch
deleted file mode 100644
index 806a31256b2007ee5f2c36d75261fac0d176cc21..0000000000000000000000000000000000000000
--- a/lang/perl/patches/110-always_use_miniperl.patch
+++ /dev/null
@@ -1,27 +0,0 @@
---- a/Makefile.SH
-+++ b/Makefile.SH
-@@ -360,22 +360,11 @@ PERL_EXE_LDFLAGS=$exeldflags
- ;;
- esac
-
--case "$usecrosscompile$perl" in
--define?*)
-- $spitshell >>$Makefile <<!GROK!THIS!
--# Macros to invoke a copy of our fully operational perl during the build.
--PERL_EXE = perl\$(EXE_EXT)
--RUN_PERL = \$(LDLIBPTH) \$(RUN) $perl\$(EXE_EXT)
--!GROK!THIS!
-- ;;
--*)
-- $spitshell >>$Makefile <<!GROK!THIS!
-+$spitshell >>$Makefile <<!GROK!THIS!
- # Macros to invoke a copy of our fully operational perl during the build.
- PERL_EXE = perl\$(EXE_EXT)
--RUN_PERL = \$(LDLIBPTH) \$(RUN) ./perl\$(EXE_EXT) -Ilib -I.
-+RUN_PERL = \$(LDLIBPTH) \$(RUN) ./miniperl\$(EXE_EXT) -Ilib -I.
- !GROK!THIS!
-- ;;
--esac
-
- $spitshell >>$Makefile <<!GROK!THIS!
- # Macros to run our tests
diff --git a/lang/perl/patches/900-use-rm-force.patch b/lang/perl/patches/900-use-rm-force.patch
index 9e44f5402f184445dcf4e9c75d96d2e412e5c4e0..baff506f6427f0b16712c252b0159ad80db20243 100644
--- a/lang/perl/patches/900-use-rm-force.patch
+++ b/lang/perl/patches/900-use-rm-force.patch
@@ -8,7 +8,7 @@
ranlib = $ranlib
ECHO = $echo
-@@ -791,7 +792,7 @@ bitcount.h: generate_uudmap$(HOST_EXE_EX
+@@ -802,7 +803,7 @@ bitcount.h: generate_uudmap$(HOST_EXE_EX
./generate_uudmap$(HOST_EXE_EXT) $(generated_headers)
generate_uudmap$(HOST_EXE_EXT): generate_uudmap$(OBJ_EXT)
@@ -17,7 +17,7 @@
$(LNS) $(HOST_GENERATE) generate_uudmap$(HOST_EXE_EXT)
!NO!SUBS!
-@@ -896,26 +897,26 @@ mydtrace.h: $(DTRACE_H)
+@@ -907,26 +908,26 @@ mydtrace.h: $(DTRACE_H)
define)
$spitshell >>$Makefile <<'!NO!SUBS!'
$(DTRACE_MINI_O): perldtrace.d $(miniperl_objs_nodt)
@@ -48,7 +48,7 @@
!NO!SUBS!
;;
-@@ -926,13 +927,13 @@ $(LIBPERL): $& $(perllib_dep) $(DYNALOAD
+@@ -937,13 +938,13 @@ $(LIBPERL): $& $(perllib_dep) $(DYNALOAD
case "$useshrplib" in
true)
$spitshell >>$Makefile <<'!NO!SUBS!'
@@ -64,7 +64,7 @@
mv $@ libperl$(OBJ_EXT)
$(AR) qv $(LIBPERL) libperl$(OBJ_EXT)
!NO!SUBS!
-@@ -941,7 +942,7 @@ $(LIBPERL): $& $(perllib_dep) $(DYNALOAD
+@@ -952,7 +953,7 @@ $(LIBPERL): $& $(perllib_dep) $(DYNALOAD
;;
*)
$spitshell >>$Makefile <<'!NO!SUBS!'
@@ -73,7 +73,7 @@
$(AR) rc $(LIBPERL) $(perllib_objs) $(DYNALOADER)
@$(ranlib) $(LIBPERL)
!NO!SUBS!
-@@ -975,7 +976,7 @@ $(MINIPERL_EXE): lib/buildcustomize.pl
+@@ -986,7 +987,7 @@ $(MINIPERL_EXE): lib/buildcustomize.pl
amigaos*)
$spitshell >>$Makefile <<'!NO!SUBS!'
lib/buildcustomize.pl: $& $(miniperl_objs) write_buildcustomize.pl
@@ -82,7 +82,7 @@
$(CC) $(CLDFLAGS) -o $(MINIPERL_EXE) \
$(miniperl_objs) $(libs)
# $(LDLIBPTH) ./miniperl$(HOST_EXE_EXT) -w -Ilib -Idist/Exporter/lib -MExporter -e '<?>' || sh -c 'echo >&2 Failed to build miniperl. Please run make minitest; exit 1'
-@@ -997,7 +998,7 @@ NAMESPACEFLAGS = -force_flat_namespace
+@@ -1008,7 +1009,7 @@ NAMESPACEFLAGS = -force_flat_namespace
esac
$spitshell >>$Makefile <<'!NO!SUBS!'
lib/buildcustomize.pl: $& $(miniperl_objs) write_buildcustomize.pl
@@ -91,7 +91,7 @@
$(CC) $(CLDFLAGS) $(NAMESPACEFLAGS) -o $(MINIPERL_EXE) \
$(miniperl_objs) $(libs)
$(LDLIBPTH) ./miniperl$(HOST_EXE_EXT) -w -Ilib -Idist/Exporter/lib -MExporter -e '<?>' || sh -c 'echo >&2 Failed to build miniperl. Please run make minitest; exit 1'
-@@ -1008,8 +1009,8 @@ lib/buildcustomize.pl: $& $(miniperl_obj
+@@ -1019,8 +1020,8 @@ lib/buildcustomize.pl: $& $(miniperl_obj
if test "X$hostperl" != X; then
$spitshell >>$Makefile <<!GROK!THIS!
lib/buildcustomize.pl: \$& \$(miniperl_dep) write_buildcustomize.pl
@@ -102,7 +102,7 @@
\$(LNS) \$(HOST_PERL) \$(MINIPERL_EXE)
\$(LDLIBPTH) ./miniperl\$(HOST_EXE_EXT) -w -Ilib -Idist/Exporter/lib -MExporter -e '<?>' || sh -c 'echo >&2 Failed to build miniperl. Please run make minitest; exit 1'
\$(MINIPERL) -f write_buildcustomize.pl 'osname' "$osname"
-@@ -1017,7 +1018,7 @@ lib/buildcustomize.pl: \$& \$(miniperl_d
+@@ -1028,7 +1029,7 @@ lib/buildcustomize.pl: \$& \$(miniperl_d
else
$spitshell >>$Makefile <<'!NO!SUBS!'
lib/buildcustomize.pl: $& $(miniperl_dep) write_buildcustomize.pl
@@ -111,7 +111,7 @@
$(CC) $(CLDFLAGS) -o $(MINIPERL_EXE) \
$(miniperl_objs) $(libs)
$(LDLIBPTH) ./miniperl$(HOST_EXE_EXT) -w -Ilib -Idist/Exporter/lib -MExporter -e '<?>' || sh -c 'echo >&2 Failed to build miniperl. Please run make minitest; exit 1'
-@@ -1030,7 +1031,7 @@ lib/buildcustomize.pl: $& $(miniperl_dep
+@@ -1041,7 +1042,7 @@ lib/buildcustomize.pl: $& $(miniperl_dep
$spitshell >>$Makefile <<'!NO!SUBS!'
$(PERL_EXE): $& $(perlmain_dep) $(LIBPERL) $(static_ext) ext.libs $(PERLEXPORT) write_buildcustomize.pl
@@ -120,7 +120,7 @@
!NO!SUBS!
case "$osname" in
-@@ -1130,8 +1131,8 @@ pod/perl5400delta.pod: pod/perldelta.pod
+@@ -1141,8 +1142,8 @@ pod/perl5400delta.pod: pod/perldelta.pod
$(LNS) perldelta.pod pod/perl5400delta.pod
extra.pods: $(MINIPERL_EXE)
@@ -131,7 +131,7 @@
-@for x in `grep -l '^=[a-z]' README.* | grep -v README.vms` ; do \
nx=`echo $$x | sed -e "s/README\.//"`; \
$(LNS) ../$$x "pod/perl"$$nx".pod" ; \
-@@ -1330,11 +1331,11 @@ realclean: _realcleaner _mopup
+@@ -1341,11 +1342,11 @@ realclean: _realcleaner _mopup
@echo "Note that '$(MAKE) realclean' does not delete config.sh or Policy.sh"
_clobber:
@@ -148,7 +148,7 @@
clobber: _realcleaner _mopup _clobber
-@@ -1342,24 +1343,24 @@ distclean: clobber
+@@ -1353,24 +1354,24 @@ distclean: clobber
# Like distclean but also removes emacs backups and *.orig.
veryclean: _verycleaner _mopup _clobber
@@ -184,7 +184,7 @@
-cd pod; $(LDLIBPTH) $(MAKE) $(CLEAN)
-cd utils; $(LDLIBPTH) $(MAKE) $(CLEAN)
-@if test -f $(MINIPERL_EXE) ; then \
-@@ -1369,8 +1370,8 @@ _cleaner1:
+@@ -1380,8 +1381,8 @@ _cleaner1:
else \
sh $(CLEAN).sh ; \
fi
@@ -195,7 +195,7 @@
# Dear POSIX, thanks for making the default to xargs to be
# run once if nothing is passed in. It is such a great help.
-@@ -1385,24 +1386,24 @@ _cleaner1:
+@@ -1396,24 +1397,24 @@ _cleaner1:
# Add new rules before that line - the next line (rm -f so_locations ...) is
# used as a placeholder by a regen script.
_cleaner2:
@@ -237,7 +237,7 @@
-rmdir lib/version lib/threads lib/inc/ExtUtils lib/inc lib/encoding
-rmdir lib/autodie/exception lib/autodie/Scope lib/autodie lib/XS
-rmdir lib/Win32API lib/VMS lib/Unicode/Collate/Locale
-@@ -1459,11 +1460,11 @@ _realcleaner:
+@@ -1470,11 +1471,11 @@ _realcleaner:
_verycleaner:
@$(LDLIBPTH) $(MAKE) _cleaner1 CLEAN=veryclean
@$(LDLIBPTH) $(MAKE) _cleaner2
@@ -251,7 +251,7 @@
lint $(lintflags) -DPERL_CORE -D_REENTRANT -DDEBUGGING -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 $(c)
cscopeflags = -Rb # Recursive, build-only.
-@@ -1524,7 +1525,7 @@ case "$targethost" in
+@@ -1535,7 +1536,7 @@ case "$targethost" in
'') $spitshell >>$Makefile <<'!NO!SUBS!'
test_prep test-prep: test_prep_pre $(MINIPERL_EXE) $(unidatafiles) $(PERL_EXE) \
$(dynamic_ext) $(TEST_PERL_DLL) runtests $(generated_pods) common_build
@@ -260,7 +260,7 @@
!NO!SUBS!
;;
-@@ -1574,7 +1575,7 @@ test_prep test-prep: test_prep_pre \$(MI
+@@ -1585,7 +1586,7 @@ test_prep test-prep: test_prep_pre \$(MI
$to config.sh
# --- For lib/diagnostics.t with -Duseshrplib
$to \$(PERL_EXE)
@@ -269,7 +269,7 @@
$to t/\$(PERL_EXE)
!GROK!THIS!
-@@ -1592,7 +1593,7 @@ else
+@@ -1603,7 +1604,7 @@ else
$spitshell >>$Makefile <<'!NO!SUBS!'
test_prep_reonly: $(MINIPERL_EXE) $(PERL_EXE) $(dynamic_ext_re) $(TEST_PERL_DLL)
$(MINIPERL) make_ext.pl $(dynamic_ext_re) MAKE="$(MAKE)" LIBPERL_A=$(LIBPERL) LINKTYPE=dynamic
@@ -278,7 +278,7 @@
!NO!SUBS!
fi
-@@ -1648,7 +1649,7 @@ minitest_prep: $(MINIPERL_EXE)
+@@ -1659,7 +1660,7 @@ minitest_prep: $(MINIPERL_EXE)
@echo "You may see some irrelevant test failures if you have been unable"
@echo "to build lib/Config.pm, or the Unicode data files."
@echo " "
diff --git a/lang/perl/patches/920-Revert-perl-127606-adjust-dependency-paths-on-instal.patch b/lang/perl/patches/920-Revert-perl-127606-adjust-dependency-paths-on-instal.patch
index e9e5688e475e810f45acbda5cd579c65e484b8b7..6436a8ea027f46a8ce1c41b13323b625cc51eb4d 100644
--- a/lang/perl/patches/920-Revert-perl-127606-adjust-dependency-paths-on-instal.patch
+++ b/lang/perl/patches/920-Revert-perl-127606-adjust-dependency-paths-on-instal.patch
@@ -42,10 +42,10 @@ Signed-off-by: Georgi Valkov <gvalkov@gmail.com>
- ;;
-esac
-
- $spitshell >>$Makefile <<!GROK!THIS!
- # Macros to invoke a copy of our fully operational perl during the build.
- PERL_EXE = perl\$(EXE_EXT)
-@@ -1045,20 +1029,6 @@ $(PERL_EXE): $& $(perlmain_dep) $(LIBPER
+ case "$usecrosscompile$perl" in
+ define?*)
+ $spitshell >>$Makefile <<!GROK!THIS!
+@@ -1056,20 +1040,6 @@ $(PERL_EXE): $& $(perlmain_dep) $(LIBPER
$(SHRPENV) $(CC) -o perl $(CLDFLAGS) $(CCDLFLAGS) $(perlmain_objs) $(LLIBPERL) $(static_ext) `cat ext.libs` $(libs)
!NO!SUBS!
;;
From: Matthias Schiffer <mschiffer@universe-factory.net>
Date: Sat, 26 Apr 2025 22:37:16 +0200
Subject: perl: fix parallel build race condition in target build
We have received reports of builds of perl occasionally failing when
building with many parallel jobs, with a log like the following:
LD_LIBRARY_PATH=[...]/perl/perl-5.40.0 ./miniperl -Ilib make_ext.pl \
dist/constant/pm_to_blib MAKE="make" LIBPERL_A=libperl.so
File/Path.pm did not return a true value at [...]/hostpkg/usr/lib/perl5/5.40.0/ExtUtils/MakeMaker.pm line 13.
BEGIN failed--compilation aborted at [...]/hostpkg/usr/lib/perl5/5.40.0/ExtUtils/MakeMaker.pm line 13.
Compilation failed in require at Makefile.PL line 3.
BEGIN failed--compilation aborted at Makefile.PL line 3.
Unsuccessful Makefile.PL(dist/constant): code=65280 at make_ext.pl line 532.
The failing extension (dist/constant in the above log) would differ
between runs.
The cause of the issue is the `-Ilib` in the command line of miniperl.
In the host build, `./miniperl -I lib` will use the following include
path:
[..]/build_dir/hostpkg/perl/perl-5.40.0/cpan/AutoLoader/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/dist/Carp/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/dist/PathTools
[..]/build_dir/hostpkg/perl/perl-5.40.0/dist/PathTools/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/cpan/ExtUtils-Install/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/cpan/ExtUtils-MakeMaker/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/cpan/ExtUtils-Manifest/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/cpan/File-Path/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/ext/re
[..]/build_dir/hostpkg/perl/perl-5.40.0/dist/Term-ReadLine/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/dist/Exporter/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/ext/File-Find/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/cpan/Text-Tabs/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/dist/constant/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/cpan/version/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/cpan/Getopt-Long/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/cpan/Text-ParseWords/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/cpan/ExtUtils-PL2Bat/lib
[..]/build_dir/hostpkg/perl/perl-5.40.0/lib
.
Various dependencies of the extension build scripts (Makefile.PL) -
including File-Path, which failed to be loaded in the error log - are
included in the path by buildcustomize.pl, as these extensions are only
installed to `lib` as the build proceeds.
However, in a target build, miniperl is just a symlink to the previously
built host perl. As the host perl does not implicitly load
`buildcustomize.pl`, we get the following include path for
`./miniperl -Ilib`:
lib
[..]/staging_dir/hostpkg/usr/lib/perl5/site_perl/5.40.0/x86_64-linux
[..]/staging_dir/hostpkg/usr/lib/perl5/site_perl/5.40.0
[..]/staging_dir/hostpkg/usr/lib/perl5/5.40.0/x86_64-linux
[..]/staging_dir/hostpkg/usr/lib/perl5/5.40.0
The host perl's install location is used as the default include path
which provides File-Path etc. for the target build; however, as more
and more libraries get installed into `lib` during the extension build,
they may get loaded from there instead, as `lib` is at the beginning of
the include path. When multiple extensions are built in parallel, a
Makefile.PL may attempt to load File/Path from `lib` after the file has
been created, but before its contents have been written fully, resulting
in the build to fail.
In fact, we should not load anything from `lib` during the target build,
as it is the staging directory for the target, including native
extensions built for the target architecture - with one exception: The
build scripts expect to find target information in the `Config` module,
so simply removing `lib` from the include path completely would break
the build.
Solve the issue by creating an alternative lib directory `lib_build`,
symlinking `Config.pm` and its dependencies in it, and replacing the
`-Ilib` argument with `-Ilib_build` using a wrapper script around the
host perl executable. This is similar to the approach seen in perl's own
obsolete/broken cross compile scripts (`Cross/Makefile`).
Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
diff --git a/lang/perl/Makefile b/lang/perl/Makefile
index 6a6dd5ea86798e7e95e3657a94cca829dbd0924b..6ad27818e17c211abc1530eb0d1b1e7c1238bf28 100644
--- a/lang/perl/Makefile
+++ b/lang/perl/Makefile
@@ -92,6 +92,21 @@ endef
# Target perl
define Build/Configure
+ # We don't want to pass -Ilib to host perl in the target build (as lib
+ # contains the target libraries, and files may currently be written
+ # while being imported in parallel builds). We do however need the
+ # target versions of the Config modules at the beginning of the include
+ # path for the build scripts' use.
+ #
+ # Create an alternative lib_build directory that will be added to the
+ # include path instead of lib (using hostperl-wrapper), containing only
+ # the config modules.
+ $(INSTALL_DIR) $(PKG_BUILD_DIR)/lib_build
+ ln -sf ../lib/Config.pm ../lib/Config_heavy.pl ../lib/Config_git.pl $(PKG_BUILD_DIR)/lib_build/
+
+ install -m0755 files/hostperl-wrapper $(PKG_BUILD_DIR)/hostperl-wrapper
+ sed -i "s'@HOST_PERL@'$(HOST_PERL_PREFIX)/bin/perl'g" $(PKG_BUILD_DIR)/hostperl-wrapper
+
$(PERL_CMD) files/perlconfig.pl -Dowrt:target_cc='$(TARGET_CC)' \
-Dowrt:gccversion=$(CONFIG_GCC_VERSION) \
-Dowrt:target_cross='$(TARGET_CROSS)' \
diff --git a/lang/perl/files/base.config b/lang/perl/files/base.config
index 7d8b88b200f589b0efad7b301d26c6f9b77dfb33..1cadfc10ac20c3b2bb05bed3c2cc8e946ba24eef 100644
--- a/lang/perl/files/base.config
+++ b/lang/perl/files/base.config
@@ -650,7 +650,7 @@ hint='recommended'
hostcat='cat /etc/hosts'
hostgenerate="$owrt:host_perl_prefix/bin/generate_uudmap"
hostosname=''
-hostperl="$owrt:host_perl_prefix/bin/perl"
+hostperl="./hostperl-wrapper"
html1dir=' '
html1direxp=''
html3dir=' '
diff --git a/lang/perl/files/hostperl-wrapper b/lang/perl/files/hostperl-wrapper
new file mode 100644
index 0000000000000000000000000000000000000000..e31ef1cf8fe37a7a90ee9dd7cc60d3ca947e7600
--- /dev/null
+++ b/lang/perl/files/hostperl-wrapper
@@ -0,0 +1,14 @@
+#!@HOST_PERL@
+
+foreach (@ARGV) {
+ # Stop parsing options if we encounter a non-option argument or --
+ last if $_ eq '--' || $_ !~ m/^-/;
+
+ # Modify first option of the form -Ilib, -I../lib, ... to refer to lib_build instead
+ if ($_ =~ m@-I(.*/)?lib@) {
+ $_ .= '_build';
+ last;
+ }
+}
+
+exec '@HOST_PERL@', @ARGV
From: Linus Lüssing <linus.luessing@c0d3.blue>
Date: Sun, 10 Nov 2024 19:34:26 +0100
Subject: batman-adv: Introduce no noflood mark
This mark prevents a multicast packet being flooded through the whole
mesh. The advantage of marking certain multicast packets via e.g.
ebtables instead of dropping is then the following:
This allows an administrator to let specific multicast packets pass as
long as they are forwarded to a limited number of nodes only and are
therefore creating no burdon to unrelated nodes.
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
diff --git a/batman-adv/patches/2002-batman-adv-Introduce-no-noflood-mark.patch b/batman-adv/patches/2002-batman-adv-Introduce-no-noflood-mark.patch
new file mode 100644
index 0000000000000000000000000000000000000000..6058bff5bb4d07c78a82f59b47213a52b04d6a1e
--- /dev/null
+++ b/batman-adv/patches/2002-batman-adv-Introduce-no-noflood-mark.patch
@@ -0,0 +1,137 @@
+From: Linus Lüssing <linus.luessing@c0d3.blue>
+Date: Sat, 31 Mar 2018 03:36:19 +0200
+Subject: batman-adv: Introduce no noflood mark
+
+This mark prevents a multicast packet being flooded through the whole
+mesh. The advantage of marking certain multicast packets via e.g.
+ebtables instead of dropping is then the following:
+
+This allows an administrator to let specific multicast packets pass as
+long as they are forwarded to a limited number of nodes only and are
+therefore creating no burdon to unrelated nodes.
+
+Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
+
+--- a/include/uapi/linux/batman_adv.h
++++ b/include/uapi/linux/batman_adv.h
+@@ -481,6 +481,18 @@ enum batadv_nl_attrs {
+ */
+ BATADV_ATTR_MULTICAST_FANOUT,
+
++ /**
++ * @BATADV_ATTR_NOFLOOD_MARK: the noflood mark which allows to tag
++ * frames which should never be broadcast flooded through the mesh.
++ */
++ BATADV_ATTR_NOFLOOD_MARK,
++
++ /**
++ * @BATADV_ATTR_NOFLOOD_MASK: the noflood (bit)mask which allows to tag
++ * frames which should never be broadcast flooded through the mesh.
++ */
++ BATADV_ATTR_NOFLOOD_MASK,
++
+ /* add attributes above here, update the policy in netlink.c */
+
+ /**
+--- a/net/batman-adv/netlink.c
++++ b/net/batman-adv/netlink.c
+@@ -133,6 +133,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 },
++ [BATADV_ATTR_NOFLOOD_MARK] = { .type = NLA_U32 },
++ [BATADV_ATTR_NOFLOOD_MASK] = { .type = NLA_U32 },
+ [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 },
+@@ -285,6 +287,14 @@ static int batadv_netlink_mesh_fill(stru
+ bat_priv->isolation_mark_mask))
+ goto nla_put_failure;
+
++ if (nla_put_u32(msg, BATADV_ATTR_NOFLOOD_MARK,
++ bat_priv->noflood_mark))
++ goto nla_put_failure;
++
++ if (nla_put_u32(msg, BATADV_ATTR_NOFLOOD_MASK,
++ bat_priv->noflood_mark_mask))
++ goto nla_put_failure;
++
+ if (nla_put_u8(msg, BATADV_ATTR_BONDING_ENABLED,
+ !!atomic_read(&bat_priv->bonding)))
+ goto nla_put_failure;
+@@ -463,6 +473,18 @@ static int batadv_netlink_set_mesh(struc
+ bat_priv->isolation_mark_mask = nla_get_u32(attr);
+ }
+
++ if (info->attrs[BATADV_ATTR_NOFLOOD_MARK]) {
++ attr = info->attrs[BATADV_ATTR_NOFLOOD_MARK];
++
++ bat_priv->noflood_mark = nla_get_u32(attr);
++ }
++
++ if (info->attrs[BATADV_ATTR_NOFLOOD_MASK]) {
++ attr = info->attrs[BATADV_ATTR_NOFLOOD_MASK];
++
++ bat_priv->noflood_mark_mask = nla_get_u32(attr);
++ }
++
+ if (info->attrs[BATADV_ATTR_BONDING_ENABLED]) {
+ attr = info->attrs[BATADV_ATTR_BONDING_ENABLED];
+
+--- a/net/batman-adv/soft-interface.c
++++ b/net/batman-adv/soft-interface.c
+@@ -177,6 +177,23 @@ static void batadv_interface_set_rx_mode
+ {
+ }
+
++/**
++ * batadv_send_skb_has_noflood_mark() - check if packet has a noflood mark
++ * @bat_priv: the bat priv with all the soft interface information
++ * @skb: the packet to check
++ *
++ * Return: True if the skb's mark matches a configured noflood mark and
++ * noflood mark mask. False otherwise.
++ */
++static bool
++batadv_skb_has_noflood_mark(struct batadv_priv *bat_priv, struct sk_buff *skb)
++{
++ u32 match_mark = skb->mark & bat_priv->noflood_mark_mask;
++
++ return bat_priv->noflood_mark_mask &&
++ match_mark == bat_priv->noflood_mark;
++}
++
+ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
+ struct net_device *soft_iface)
+ {
+@@ -333,6 +350,9 @@ send:
+ if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb))
+ brd_delay = msecs_to_jiffies(ARP_REQ_DELAY);
+
++ if (batadv_skb_has_noflood_mark(bat_priv, skb))
++ goto dropped;
++
+ if (batadv_skb_head_push(skb, sizeof(*bcast_packet)) < 0)
+ goto dropped;
+
+--- a/net/batman-adv/types.h
++++ b/net/batman-adv/types.h
+@@ -1711,6 +1711,18 @@ struct batadv_priv {
+ */
+ u32 isolation_mark_mask;
+
++ /**
++ * @noflood_mark: the skb->mark value used to allow directed targeting
++ * only
++ */
++ u32 noflood_mark;
++
++ /**
++ * @noflood_mark_mask: bitmask identifying the bits in skb->mark to be
++ * used for the noflood mark
++ */
++ u32 noflood_mark_mask;
++
+ /** @bcast_seqno: last sent broadcast packet sequence number */
+ atomic_t bcast_seqno;
+