From cfddc9a78ae2e4a01c5280ac2c18f214ad3cf036 Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Wed, 8 Jul 2026 08:37:56 +1200 Subject: [PATCH 01/18] build: pin to OpenWrt 25.12 (v25.12.5) branch_name/branch_id/packages_branch repointed from openwrt-24.10 to openwrt-25.12 -- confirmed the openwrt-25.12 branch exists in both openwrt/openwrt and openwrt/packages, matching build.sh's existing checkout convention exactly. openwrt_commit pinned to f0a60eee2f (the v25.12.5 tag's dereferenced commit, not branch head) for reproducibility -- same convention as the prior 24.10 pin. 24.10 security support ends 2026-09-05; this is Stage 1 of a two-stage bump (base first with USE_APK=n, apk flip separately) -- see docs/openwrt-2512-bump-plan.md in gargoyle-tools for the full track plan. --- build.sh | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/build.sh b/build.sh index 01f5fe6e8..47ef395ae 100755 --- a/build.sh +++ b/build.sh @@ -26,15 +26,18 @@ set_version_variables() { #openwrt branch - branch_name="24.10" - branch_id="openwrt-24.10" - packages_branch="openwrt-24.10" + branch_name="25.12" + branch_id="openwrt-25.12" + packages_branch="openwrt-25.12" - # set precise commit in repo to use - # you can set this to an alternate commit + # set precise commit in repo to use + # you can set this to an alternate commit # or empty to checkout latest - openwrt_commit="95d0ca014c4ce5e225579f859c066dc74a20763b" + # pinned to the v25.12.5 tag's commit (not branch head) for + # reproducibility, same convention as the prior 24.10 pin -- see + # docs/openwrt-2512-bump-plan.md/-progress.md in gargoyle-tools + openwrt_commit="f0a60eee2fe051741c643ea6118718aae1ef17fb" openwrt_abbrev_commit=$( echo "$openwrt_commit" | cut -b 1-7 ) From 6342c5b04a017df8feb9fd967cf50dafa43fd208 Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Thu, 9 Jul 2026 21:41:12 +1200 Subject: [PATCH 02/18] patches: re-derive carried patches for 25.12 004-fix_postinst_prerm_scripts, 027-wireguard_tools_bump, and 101-gargoyle_ssid_override needed re-anchoring against the 25.12 tree (context drift, not logic changes). targets/mediatek/patches/001-uboot needed the same treatment: 25.12 dropped the --enable SERIAL_RX_BUFFER line the patch modified from UBOOT_CUSTOMIZE_CONFIG; re-derived against the new block, adds back both the enable and the 256-byte size. --- .../004-fix_postinst_prerm_scripts.patch | 18 +++++++++++------- ...027-wireguard_tools_bump_1.0.20260223.patch | 7 +++---- .../101-gargoyle_ssid_override.patch | 7 ++++--- ...-uboot-mediatek_serial_rx_buffer_size.patch | 9 +++++---- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/patches-generic/004-fix_postinst_prerm_scripts.patch b/patches-generic/004-fix_postinst_prerm_scripts.patch index 40e1d35ca..a0bfcb101 100644 --- a/patches-generic/004-fix_postinst_prerm_scripts.patch +++ b/patches-generic/004-fix_postinst_prerm_scripts.patch @@ -1,6 +1,6 @@ --- a/package/base-files/files/lib/functions.sh +++ b/package/base-files/files/lib/functions.sh -@@ -213,16 +213,19 @@ default_prerm() { +@@ -220,6 +220,7 @@ local root="${IPKG_INSTROOT}" [ -z "$pkgname" ] && local pkgname="$(basename ${1%.*})" local ret=0 @@ -8,6 +8,10 @@ local filelist="${root}/usr/lib/opkg/info/${pkgname}.list" [ -f "$root/lib/apk/packages/${pkgname}.list" ] && filelist="$root/lib/apk/packages/${pkgname}.list" +@@ -227,13 +228,15 @@ + update_alternatives remove "${pkgname}" + fi + - if [ -f "$root/usr/lib/opkg/info/${pkgname}.prerm-pkg" ]; then - ( . "$root/usr/lib/opkg/info/${pkgname}.prerm-pkg" ) + pkg_prerm="${1}-pkg" @@ -23,7 +27,7 @@ if [ -n "$root" ]; then ${shell:-/bin/sh} "$root/etc/rc.common" "$root$i" disable else -@@ -238,7 +241,8 @@ default_prerm() { +@@ -249,7 +252,8 @@ add_group_and_user() { [ -z "$pkgname" ] && local pkgname="$(basename ${1%.*})" @@ -33,7 +37,7 @@ if [ -f "$root/lib/apk/packages/${pkgname}.rusers" ]; then local rusers="$(cat $root/lib/apk/packages/${pkgname}.rusers)" fi -@@ -347,9 +351,18 @@ default_postinst() { +@@ -358,9 +362,18 @@ [ -f "$root/lib/apk/packages/${pkgname}.list" ] && filelist="$root/lib/apk/packages/${pkgname}.list" local ret=0 @@ -52,8 +56,8 @@ + add_group_and_user "${pkg_control}" fi - if [ -e "${root}/lib/apk/packages/${pkgname}.list" ]; then -@@ -363,17 +376,17 @@ default_postinst() { + if [ -e "${root}/lib/apk/packages/${pkgname}.alternatives" ]; then +@@ -373,17 +386,17 @@ fi if [ -z "$root" ]; then @@ -75,8 +79,8 @@ ( [ -f "$i" ] && cd "$(dirname $i)" && . "$i" ) && rm -f "$i" done uci commit -@@ -382,13 +395,13 @@ default_postinst() { - rm -f /tmp/luci-indexcache +@@ -392,13 +405,13 @@ + rm -f /tmp/luci-indexcache.* fi - if [ -f "$root/usr/lib/opkg/info/${pkgname}.postinst-pkg" ]; then diff --git a/patches-generic/027-wireguard_tools_bump_1.0.20260223.patch b/patches-generic/027-wireguard_tools_bump_1.0.20260223.patch index fcdfcc9d8..87d9d5ed1 100644 --- a/patches-generic/027-wireguard_tools_bump_1.0.20260223.patch +++ b/patches-generic/027-wireguard_tools_bump_1.0.20260223.patch @@ -4,14 +4,13 @@ PKG_NAME:=wireguard-tools --PKG_VERSION:=1.0.20210914 --PKG_RELEASE:=4 +-PKG_VERSION:=1.0.20250521 +PKG_VERSION:=1.0.20260223 -+PKG_RELEASE:=1 + PKG_RELEASE:=1 PKG_SOURCE:=wireguard-tools-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=https://git.zx2c4.com/wireguard-tools/snapshot/ --PKG_HASH:=97ff31489217bb265b7ae850d3d0f335ab07d2652ba1feec88b734bc96bd05ac +-PKG_HASH:=b6f2628b85b1b23cc06517ec9c74f82d52c4cdbd020f3dd2f00c972a1782950e +PKG_HASH:=af459827b80bfd31b83b08077f4b5843acb7d18ad9a33a2ef532d3090f291fbf PKG_LICENSE:=GPL-2.0 diff --git a/patches-generic/101-gargoyle_ssid_override.patch b/patches-generic/101-gargoyle_ssid_override.patch index dda816138..563e0a1ce 100644 --- a/patches-generic/101-gargoyle_ssid_override.patch +++ b/patches-generic/101-gargoyle_ssid_override.patch @@ -1,11 +1,12 @@ --- a/package/network/config/wifi-scripts/files/lib/wifi/mac80211.uc +++ b/package/network/config/wifi-scripts/files/lib/wifi/mac80211.uc -@@ -104,7 +104,7 @@ +@@ -109,7 +109,7 @@ set ${si}.device='${name}' set ${si}.network='lan' set ${si}.mode='ap' -set ${si}.ssid='${defaults?.ssid || "OpenWrt"}' +set ${si}.ssid='${defaults?.ssid || "Gargoyle"}' - set ${si}.encryption='${defaults?.encryption || "none"}' + set ${si}.encryption='${defaults?.encryption || encryption}' set ${si}.key='${defaults?.key || ""}' - + set ${si}.disabled='${defaults ? 0 : 1}' + diff --git a/targets/mediatek/patches/001-uboot-mediatek_serial_rx_buffer_size.patch b/targets/mediatek/patches/001-uboot-mediatek_serial_rx_buffer_size.patch index 6b5fe6de0..ddb71481f 100644 --- a/targets/mediatek/patches/001-uboot-mediatek_serial_rx_buffer_size.patch +++ b/targets/mediatek/patches/001-uboot-mediatek_serial_rx_buffer_size.patch @@ -1,12 +1,13 @@ --- a/package/boot/uboot-mediatek/Makefile +++ b/package/boot/uboot-mediatek/Makefile -@@ -911,7 +911,8 @@ UBOOT_CUSTOMIZE_CONFIG := \ +@@ -1311,7 +1311,9 @@ + UBOOT_CUSTOMIZE_CONFIG := \ --disable TOOLS_KWBIMAGE \ --disable TOOLS_LIBCRYPTO \ - --disable TOOLS_MKEFICAPSULE \ -- --enable SERIAL_RX_BUFFER +- --disable TOOLS_MKEFICAPSULE ++ --disable TOOLS_MKEFICAPSULE \ + --enable SERIAL_RX_BUFFER \ + --set-val SERIAL_RX_BUFFER_SIZE 256 - + ifdef CONFIG_TARGET_mediatek UBOOT_MAKE_FLAGS += $(UBOOT_IMAGE:.fip=.bin) From a2c5f27815f4d10c457f39cbc5acd97abe4bc54e Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Wed, 8 Jul 2026 10:02:01 +1200 Subject: [PATCH 03/18] patches: remove 023/024 -- both fully absorbed natively by 25.12's pinned versions Discovered live during a real B2 build (Gargoyle's netfilter-match-modules integration script, netfilter-match-modules/integrate_netfilter_modules.sh, downloads the exact package-Makefile-pinned nftables/libnftnl source and re-applies package/.../patches/*.patch against it as part of preparing to layer Gargoyle's own custom NFT match modules on top) -- both patches failed against the real, current 25.12-pinned versions (nftables 1.1.6, libnftnl 1.3.1), non-fatally to the overall build but a real correctness gap worth fixing properly rather than ignoring. 023-nftables-remove-patch-files.patch deleted a stray tests/shell/ run-tests.sh.rej file that shipped in nftables' own 24.10-era source tarball. Verified directly against the real nftables-1.1.6.tar.xz: that file no longer exists in the tarball at all -- upstream's own release process cleaned it up. Nothing left for this patch to do. 024-backport_nftables_bitwise_mask_xor.patch backported a specific upstream libnftnl commit (12bd1aea5, Jeremy Sowden, "add new bitwise boolean attributes to nf_tables.h") into an older libnftnl's headers. Verified directly against the real libnftnl-1.3.1.tar.xz's include/linux/netfilter/nf_tables.h: every field this patch adds (NFT_BITWISE_MASK_XOR, NFT_BITWISE_AND/OR/XOR, the NFT_BITWISE_BOOL backwards-compat define, NFTA_BITWISE_SREG2) is already present natively. libnftnl 1.3.1 ships with zero patches at all in package/libs/libnftnl/patches/ once these two are removed. This is exactly the "check whether upstream absorbed the change natively" scenario from the 24.10 bump's own patch-024 lesson -- these two patches needed deleting, not re-deriving. Verified via a fresh v25.12.5 scratch clone + the real scripts/patch-kernel.sh: all 22 remaining patches apply clean, and the nftables/libnftnl patches/ directories end up containing only upstream's own native patches (3 for nftables, none for libnftnl) with nothing left over from us to fail. --- .../023-nftables-remove-patch-files.patch | 21 - ...4-backport_nftables_bitwise_mask_xor.patch | 1403 ----------------- 2 files changed, 1424 deletions(-) delete mode 100644 patches-generic/023-nftables-remove-patch-files.patch delete mode 100644 patches-generic/024-backport_nftables_bitwise_mask_xor.patch diff --git a/patches-generic/023-nftables-remove-patch-files.patch b/patches-generic/023-nftables-remove-patch-files.patch deleted file mode 100644 index 881db4abd..000000000 --- a/patches-generic/023-nftables-remove-patch-files.patch +++ /dev/null @@ -1,21 +0,0 @@ ---- /dev/null -+++ b/package/network/utils/nftables/patches/001-remove-patch-files.patch -@@ -0,0 +1,18 @@ -+--- a/tests/shell/run-tests.sh.rej -++++ /dev/null -+@@ -1,15 +0,0 @@ -+---- run-tests.sh -+-+++ run-tests.sh -+-@@ -565,11 +565,8 @@ feature_probe() -+- fi -+- -+- if [ -x "$with_path.sh" ] ; then -+-- echo $with_path -+- NFT="$NFT_REAL" $NFT_TEST_UNSHARE_CMD "$with_path.sh" &>/dev/null -+-- RET=$? -+-- echo $? -+-- return $RET -+-+ return $? -+- fi -+- -+- return 1 diff --git a/patches-generic/024-backport_nftables_bitwise_mask_xor.patch b/patches-generic/024-backport_nftables_bitwise_mask_xor.patch deleted file mode 100644 index 2d36b1c65..000000000 --- a/patches-generic/024-backport_nftables_bitwise_mask_xor.patch +++ /dev/null @@ -1,1403 +0,0 @@ ---- /dev/null -+++ b/package/libs/libnftnl/patches/001-include_add_new_bitwise_bool_attr_to_nftables_h.patch -@@ -0,0 +1,67 @@ -+From 12bd1aea5233da4f20c19e4c7e6c4ff961185ea1 Mon Sep 17 00:00:00 2001 -+From: Jeremy Sowden -+Date: Wed, 13 Nov 2024 22:25:47 +0100 -+Subject: include: add new bitwise boolean attributes to nf_tables.h -+ -+The kernel now has native support for AND, OR and XOR bitwise -+operations. -+ -+Signed-off-by: Jeremy Sowden -+Signed-off-by: Pablo Neira Ayuso -+--- -+ include/linux/netfilter/nf_tables.h | 18 +++++++++++++++--- -+ 1 file changed, 15 insertions(+), 3 deletions(-) -+ -+diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h -+index 9e90793..49c944e 100644 -+--- a/include/linux/netfilter/nf_tables.h -++++ b/include/linux/netfilter/nf_tables.h -+@@ -564,16 +564,26 @@ enum nft_immediate_attributes { -+ /** -+ * enum nft_bitwise_ops - nf_tables bitwise operations -+ * -+- * @NFT_BITWISE_BOOL: mask-and-xor operation used to implement NOT, AND, OR and -+- * XOR boolean operations -++ * @NFT_BITWISE_MASK_XOR: mask-and-xor operation used to implement NOT, AND, OR -++ * and XOR boolean operations -+ * @NFT_BITWISE_LSHIFT: left-shift operation -+ * @NFT_BITWISE_RSHIFT: right-shift operation -++ * @NFT_BITWISE_AND: and operation -++ * @NFT_BITWISE_OR: or operation -++ * @NFT_BITWISE_XOR: xor operation -+ */ -+ enum nft_bitwise_ops { -+- NFT_BITWISE_BOOL, -++ NFT_BITWISE_MASK_XOR, -+ NFT_BITWISE_LSHIFT, -+ NFT_BITWISE_RSHIFT, -++ NFT_BITWISE_AND, -++ NFT_BITWISE_OR, -++ NFT_BITWISE_XOR, -+ }; -++/* -++ * Old name for NFT_BITWISE_MASK_XOR. Retained for backwards-compatibility. -++ */ -++#define NFT_BITWISE_BOOL NFT_BITWISE_MASK_XOR -+ -+ /** -+ * enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes -+@@ -586,6 +596,7 @@ enum nft_bitwise_ops { -+ * @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops) -+ * @NFTA_BITWISE_DATA: argument for non-boolean operations -+ * (NLA_NESTED: nft_data_attributes) -++ * @NFTA_BITWISE_SREG2: second source register (NLA_U32: nft_registers) -+ * -+ * The bitwise expression supports boolean and shift operations. It implements -+ * the boolean operations by performing the following operation: -+@@ -609,6 +620,7 @@ enum nft_bitwise_attributes { -+ NFTA_BITWISE_XOR, -+ NFTA_BITWISE_OP, -+ NFTA_BITWISE_DATA, -++ NFTA_BITWISE_SREG2, -+ __NFTA_BITWISE_MAX -+ }; -+ #define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1) -+-- -+cgit v1.2.3 -+ ---- /dev/null -+++ b/package/libs/libnftnl/patches/002-expr_bitwise_rename_boolean_ops_funcs.patch -@@ -0,0 +1,153 @@ -+From 638b687979befc4e2b22b92c6830ccc9bdcf41fb Mon Sep 17 00:00:00 2001 -+From: Jeremy Sowden -+Date: Wed, 13 Nov 2024 22:39:12 +0100 -+Subject: expr: bitwise: rename some boolean operation functions -+ -+In the next patch we add support for doing AND, OR and XOR operations -+directly in the kernel, so rename some functions and an enum constant -+related to mask-and-xor boolean operations. -+ -+Signed-off-by: Jeremy Sowden -+Signed-off-by: Pablo Neira Ayuso -+--- -+ src/expr/bitwise.c | 8 ++++---- -+ tests/nft-expr_bitwise-test.c | 34 +++++++++++++++++----------------- -+ 2 files changed, 21 insertions(+), 21 deletions(-) -+ -+diff --git a/src/expr/bitwise.c b/src/expr/bitwise.c -+index 1a945e9..9385219 100644 -+--- a/src/expr/bitwise.c -++++ b/src/expr/bitwise.c -+@@ -198,8 +198,8 @@ nftnl_expr_bitwise_parse(struct nftnl_expr *e, struct nlattr *attr) -+ } -+ -+ static int -+-nftnl_expr_bitwise_snprintf_bool(char *buf, size_t remain, -+- const struct nftnl_expr_bitwise *bitwise) -++nftnl_expr_bitwise_snprintf_mask_xor(char *buf, size_t remain, -++ const struct nftnl_expr_bitwise *bitwise) -+ { -+ int offset = 0, ret; -+ -+@@ -248,8 +248,8 @@ nftnl_expr_bitwise_snprintf(char *buf, size_t size, -+ int err = -1; -+ -+ switch (bitwise->op) { -+- case NFT_BITWISE_BOOL: -+- err = nftnl_expr_bitwise_snprintf_bool(buf, size, bitwise); -++ case NFT_BITWISE_MASK_XOR: -++ err = nftnl_expr_bitwise_snprintf_mask_xor(buf, size, bitwise); -+ break; -+ case NFT_BITWISE_LSHIFT: -+ err = nftnl_expr_bitwise_snprintf_shift(buf, size, "<<", bitwise); -+diff --git a/tests/nft-expr_bitwise-test.c b/tests/nft-expr_bitwise-test.c -+index d98569c..04bf95c 100644 -+--- a/tests/nft-expr_bitwise-test.c -++++ b/tests/nft-expr_bitwise-test.c -+@@ -22,32 +22,32 @@ static void print_err(const char *test, const char *msg) -+ printf("\033[31mERROR:\e[0m [%s] %s\n", test, msg); -+ } -+ -+-static void cmp_nftnl_expr_bool(struct nftnl_expr *rule_a, -+- struct nftnl_expr *rule_b) -++static void cmp_nftnl_expr_mask_xor(struct nftnl_expr *rule_a, -++ struct nftnl_expr *rule_b) -+ { -+ uint32_t maska, maskb; -+ uint32_t xora, xorb; -+ -+ if (nftnl_expr_get_u32(rule_a, NFTNL_EXPR_BITWISE_DREG) != -+ nftnl_expr_get_u32(rule_b, NFTNL_EXPR_BITWISE_DREG)) -+- print_err("bool", "Expr BITWISE_DREG mismatches"); -++ print_err("mask & xor", "Expr BITWISE_DREG mismatches"); -+ if (nftnl_expr_get_u32(rule_a, NFTNL_EXPR_BITWISE_SREG) != -+ nftnl_expr_get_u32(rule_b, NFTNL_EXPR_BITWISE_SREG)) -+- print_err("bool", "Expr BITWISE_SREG mismatches"); -++ print_err("mask & xor", "Expr BITWISE_SREG mismatches"); -+ if (nftnl_expr_get_u32(rule_a, NFTNL_EXPR_BITWISE_OP) != -+ nftnl_expr_get_u32(rule_b, NFTNL_EXPR_BITWISE_OP)) -+- print_err("bool", "Expr BITWISE_OP mismatches"); -++ print_err("mask & xor", "Expr BITWISE_OP mismatches"); -+ if (nftnl_expr_get_u16(rule_a, NFTNL_EXPR_BITWISE_LEN) != -+ nftnl_expr_get_u16(rule_b, NFTNL_EXPR_BITWISE_LEN)) -+- print_err("bool", "Expr BITWISE_LEN mismatches"); -++ print_err("mask & xor", "Expr BITWISE_LEN mismatches"); -+ nftnl_expr_get(rule_a, NFTNL_EXPR_BITWISE_MASK, &maska); -+ nftnl_expr_get(rule_b, NFTNL_EXPR_BITWISE_MASK, &maskb); -+ if (maska != maskb) -+- print_err("bool", "Size of BITWISE_MASK mismatches"); -++ print_err("mask & xor", "Size of BITWISE_MASK mismatches"); -+ nftnl_expr_get(rule_a, NFTNL_EXPR_BITWISE_XOR, &xora); -+ nftnl_expr_get(rule_b, NFTNL_EXPR_BITWISE_XOR, &xorb); -+ if (xora != xorb) -+- print_err("bool", "Size of BITWISE_XOR mismatches"); -++ print_err("mask & xor", "Size of BITWISE_XOR mismatches"); -+ } -+ -+ static void cmp_nftnl_expr_lshift(struct nftnl_expr *rule_a, -+@@ -96,7 +96,7 @@ static void cmp_nftnl_expr_rshift(struct nftnl_expr *rule_a, -+ print_err("rshift", "Expr BITWISE_DATA mismatches"); -+ } -+ -+-static void test_bool(void) -++static void test_mask_xor(void) -+ { -+ struct nftnl_rule *a, *b = NULL; -+ struct nftnl_expr *ex = NULL; -+@@ -110,10 +110,10 @@ static void test_bool(void) -+ a = nftnl_rule_alloc(); -+ b = nftnl_rule_alloc(); -+ if (a == NULL || b == NULL) -+- print_err("bool", "OOM"); -++ print_err("mask & xor", "OOM"); -+ ex = nftnl_expr_alloc("bitwise"); -+ if (ex == NULL) -+- print_err("bool", "OOM"); -++ print_err("mask & xor", "OOM"); -+ -+ nftnl_expr_set_u32(ex, NFTNL_EXPR_BITWISE_SREG, 0x12345678); -+ nftnl_expr_set_u32(ex, NFTNL_EXPR_BITWISE_DREG, 0x78123456); -+@@ -128,26 +128,26 @@ static void test_bool(void) -+ nftnl_rule_nlmsg_build_payload(nlh, a); -+ -+ if (nftnl_rule_nlmsg_parse(nlh, b) < 0) -+- print_err("bool", "parsing problems"); -++ print_err("mask & xor", "parsing problems"); -+ -+ iter_a = nftnl_expr_iter_create(a); -+ iter_b = nftnl_expr_iter_create(b); -+ if (iter_a == NULL || iter_b == NULL) -+- print_err("bool", "OOM"); -++ print_err("mask & xor", "OOM"); -+ -+ rule_a = nftnl_expr_iter_next(iter_a); -+ rule_b = nftnl_expr_iter_next(iter_b); -+ if (rule_a == NULL || rule_b == NULL) -+- print_err("bool", "OOM"); -++ print_err("mask & xor", "OOM"); -+ -+ if (nftnl_expr_iter_next(iter_a) != NULL || -+ nftnl_expr_iter_next(iter_b) != NULL) -+- print_err("bool", "More 1 expr."); -++ print_err("mask & xor", "More 1 expr."); -+ -+ nftnl_expr_iter_destroy(iter_a); -+ nftnl_expr_iter_destroy(iter_b); -+ -+- cmp_nftnl_expr_bool(rule_a,rule_b); -++ cmp_nftnl_expr_mask_xor(rule_a,rule_b); -+ -+ nftnl_rule_free(a); -+ nftnl_rule_free(b); -+@@ -263,7 +263,7 @@ static void test_rshift(void) -+ -+ int main(int argc, char *argv[]) -+ { -+- test_bool(); -++ test_mask_xor(); -+ if (!test_ok) -+ exit(EXIT_FAILURE); -+ -+-- -+cgit v1.2.3 -+ ---- /dev/null -+++ b/package/libs/libnftnl/patches/003-expr_bitwise_add_support_kernel_and_or_xor_ops.patch -@@ -0,0 +1,158 @@ -+From f683f636a0aa8b121a9153c96cf5ca3f8e76faa5 Mon Sep 17 00:00:00 2001 -+From: Jeremy Sowden -+Date: Wed, 13 Nov 2024 22:27:08 +0100 -+Subject: expr: bitwise: add support for kernel space AND, OR and XOR -+ operations -+ -+Hitherto, the kernel has only supported boolean operations of the form: -+ -+ dst = (src & mask) ^ xor -+ -+where `src` is held in a register, and `mask` and `xor` are immediate -+values. User space has converted AND, OR and XOR operations to this -+form, and so one operand has had to be immediate. The kernel now -+supports performing AND, OR and XOR operations directly, on one register -+and an immediate value or on two registers, so we make that support -+available to user space. -+ -+Signed-off-by: Jeremy Sowden -+Signed-off-by: Pablo Neira Ayuso -+--- -+ include/libnftnl/expr.h | 1 + -+ src/expr/bitwise.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++-- -+ 2 files changed, 56 insertions(+), 2 deletions(-) -+ -+diff --git a/include/libnftnl/expr.h b/include/libnftnl/expr.h -+index fba1210..1c07b54 100644 -+--- a/include/libnftnl/expr.h -++++ b/include/libnftnl/expr.h -+@@ -139,6 +139,7 @@ enum { -+ NFTNL_EXPR_BITWISE_XOR, -+ NFTNL_EXPR_BITWISE_OP, -+ NFTNL_EXPR_BITWISE_DATA, -++ NFTNL_EXPR_BITWISE_SREG2, -+ __NFTNL_EXPR_BITWISE_MAX -+ }; -+ -+diff --git a/src/expr/bitwise.c b/src/expr/bitwise.c -+index 9385219..cac47a5 100644 -+--- a/src/expr/bitwise.c -++++ b/src/expr/bitwise.c -+@@ -19,6 +19,7 @@ -+ -+ struct nftnl_expr_bitwise { -+ enum nft_registers sreg; -++ enum nft_registers sreg2; -+ enum nft_registers dreg; -+ enum nft_bitwise_ops op; -+ unsigned int len; -+@@ -37,6 +38,9 @@ nftnl_expr_bitwise_set(struct nftnl_expr *e, uint16_t type, -+ case NFTNL_EXPR_BITWISE_SREG: -+ memcpy(&bitwise->sreg, data, data_len); -+ break; -++ case NFTNL_EXPR_BITWISE_SREG2: -++ memcpy(&bitwise->sreg2, data, sizeof(bitwise->sreg2)); -++ break; -+ case NFTNL_EXPR_BITWISE_DREG: -+ memcpy(&bitwise->dreg, data, data_len); -+ break; -+@@ -66,6 +70,9 @@ nftnl_expr_bitwise_get(const struct nftnl_expr *e, uint16_t type, -+ case NFTNL_EXPR_BITWISE_SREG: -+ *data_len = sizeof(bitwise->sreg); -+ return &bitwise->sreg; -++ case NFTNL_EXPR_BITWISE_SREG2: -++ *data_len = sizeof(bitwise->sreg2); -++ return &bitwise->sreg2; -+ case NFTNL_EXPR_BITWISE_DREG: -+ *data_len = sizeof(bitwise->dreg); -+ return &bitwise->dreg; -+@@ -98,6 +105,7 @@ static int nftnl_expr_bitwise_cb(const struct nlattr *attr, void *data) -+ -+ switch(type) { -+ case NFTA_BITWISE_SREG: -++ case NFTA_BITWISE_SREG2: -+ case NFTA_BITWISE_DREG: -+ case NFTA_BITWISE_OP: -+ case NFTA_BITWISE_LEN: -+@@ -123,6 +131,8 @@ nftnl_expr_bitwise_build(struct nlmsghdr *nlh, const struct nftnl_expr *e) -+ -+ if (e->flags & (1 << NFTNL_EXPR_BITWISE_SREG)) -+ mnl_attr_put_u32(nlh, NFTA_BITWISE_SREG, htonl(bitwise->sreg)); -++ if (e->flags & (1 << NFTNL_EXPR_BITWISE_SREG2)) -++ mnl_attr_put_u32(nlh, NFTA_BITWISE_SREG2, htonl(bitwise->sreg2)); -+ if (e->flags & (1 << NFTNL_EXPR_BITWISE_DREG)) -+ mnl_attr_put_u32(nlh, NFTA_BITWISE_DREG, htonl(bitwise->dreg)); -+ if (e->flags & (1 << NFTNL_EXPR_BITWISE_OP)) -+@@ -169,6 +179,10 @@ nftnl_expr_bitwise_parse(struct nftnl_expr *e, struct nlattr *attr) -+ bitwise->sreg = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_SREG])); -+ e->flags |= (1 << NFTNL_EXPR_BITWISE_SREG); -+ } -++ if (tb[NFTA_BITWISE_SREG2]) { -++ bitwise->sreg2 = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_SREG2])); -++ e->flags |= (1 << NFTNL_EXPR_BITWISE_SREG2); -++ } -+ if (tb[NFTA_BITWISE_DREG]) { -+ bitwise->dreg = ntohl(mnl_attr_get_u32(tb[NFTA_BITWISE_DREG])); -+ e->flags |= (1 << NFTNL_EXPR_BITWISE_DREG); -+@@ -240,6 +254,31 @@ nftnl_expr_bitwise_snprintf_shift(char *buf, size_t remain, const char *op, -+ return offset; -+ } -+ -++static int -++nftnl_expr_bitwise_snprintf_bool(char *buf, size_t remain, const char *op, -++ const struct nftnl_expr *e, -++ const struct nftnl_expr_bitwise *bitwise) -++{ -++ int offset = 0, ret; -++ -++ ret = snprintf(buf, remain, "reg %u = ( reg %u %s ", -++ bitwise->dreg, bitwise->sreg, op); -++ SNPRINTF_BUFFER_SIZE(ret, remain, offset); -++ -++ if (e->flags & (1 << NFTNL_EXPR_BITWISE_SREG2)) -++ ret = snprintf(buf + offset, remain, "reg %u ", bitwise->sreg2); -++ else -++ ret = nftnl_data_reg_snprintf(buf + offset, remain, -++ &bitwise->data, -++ 0, DATA_VALUE); -++ SNPRINTF_BUFFER_SIZE(ret, remain, offset); -++ -++ ret = snprintf(buf + offset, remain, ") "); -++ SNPRINTF_BUFFER_SIZE(ret, remain, offset); -++ -++ return offset; -++} -++ -+ static int -+ nftnl_expr_bitwise_snprintf(char *buf, size_t size, -+ uint32_t flags, const struct nftnl_expr *e) -+@@ -252,10 +291,24 @@ nftnl_expr_bitwise_snprintf(char *buf, size_t size, -+ err = nftnl_expr_bitwise_snprintf_mask_xor(buf, size, bitwise); -+ break; -+ case NFT_BITWISE_LSHIFT: -+- err = nftnl_expr_bitwise_snprintf_shift(buf, size, "<<", bitwise); -++ err = nftnl_expr_bitwise_snprintf_shift(buf, size, "<<", -++ bitwise); -+ break; -+ case NFT_BITWISE_RSHIFT: -+- err = nftnl_expr_bitwise_snprintf_shift(buf, size, ">>", bitwise); -++ err = nftnl_expr_bitwise_snprintf_shift(buf, size, ">>", -++ bitwise); -++ break; -++ case NFT_BITWISE_AND: -++ err = nftnl_expr_bitwise_snprintf_bool(buf, size, "&", e, -++ bitwise); -++ break; -++ case NFT_BITWISE_OR: -++ err = nftnl_expr_bitwise_snprintf_bool(buf, size, "|", e, -++ bitwise); -++ break; -++ case NFT_BITWISE_XOR: -++ err = nftnl_expr_bitwise_snprintf_bool(buf, size, "^", e, -++ bitwise); -+ break; -+ } -+ -+-- -+cgit v1.2.3 -+ ---- /dev/null -+++ b/package/network/utils/nftables/patches/002-allow_binop_expr_variable_rhs_operands.patch -@@ -0,0 +1,1013 @@ -+From 54bfc38c522babe709e951f1fd128ff725b36704 Mon Sep 17 00:00:00 2001 -+From: Jeremy Sowden -+Date: Tue, 19 Nov 2024 00:18:28 +0100 -+Subject: src: allow binop expressions with variable right-hand operands -+ -+Hitherto, the kernel has required constant values for the `xor` and -+`mask` attributes of boolean bitwise expressions. This has meant that -+the right-hand operand of a boolean binop must be constant. Now the -+kernel has support for AND, OR and XOR operations with right-hand -+operands passed via registers, we can relax this restriction. Allow -+non-constant right-hand operands if the left-hand operand is not -+constant, e.g.: -+ -+ ct mark & 0xffff0000 | meta mark & 0xffff -+ -+The kernel now supports performing AND, OR and XOR operations directly, -+on one register and an immediate value or on two registers, so we need -+to be able to generate and parse bitwise boolean expressions of this -+form. -+ -+If a boolean operation has a constant RHS, we continue to send a -+mask-and-xor expression to the kernel. -+ -+Add tests for {ct,meta} mark with variable RHS operands. -+ -+JSON support is also included. -+ -+This requires Linux kernel >= 6.13-rc. -+ -+[ Originally posted as patch 1/8 and 6/8 which has been collapsed and -+ simplified to focus on initial {ct,meta} mark support. Tests have -+ been extracted from 8/8 including a tests/py fix to payload output -+ due to incorrect output in original patchset. JSON support has been -+ extracted from patch 7/8 --pablo] -+ -+Signed-off-by: Jeremy Sowden -+Signed-off-by: Pablo Neira Ayuso -+--- -+ include/linux/netfilter/nf_tables.h | 19 ++++++- -+ src/evaluate.c | 52 ++++++++++++------ -+ src/netlink_delinearize.c | 64 +++++++++++++++++----- -+ src/netlink_linearize.c | 61 +++++++++++++++++---- -+ src/parser_json.c | 4 +- -+ tests/py/any/ct.t | 3 + -+ tests/py/any/ct.t.json | 60 ++++++++++++++++++++ -+ tests/py/any/ct.t.payload | 15 +++++ -+ tests/py/inet/meta.t | 2 + -+ tests/py/inet/meta.t.json | 37 +++++++++++++ -+ tests/py/inet/meta.t.payload | 9 +++ -+ tests/py/ip/ct.t | 2 + -+ tests/py/ip/ct.t.json | 32 +++++++++++ -+ tests/py/ip/ct.t.payload | 11 ++++ -+ tests/py/ip6/ct.t | 1 + -+ tests/py/ip6/ct.t.json | 32 +++++++++++ -+ tests/py/ip6/ct.t.payload | 12 ++++ -+ tests/shell/features/bitwise_multireg.nft | 5 ++ -+ tests/shell/testcases/bitwise/0040mark_binop_10 | 13 +++++ -+ tests/shell/testcases/bitwise/0040mark_binop_11 | 13 +++++ -+ tests/shell/testcases/bitwise/0040mark_binop_12 | 13 +++++ -+ tests/shell/testcases/bitwise/0040mark_binop_13 | 13 +++++ -+ tests/shell/testcases/bitwise/0044payload_binop_2 | 13 +++++ -+ tests/shell/testcases/bitwise/0044payload_binop_5 | 13 +++++ -+ .../testcases/bitwise/dumps/0040mark_binop_10.nft | 6 ++ -+ .../testcases/bitwise/dumps/0040mark_binop_11.nft | 6 ++ -+ .../testcases/bitwise/dumps/0040mark_binop_12.nft | 6 ++ -+ .../testcases/bitwise/dumps/0040mark_binop_13.nft | 6 ++ -+ .../bitwise/dumps/0044payload_binop_2.nft | 6 ++ -+ .../bitwise/dumps/0044payload_binop_5.nft | 6 ++ -+ 30 files changed, 489 insertions(+), 46 deletions(-) -+ create mode 100644 tests/shell/features/bitwise_multireg.nft -+ create mode 100755 tests/shell/testcases/bitwise/0040mark_binop_10 -+ create mode 100755 tests/shell/testcases/bitwise/0040mark_binop_11 -+ create mode 100755 tests/shell/testcases/bitwise/0040mark_binop_12 -+ create mode 100755 tests/shell/testcases/bitwise/0040mark_binop_13 -+ create mode 100755 tests/shell/testcases/bitwise/0044payload_binop_2 -+ create mode 100755 tests/shell/testcases/bitwise/0044payload_binop_5 -+ create mode 100644 tests/shell/testcases/bitwise/dumps/0040mark_binop_10.nft -+ create mode 100644 tests/shell/testcases/bitwise/dumps/0040mark_binop_11.nft -+ create mode 100644 tests/shell/testcases/bitwise/dumps/0040mark_binop_12.nft -+ create mode 100644 tests/shell/testcases/bitwise/dumps/0040mark_binop_13.nft -+ create mode 100644 tests/shell/testcases/bitwise/dumps/0044payload_binop_2.nft -+ create mode 100644 tests/shell/testcases/bitwise/dumps/0044payload_binop_5.nft -+ -+diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h -+index c62e6ac5..f57963e8 100644 -+--- a/include/linux/netfilter/nf_tables.h -++++ b/include/linux/netfilter/nf_tables.h -+@@ -557,16 +557,27 @@ enum nft_immediate_attributes { -+ /** -+ * enum nft_bitwise_ops - nf_tables bitwise operations -+ * -+- * @NFT_BITWISE_BOOL: mask-and-xor operation used to implement NOT, AND, OR and -+- * XOR boolean operations -++ * @NFT_BITWISE_MASK_XOR: mask-and-xor operation used to implement NOT, AND, OR -++ * and XOR boolean operations -+ * @NFT_BITWISE_LSHIFT: left-shift operation -+ * @NFT_BITWISE_RSHIFT: right-shift operation -++ * @NFT_BITWISE_AND: and operation -++ * @NFT_BITWISE_OR: or operation -++ * @NFT_BITWISE_XOR: xor operation -+ */ -+ enum nft_bitwise_ops { -+- NFT_BITWISE_BOOL, -++ NFT_BITWISE_MASK_XOR, -+ NFT_BITWISE_LSHIFT, -+ NFT_BITWISE_RSHIFT, -++ NFT_BITWISE_AND, -++ NFT_BITWISE_OR, -++ NFT_BITWISE_XOR, -+ }; -++/* -++ * Old name for NFT_BITWISE_MASK_XOR, predating the addition of NFT_BITWISE_AND, -++ * NFT_BITWISE_OR and NFT_BITWISE_XOR. Retained for backwards-compatibility. -++ */ -++#define NFT_BITWISE_BOOL NFT_BITWISE_MASK_XOR -+ -+ /** -+ * enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes -+@@ -579,6 +590,7 @@ enum nft_bitwise_ops { -+ * @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops) -+ * @NFTA_BITWISE_DATA: argument for non-boolean operations -+ * (NLA_NESTED: nft_data_attributes) -++ * @NFTA_BITWISE_SREG2: second source register (NLA_U32: nft_registers) -+ * -+ * The bitwise expression supports boolean and shift operations. It implements -+ * the boolean operations by performing the following operation: -+@@ -602,6 +614,7 @@ enum nft_bitwise_attributes { -+ NFTA_BITWISE_XOR, -+ NFTA_BITWISE_OP, -+ NFTA_BITWISE_DATA, -++ NFTA_BITWISE_SREG2, -+ __NFTA_BITWISE_MAX -+ }; -+ #define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1) -+diff --git a/src/evaluate.c b/src/evaluate.c -+index 593a0140..cd3619a2 100644 -+--- a/src/evaluate.c -++++ b/src/evaluate.c -+@@ -1487,16 +1487,18 @@ static int expr_evaluate_bitwise(struct eval_ctx *ctx, struct expr **expr) -+ op->byteorder = byteorder; -+ op->len = max_len; -+ -+- if (expr_is_constant(left)) -++ if (expr_is_constant(left) && expr_is_constant(op->right)) -+ return constant_binop_simplify(ctx, expr); -+ return 0; -+ } -+ -+ /* -+- * Binop expression: both sides must be of integer base type. The left -+- * hand side may be either constant or non-constant; in case its constant -+- * it must be a singleton. The ride hand side must always be a constant -+- * singleton. -++ * Binop expression: both sides must be of integer base type. The left-hand side -++ * may be either constant or non-constant; if it is constant, it must be a -++ * singleton. For bitwise operations, the right-hand side must be constant if -++ * the left-hand side is constant; the right-hand side may be constant or -++ * non-constant, if the left-hand side is non-constant; for shifts, the -++ * right-hand side must be constant; if it is constant, it must be a singleton. -+ */ -+ static int expr_evaluate_binop(struct eval_ctx *ctx, struct expr **expr) -+ { -+@@ -1527,6 +1529,13 @@ static int expr_evaluate_binop(struct eval_ctx *ctx, struct expr **expr) -+ return -1; -+ right = op->right; -+ -++ /* evaluation expects constant to the right hand side. */ -++ if (expr_is_constant(left) && !expr_is_constant(right)) { -++ range_expr_swap_values(op); -++ left = op->left; -++ right = op->right; -++ } -++ -+ switch (expr_basetype(left)->type) { -+ case TYPE_INTEGER: -+ case TYPE_STRING: -+@@ -1544,17 +1553,6 @@ static int expr_evaluate_binop(struct eval_ctx *ctx, struct expr **expr) -+ "for %s expressions", -+ sym, expr_name(left)); -+ -+- if (!expr_is_constant(right)) -+- return expr_binary_error(ctx->msgs, right, op, -+- "Right hand side of binary operation " -+- "(%s) must be constant", sym); -+- -+- if (!expr_is_singleton(right)) -+- return expr_binary_error(ctx->msgs, left, op, -+- "Binary operation (%s) is undefined " -+- "for %s expressions", -+- sym, expr_name(right)); -+- -+ if (!datatype_equal(expr_basetype(left), expr_basetype(right))) -+ return expr_binary_error(ctx->msgs, left, op, -+ "Binary operation (%s) with different base types " -+@@ -1564,11 +1562,33 @@ static int expr_evaluate_binop(struct eval_ctx *ctx, struct expr **expr) -+ switch (op->op) { -+ case OP_LSHIFT: -+ case OP_RSHIFT: -++ if (!expr_is_constant(right)) -++ return expr_binary_error(ctx->msgs, right, op, -++ "Right hand side of binary operation " -++ "(%s) must be constant", sym); -++ -++ if (!expr_is_singleton(right)) -++ return expr_binary_error(ctx->msgs, left, op, -++ "Binary operation (%s) is undefined " -++ "for %s expressions", -++ sym, expr_name(right)); -++ -+ ret = expr_evaluate_shift(ctx, expr); -+ break; -+ case OP_AND: -+ case OP_XOR: -+ case OP_OR: -++ if (expr_is_constant(left) && !expr_is_constant(right)) -++ return expr_binary_error(ctx->msgs, right, op, -++ "Right hand side of binary operation " -++ "(%s) must be constant", sym); -++ -++ if (expr_is_constant(right) && !expr_is_singleton(right)) -++ return expr_binary_error(ctx->msgs, left, op, -++ "Binary operation (%s) is undefined " -++ "for %s expressions", -++ sym, expr_name(right)); -++ -+ ret = expr_evaluate_bitwise(ctx, expr); -+ break; -+ default: -+diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c -+index e3d9cfbb..db8b6bbe 100644 -+--- a/src/netlink_delinearize.c -++++ b/src/netlink_delinearize.c -+@@ -455,12 +455,12 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx, -+ ctx->stmt = expr_stmt_alloc(loc, expr); -+ } -+ -+-static struct expr *netlink_parse_bitwise_bool(struct netlink_parse_ctx *ctx, -+- const struct location *loc, -+- const struct nftnl_expr *nle, -+- enum nft_registers sreg, -+- struct expr *left) -+- -++static struct expr * -++netlink_parse_bitwise_mask_xor(struct netlink_parse_ctx *ctx, -++ const struct location *loc, -++ const struct nftnl_expr *nle, -++ enum nft_registers sreg, -++ struct expr *left) -+ { -+ struct nft_data_delinearize nld; -+ struct expr *expr, *mask, *xor, *or; -+@@ -520,10 +520,39 @@ static struct expr *netlink_parse_bitwise_bool(struct netlink_parse_ctx *ctx, -+ return expr; -+ } -+ -++static struct expr *netlink_parse_bitwise_bool(struct netlink_parse_ctx *ctx, -++ const struct location *loc, -++ const struct nftnl_expr *nle, -++ enum nft_bitwise_ops op, -++ enum nft_registers sreg, -++ struct expr *left) -++{ -++ enum nft_registers sreg2; -++ struct expr *right, *expr; -++ -++ sreg2 = netlink_parse_register(nle, NFTNL_EXPR_BITWISE_SREG2); -++ right = netlink_get_register(ctx, loc, sreg2); -++ if (right == NULL) { -++ netlink_error(ctx, loc, -++ "Bitwise expression has no right-hand expression"); -++ return NULL; -++ } -++ -++ expr = binop_expr_alloc(loc, -++ op == NFT_BITWISE_XOR ? OP_XOR : -++ op == NFT_BITWISE_AND ? OP_AND : OP_OR, -++ left, right); -++ -++ if (left->len > 0) -++ expr->len = left->len; -++ -++ return expr; -++} -++ -+ static struct expr *netlink_parse_bitwise_shift(struct netlink_parse_ctx *ctx, -+ const struct location *loc, -+ const struct nftnl_expr *nle, -+- enum ops op, -++ enum nft_bitwise_ops op, -+ enum nft_registers sreg, -+ struct expr *left) -+ { -+@@ -534,7 +563,9 @@ static struct expr *netlink_parse_bitwise_shift(struct netlink_parse_ctx *ctx, -+ right = netlink_alloc_value(loc, &nld); -+ right->byteorder = BYTEORDER_HOST_ENDIAN; -+ -+- expr = binop_expr_alloc(loc, op, left, right); -++ expr = binop_expr_alloc(loc, -++ op == NFT_BITWISE_LSHIFT ? OP_LSHIFT : OP_RSHIFT, -++ left, right); -+ expr->len = nftnl_expr_get_u32(nle, NFTNL_EXPR_BITWISE_LEN) * BITS_PER_BYTE; -+ -+ return expr; -+@@ -558,16 +589,19 @@ static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx, -+ op = nftnl_expr_get_u32(nle, NFTNL_EXPR_BITWISE_OP); -+ -+ switch (op) { -+- case NFT_BITWISE_BOOL: -+- expr = netlink_parse_bitwise_bool(ctx, loc, nle, sreg, -+- left); -++ case NFT_BITWISE_MASK_XOR: -++ expr = netlink_parse_bitwise_mask_xor(ctx, loc, nle, sreg, -++ left); -+ break; -+- case NFT_BITWISE_LSHIFT: -+- expr = netlink_parse_bitwise_shift(ctx, loc, nle, OP_LSHIFT, -+- sreg, left); -++ case NFT_BITWISE_XOR: -++ case NFT_BITWISE_AND: -++ case NFT_BITWISE_OR: -++ expr = netlink_parse_bitwise_bool(ctx, loc, nle, op, -++ sreg, left); -+ break; -++ case NFT_BITWISE_LSHIFT: -+ case NFT_BITWISE_RSHIFT: -+- expr = netlink_parse_bitwise_shift(ctx, loc, nle, OP_RSHIFT, -++ expr = netlink_parse_bitwise_shift(ctx, loc, nle, op, -+ sreg, left); -+ break; -+ default: -+diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c -+index 77bc5149..42310115 100644 -+--- a/src/netlink_linearize.c -++++ b/src/netlink_linearize.c -+@@ -664,9 +664,9 @@ static void combine_binop(mpz_t mask, mpz_t xor, const mpz_t m, const mpz_t x) -+ mpz_and(mask, mask, m); -+ } -+ -+-static void netlink_gen_shift(struct netlink_linearize_ctx *ctx, -+- const struct expr *expr, -+- enum nft_registers dreg) -++static void netlink_gen_bitwise_shift(struct netlink_linearize_ctx *ctx, -++ const struct expr *expr, -++ enum nft_registers dreg) -+ { -+ enum nft_bitwise_ops op = expr->op == OP_LSHIFT ? -+ NFT_BITWISE_LSHIFT : NFT_BITWISE_RSHIFT; -+@@ -691,9 +691,9 @@ static void netlink_gen_shift(struct netlink_linearize_ctx *ctx, -+ nft_rule_add_expr(ctx, nle, &expr->location); -+ } -+ -+-static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx, -+- const struct expr *expr, -+- enum nft_registers dreg) -++static void netlink_gen_bitwise_mask_xor(struct netlink_linearize_ctx *ctx, -++ const struct expr *expr, -++ enum nft_registers dreg) -+ { -+ struct expr *binops[NFT_MAX_EXPR_RECURSION]; -+ struct nftnl_expr *nle; -+@@ -709,7 +709,7 @@ static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx, -+ mpz_init(tmp); -+ -+ binops[n++] = left = (struct expr *) expr; -+- while (left->etype == EXPR_BINOP && left->left != NULL && -++ while (left->etype == EXPR_BINOP && left->left != NULL && expr_is_constant(left->right) && -+ (left->op == OP_AND || left->op == OP_OR || left->op == OP_XOR)) { -+ if (n == array_size(binops)) -+ BUG("NFT_MAX_EXPR_RECURSION limit reached"); -+@@ -747,7 +747,7 @@ static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx, -+ nle = alloc_nft_expr("bitwise"); -+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, dreg); -+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, dreg); -+- nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_OP, NFT_BITWISE_BOOL); -++ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_OP, NFT_BITWISE_MASK_XOR); -+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len); -+ -+ netlink_gen_raw_data(mask, expr->byteorder, len, &nld); -+@@ -763,6 +763,44 @@ static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx, -+ nft_rule_add_expr(ctx, nle, &expr->location); -+ } -+ -++static void netlink_gen_bitwise_bool(struct netlink_linearize_ctx *ctx, -++ const struct expr *expr, -++ enum nft_registers dreg) -++{ -++ enum nft_registers sreg2; -++ struct nftnl_expr *nle; -++ unsigned int len; -++ -++ nle = alloc_nft_expr("bitwise"); -++ -++ switch (expr->op) { -++ case OP_XOR: -++ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_OP, NFT_BITWISE_XOR); -++ break; -++ case OP_AND: -++ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_OP, NFT_BITWISE_AND); -++ break; -++ case OP_OR: -++ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_OP, NFT_BITWISE_OR); -++ break; -++ default: -++ BUG("invalid binary operation %u\n", expr->op); -++ } -++ -++ netlink_gen_expr(ctx, expr->left, dreg); -++ netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, dreg); -++ netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, dreg); -++ -++ sreg2 = get_register(ctx, expr->right); -++ netlink_gen_expr(ctx, expr->right, sreg2); -++ netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG2, sreg2); -++ -++ len = div_round_up(expr->len, BITS_PER_BYTE); -++ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len); -++ -++ nftnl_rule_add_expr(ctx->nlr, nle); -++} -++ -+ static void netlink_gen_binop(struct netlink_linearize_ctx *ctx, -+ const struct expr *expr, -+ enum nft_registers dreg) -+@@ -770,10 +808,13 @@ static void netlink_gen_binop(struct netlink_linearize_ctx *ctx, -+ switch(expr->op) { -+ case OP_LSHIFT: -+ case OP_RSHIFT: -+- netlink_gen_shift(ctx, expr, dreg); -++ netlink_gen_bitwise_shift(ctx, expr, dreg); -+ break; -+ default: -+- netlink_gen_bitwise(ctx, expr, dreg); -++ if (expr_is_constant(expr->right)) -++ netlink_gen_bitwise_mask_xor(ctx, expr, dreg); -++ else -++ netlink_gen_bitwise_bool(ctx, expr, dreg); -+ break; -+ } -+ } -+diff --git a/src/parser_json.c b/src/parser_json.c -+index bae2c3c0..5ac5f027 100644 -+--- a/src/parser_json.c -++++ b/src/parser_json.c -+@@ -1557,12 +1557,12 @@ static struct expr *json_parse_expr(struct json_ctx *ctx, json_t *root) -+ { "ip option", json_parse_ip_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT }, -+ { "sctp chunk", json_parse_sctp_chunk_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT }, -+ { "dccp option", json_parse_dccp_option_expr, CTX_F_PRIMARY }, -+- { "meta", json_parse_meta_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, -++ { "meta", json_parse_meta_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, -+ { "osf", json_parse_osf_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT }, -+ { "ipsec", json_parse_xfrm_expr, CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT }, -+ { "socket", json_parse_socket_expr, CTX_F_PRIMARY | CTX_F_CONCAT }, -+ { "rt", json_parse_rt_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, -+- { "ct", json_parse_ct_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, -++ { "ct", json_parse_ct_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, -+ { "numgen", json_parse_numgen_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, -+ /* below two are hash expr */ -+ { "jhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT }, -+diff --git a/tests/py/any/ct.t b/tests/py/any/ct.t -+index f73fa4e7..0059e49c 100644 -+--- a/tests/py/any/ct.t -++++ b/tests/py/any/ct.t -+@@ -40,7 +40,9 @@ ct mark and 0x23 == 0x11;ok;ct mark & 0x00000023 == 0x00000011 -+ ct mark and 0x3 != 0x1;ok;ct mark & 0x00000003 != 0x00000001 -+ ct mark xor 0x23 == 0x11;ok;ct mark 0x00000032 -+ ct mark xor 0x3 != 0x1;ok;ct mark != 0x00000002 -++ -+ ct mark set ct mark or 0x00000001;ok;ct mark set ct mark | 0x00000001 -++ct mark set 0x00000001 or ct mark;ok;ct mark set ct mark | 0x00000001 -+ -+ ct mark 0x00000032;ok -+ ct mark != 0x00000032;ok -+@@ -61,6 +63,7 @@ ct mark set 0x11;ok;ct mark set 0x00000011 -+ ct mark set mark;ok;ct mark set meta mark -+ ct mark set (meta mark | 0x10) << 8;ok;ct mark set (meta mark | 0x00000010) << 8 -+ ct mark set mark map { 1 : 10, 2 : 20, 3 : 30 };ok;ct mark set meta mark map { 0x00000003 : 0x0000001e, 0x00000002 : 0x00000014, 0x00000001 : 0x0000000a} -++ct mark set ct mark and 0xffff0000 or meta mark and 0xffff;ok;ct mark set ct mark & 0xffff0000 | meta mark & 0x0000ffff -+ -+ ct mark set {0x11333, 0x11};fail -+ ct zone set {123, 127};fail -+diff --git a/tests/py/any/ct.t.json b/tests/py/any/ct.t.json -+index a2a06025..ef350000 100644 -+--- a/tests/py/any/ct.t.json -++++ b/tests/py/any/ct.t.json -+@@ -560,6 +560,29 @@ -+ } -+ ] -+ -++# ct mark set 0x00000001 or ct mark -++[ -++ { -++ "mangle": { -++ "key": { -++ "ct": { -++ "key": "mark" -++ } -++ }, -++ "value": { -++ "|": [ -++ { -++ "ct": { -++ "key": "mark" -++ } -++ }, -++ 1 -++ ] -++ } -++ } -++ } -++] -++ -+ # ct mark 0x00000032 -+ [ -+ { -+@@ -817,6 +840,43 @@ -+ } -+ ] -+ -++# ct mark set ct mark and 0xffff0000 or meta mark and 0xffff -++[ -++ { -++ "mangle": { -++ "key": { -++ "ct": { -++ "key": "mark" -++ } -++ }, -++ "value": { -++ "|": [ -++ { -++ "&": [ -++ { -++ "ct": { -++ "key": "mark" -++ } -++ }, -++ 4294901760 -++ ] -++ }, -++ { -++ "&": [ -++ { -++ "meta": { -++ "key": "mark" -++ } -++ }, -++ 65535 -++ ] -++ } -++ ] -++ } -++ } -++ } -++] -++ -+ # ct expiration 30s -+ [ -+ { -+diff --git a/tests/py/any/ct.t.payload b/tests/py/any/ct.t.payload -+index ed868e53..14385cf7 100644 -+--- a/tests/py/any/ct.t.payload -++++ b/tests/py/any/ct.t.payload -+@@ -336,6 +336,15 @@ ip test-ip4 output -+ [ lookup reg 1 set __map%d dreg 1 ] -+ [ ct set mark with reg 1 ] -+ -++# ct mark set ct mark and 0xffff0000 or meta mark and 0xffff -++ip -++ [ ct load mark => reg 1 ] -++ [ bitwise reg 1 = ( reg 1 & 0xffff0000 ) ^ 0x00000000 ] -++ [ meta load mark => reg 2 ] -++ [ bitwise reg 2 = ( reg 2 & 0x0000ffff ) ^ 0x00000000 ] -++ [ bitwise reg 1 = ( reg 1 | reg 2 ) ] -++ [ ct set mark with reg 1 ] -++ -+ # ct original bytes > 100000 -+ ip test-ip4 output -+ [ ct load bytes => reg 1 , dir original ] -+@@ -497,6 +506,12 @@ ip test-ip4 output -+ [ bitwise reg 1 = ( reg 1 & 0xfffffffe ) ^ 0x00000001 ] -+ [ ct set mark with reg 1 ] -+ -++# ct mark set 0x00000001 or ct mark -++ip test-ip4 output -++ [ ct load mark => reg 1 ] -++ [ bitwise reg 1 = ( reg 1 & 0xfffffffe ) ^ 0x00000001 ] -++ [ ct set mark with reg 1 ] -++ -+ # ct id 12345 -+ ip test-ip4 output -+ [ ct load unknown => reg 1 ] -+diff --git a/tests/py/inet/meta.t b/tests/py/inet/meta.t -+index 7d2515c9..5c5c11d4 100644 -+--- a/tests/py/inet/meta.t -++++ b/tests/py/inet/meta.t -+@@ -31,3 +31,5 @@ meta mark set ip dscp;ok -+ meta mark set ip dscp | 0x40;ok -+ meta mark set ip6 dscp;ok -+ meta mark set ip6 dscp | 0x40;ok -++ -++meta mark set ct mark and 0xffff0000 or meta mark and 0xffff;ok;meta mark set ct mark & 0xffff0000 | meta mark & 0x0000ffff -+diff --git a/tests/py/inet/meta.t.json b/tests/py/inet/meta.t.json -+index 0fee165f..4352b963 100644 -+--- a/tests/py/inet/meta.t.json -++++ b/tests/py/inet/meta.t.json -+@@ -236,6 +236,43 @@ -+ } -+ ] -+ -++# meta mark set ct mark and 0xffff0000 or meta mark and 0xffff -++[ -++ { -++ "mangle": { -++ "key": { -++ "meta": { -++ "key": "mark" -++ } -++ }, -++ "value": { -++ "|": [ -++ { -++ "&": [ -++ { -++ "ct": { -++ "key": "mark" -++ } -++ }, -++ 4294901760 -++ ] -++ }, -++ { -++ "&": [ -++ { -++ "meta": { -++ "key": "mark" -++ } -++ }, -++ 65535 -++ ] -++ } -++ ] -++ } -++ } -++ } -++] -++ -+ # meta protocol ip udp dport 67 -+ [ -+ { -+diff --git a/tests/py/inet/meta.t.payload b/tests/py/inet/meta.t.payload -+index 7184fa0c..04dfbd8f 100644 -+--- a/tests/py/inet/meta.t.payload -++++ b/tests/py/inet/meta.t.payload -+@@ -80,6 +80,15 @@ inet test-inet input -+ [ bitwise reg 1 = ( reg 1 >> 0x00000008 ) ] -+ [ meta set mark with reg 1 ] -+ -++# meta mark set ct mark and 0xffff0000 or meta mark and 0xffff -++inet test-inet input -++ [ ct load mark => reg 1 ] -++ [ bitwise reg 1 = ( reg 1 & 0xffff0000 ) ^ 0x00000000 ] -++ [ meta load mark => reg 2 ] -++ [ bitwise reg 2 = ( reg 2 & 0x0000ffff ) ^ 0x00000000 ] -++ [ bitwise reg 1 = ( reg 1 | reg 2 ) ] -++ [ meta set mark with reg 1 ] -++ -+ # meta protocol ip udp dport 67 -+ inet test-inet input -+ [ meta load protocol => reg 1 ] -+diff --git a/tests/py/ip/ct.t b/tests/py/ip/ct.t -+index a0a22289..523d0244 100644 -+--- a/tests/py/ip/ct.t -++++ b/tests/py/ip/ct.t -+@@ -28,9 +28,11 @@ meta mark set ct original saddr . meta mark map { 1.1.1.1 . 0x00000014 : 0x00000 -+ meta mark set ct original ip saddr . meta mark map { 1.1.1.1 . 0x00000014 : 0x0000001e };ok -+ ct original saddr . meta mark { 1.1.1.1 . 0x00000014 };fail -+ ct original ip saddr . meta mark { 1.1.1.1 . 0x00000014 };ok -++ -+ ct mark set ip dscp << 2 | 0x10;ok -+ ct mark set ip dscp << 26 | 0x10;ok -+ ct mark set ip dscp & 0x0f << 1;ok;ct mark set ip dscp & af33 -+ ct mark set ip dscp & 0x0f << 2;ok;ct mark set ip dscp & 0x3c -+ ct mark set ip dscp | 0x04;ok -+ ct mark set ip dscp | 1 << 20;ok;ct mark set ip dscp | 0x100000 -++ct mark set ct mark | ip dscp | 0x200 counter;ok;ct mark set ct mark | ip dscp | 0x00000200 counter -+diff --git a/tests/py/ip/ct.t.json b/tests/py/ip/ct.t.json -+index 915632ae..9e60f7e2 100644 -+--- a/tests/py/ip/ct.t.json -++++ b/tests/py/ip/ct.t.json -+@@ -479,3 +479,35 @@ -+ } -+ } -+ ] -++ -++# ct mark set ct mark | ip dscp | 0x200 counter -++[ -++ { -++ "mangle": { -++ "key": { -++ "ct": { -++ "key": "mark" -++ } -++ }, -++ "value": { -++ "|": [ -++ { -++ "ct": { -++ "key": "mark" -++ } -++ }, -++ { -++ "payload": { -++ "protocol": "ip", -++ "field": "dscp" -++ } -++ }, -++ 512 -++ ] -++ } -++ } -++ }, -++ { -++ "counter": null -++ } -++] -+diff --git a/tests/py/ip/ct.t.payload b/tests/py/ip/ct.t.payload -+index 692011d0..823de597 100644 -+--- a/tests/py/ip/ct.t.payload -++++ b/tests/py/ip/ct.t.payload -+@@ -134,3 +134,14 @@ ip test-ip4 output -+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ] -+ [ bitwise reg 1 = ( reg 1 & 0xffefffff ) ^ 0x00100000 ] -+ [ ct set mark with reg 1 ] -++ -++# ct mark set ct mark | ip dscp | 0x200 counter -++ip test-ip4 output -++ [ ct load mark => reg 1 ] -++ [ payload load 1b @ network header + 1 => reg 2 ] -++ [ bitwise reg 2 = ( reg 2 & 0x000000fc ) ^ 0x00000000 ] -++ [ bitwise reg 2 = ( reg 2 >> 0x00000002 ) ] -++ [ bitwise reg 1 = ( reg 1 | reg 2 ) ] -++ [ bitwise reg 1 = ( reg 1 & 0xfffffdff ) ^ 0x00000200 ] -++ [ ct set mark with reg 1 ] -++ [ counter pkts 0 bytes 0 ] -+diff --git a/tests/py/ip6/ct.t b/tests/py/ip6/ct.t -+index c06fd6a0..1617c68b 100644 -+--- a/tests/py/ip6/ct.t -++++ b/tests/py/ip6/ct.t -+@@ -7,3 +7,4 @@ ct mark set ip6 dscp << 26 | 0x10;ok -+ ct mark set ip6 dscp | 0x04;ok -+ ct mark set ip6 dscp | 0xff000000;ok -+ ct mark set ip6 dscp & 0x0f << 2;ok;ct mark set ip6 dscp & 0x3c -++ct mark set ct mark | ip6 dscp | 0x200 counter;ok;ct mark set ct mark | ip6 dscp | 0x00000200 counter -+diff --git a/tests/py/ip6/ct.t.json b/tests/py/ip6/ct.t.json -+index 7d8c88bb..2633c2b9 100644 -+--- a/tests/py/ip6/ct.t.json -++++ b/tests/py/ip6/ct.t.json -+@@ -291,3 +291,35 @@ -+ } -+ } -+ ] -++ -++# ct mark set ct mark | ip6 dscp | 0x200 counter -++[ -++ { -++ "mangle": { -++ "key": { -++ "ct": { -++ "key": "mark" -++ } -++ }, -++ "value": { -++ "|": [ -++ { -++ "ct": { -++ "key": "mark" -++ } -++ }, -++ { -++ "payload": { -++ "protocol": "ip6", -++ "field": "dscp" -++ } -++ }, -++ 512 -++ ] -++ } -++ } -++ }, -++ { -++ "counter": null -++ } -++] -+diff --git a/tests/py/ip6/ct.t.payload b/tests/py/ip6/ct.t.payload -+index 944208f2..a7a56d4b 100644 -+--- a/tests/py/ip6/ct.t.payload -++++ b/tests/py/ip6/ct.t.payload -+@@ -44,3 +44,15 @@ ip6 test-ip6 output -+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ] -+ [ bitwise reg 1 = ( reg 1 & 0x0000003c ) ^ 0x00000000 ] -+ [ ct set mark with reg 1 ] -++ -++# ct mark set ct mark | ip6 dscp | 0x200 counter -++ip6 test-ip6 output -++ [ ct load mark => reg 1 ] -++ [ payload load 2b @ network header + 0 => reg 2 ] -++ [ bitwise reg 2 = ( reg 2 & 0x0000c00f ) ^ 0x00000000 ] -++ [ byteorder reg 2 = ntoh(reg 2, 2, 2) ] -++ [ bitwise reg 2 = ( reg 2 >> 0x00000006 ) ] -++ [ bitwise reg 1 = ( reg 1 | reg 2 ) ] -++ [ bitwise reg 1 = ( reg 1 & 0xfffffdff ) ^ 0x00000200 ] -++ [ ct set mark with reg 1 ] -++ [ counter pkts 0 bytes 0 ] -+diff --git a/tests/shell/features/bitwise_multireg.nft b/tests/shell/features/bitwise_multireg.nft -+new file mode 100644 -+index 00000000..cfce5a39 -+--- /dev/null -++++ b/tests/shell/features/bitwise_multireg.nft -+@@ -0,0 +1,5 @@ -++table inet test { -++ chain y { -++ ct mark set ct mark | meta mark -++ } -++} -+diff --git a/tests/shell/testcases/bitwise/0040mark_binop_10 b/tests/shell/testcases/bitwise/0040mark_binop_10 -+new file mode 100755 -+index 00000000..f523bd73 -+--- /dev/null -++++ b/tests/shell/testcases/bitwise/0040mark_binop_10 -+@@ -0,0 +1,13 @@ -++#!/bin/bash -++ -++# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitwise_multireg) -++ -++set -e -++ -++RULESET=" -++ add table t -++ add chain t c { type filter hook output priority filter; } -++ add rule t c ct mark set ct mark and 0xffff0000 or meta mark and 0xffff -++" -++ -++$NFT -f - <<< "$RULESET" -+diff --git a/tests/shell/testcases/bitwise/0040mark_binop_11 b/tests/shell/testcases/bitwise/0040mark_binop_11 -+new file mode 100755 -+index 00000000..d6dfb3b8 -+--- /dev/null -++++ b/tests/shell/testcases/bitwise/0040mark_binop_11 -+@@ -0,0 +1,13 @@ -++#!/bin/bash -++ -++# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitwise_multireg) -++ -++set -e -++ -++RULESET=" -++ add table t -++ add chain t c { type filter hook input priority filter; } -++ add rule t c meta mark set ct mark and 0xffff0000 or meta mark and 0xffff -++" -++ -++$NFT -f - <<< "$RULESET" -+diff --git a/tests/shell/testcases/bitwise/0040mark_binop_12 b/tests/shell/testcases/bitwise/0040mark_binop_12 -+new file mode 100755 -+index 00000000..bbddb55b -+--- /dev/null -++++ b/tests/shell/testcases/bitwise/0040mark_binop_12 -+@@ -0,0 +1,13 @@ -++#!/bin/bash -++ -++# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitwise_multireg) -++ -++set -e -++ -++RULESET=" -++ add table ip6 t -++ add chain ip6 t c { type filter hook output priority filter; } -++ add rule ip6 t c ct mark set ct mark and 0xffff0000 or meta mark and 0xffff -++" -++ -++$NFT -f - <<< "$RULESET" -+diff --git a/tests/shell/testcases/bitwise/0040mark_binop_13 b/tests/shell/testcases/bitwise/0040mark_binop_13 -+new file mode 100755 -+index 00000000..769acb63 -+--- /dev/null -++++ b/tests/shell/testcases/bitwise/0040mark_binop_13 -+@@ -0,0 +1,13 @@ -++#!/bin/bash -++ -++# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitwise_multireg) -++ -++set -e -++ -++RULESET=" -++ add table ip6 t -++ add chain ip6 t c { type filter hook input priority filter; } -++ add rule ip6 t c meta mark set ct mark and 0xffff0000 or meta mark and 0xffff -++" -++ -++$NFT -f - <<< "$RULESET" -+diff --git a/tests/shell/testcases/bitwise/0044payload_binop_2 b/tests/shell/testcases/bitwise/0044payload_binop_2 -+new file mode 100755 -+index 00000000..13c4acef -+--- /dev/null -++++ b/tests/shell/testcases/bitwise/0044payload_binop_2 -+@@ -0,0 +1,13 @@ -++#!/bin/bash -++ -++# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitwise_multireg) -++ -++set -e -++ -++RULESET=" -++ add table t -++ add chain t c { type filter hook output priority filter; } -++ add rule t c ct mark set ct mark | ip dscp | 0x200 counter -++" -++ -++$NFT -f - <<< "$RULESET" -+diff --git a/tests/shell/testcases/bitwise/0044payload_binop_5 b/tests/shell/testcases/bitwise/0044payload_binop_5 -+new file mode 100755 -+index 00000000..7e8095c8 -+--- /dev/null -++++ b/tests/shell/testcases/bitwise/0044payload_binop_5 -+@@ -0,0 +1,13 @@ -++#!/bin/bash -++ -++# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitwise_multireg) -++ -++set -e -++ -++RULESET=" -++ add table ip6 t -++ add chain ip6 t c { type filter hook output priority filter; } -++ add rule ip6 t c ct mark set ct mark | ip6 dscp | 0x200 counter -++" -++ -++$NFT -f - <<< "$RULESET" -+diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_10.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_10.nft -+new file mode 100644 -+index 00000000..5566f729 -+--- /dev/null -++++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_10.nft -+@@ -0,0 +1,6 @@ -++table ip t { -++ chain c { -++ type filter hook output priority filter; policy accept; -++ ct mark set ct mark & 0xffff0000 | meta mark & 0x0000ffff -++ } -++} -+diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_11.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_11.nft -+new file mode 100644 -+index 00000000..719980d5 -+--- /dev/null -++++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_11.nft -+@@ -0,0 +1,6 @@ -++table ip t { -++ chain c { -++ type filter hook input priority filter; policy accept; -++ meta mark set ct mark & 0xffff0000 | meta mark & 0x0000ffff -++ } -++} -+diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_12.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_12.nft -+new file mode 100644 -+index 00000000..bd589fe5 -+--- /dev/null -++++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_12.nft -+@@ -0,0 +1,6 @@ -++table ip6 t { -++ chain c { -++ type filter hook output priority filter; policy accept; -++ ct mark set ct mark & 0xffff0000 | meta mark & 0x0000ffff -++ } -++} -+diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_13.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_13.nft -+new file mode 100644 -+index 00000000..2b046b12 -+--- /dev/null -++++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_13.nft -+@@ -0,0 +1,6 @@ -++table ip6 t { -++ chain c { -++ type filter hook input priority filter; policy accept; -++ meta mark set ct mark & 0xffff0000 | meta mark & 0x0000ffff -++ } -++} -+diff --git a/tests/shell/testcases/bitwise/dumps/0044payload_binop_2.nft b/tests/shell/testcases/bitwise/dumps/0044payload_binop_2.nft -+new file mode 100644 -+index 00000000..ed347bb2 -+--- /dev/null -++++ b/tests/shell/testcases/bitwise/dumps/0044payload_binop_2.nft -+@@ -0,0 +1,6 @@ -++table ip t { -++ chain c { -++ type filter hook output priority filter; policy accept; -++ ct mark set ct mark | ip dscp | 0x00000200 counter packets 0 bytes 0 -++ } -++} -+diff --git a/tests/shell/testcases/bitwise/dumps/0044payload_binop_5.nft b/tests/shell/testcases/bitwise/dumps/0044payload_binop_5.nft -+new file mode 100644 -+index 00000000..ccdb93d7 -+--- /dev/null -++++ b/tests/shell/testcases/bitwise/dumps/0044payload_binop_5.nft -+@@ -0,0 +1,6 @@ -++table ip6 t { -++ chain c { -++ type filter hook output priority filter; policy accept; -++ ct mark set ct mark | ip6 dscp | 0x00000200 counter packets 0 bytes 0 -++ } -++} -+-- -+cgit v1.2.3 -+ From a0e2dab9c3b7784f09f0f9969156d38011a7fc3b Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Wed, 8 Jul 2026 08:38:43 +1200 Subject: [PATCH 04/18] targets: force USE_APK=n in every diffconfig profile for the 25.12 bump On 24.10, USE_APK "depends on BROKEN" with no explicit default -- structurally unselectable, so no existing Gargoyle diffconfig ever needed to mention it. On 25.12, that "depends on BROKEN" is gone, replaced with "default y". An existing diffconfig that stays silent on USE_APK would pick up y automatically on a fresh make defconfig against the new base -- exactly the violation the whole two-stage bump strategy (base bump first with the legacy opkg backend unchanged, apk flip separately once ispyisail/gargoyle#39's backend is proven on-target) depends on avoiding. Added "# CONFIG_USE_APK is not set" to all 9 diffconfig-format profiles across the 4 targets the #1028 port already converted (x86 x5 profiles, mediatek x2, ath79 x2, ipq40xx x1), alphabetically placed immediately before the existing USE_FS_ACL_ATTR line already present in every one of them. The 7 remaining full-config targets are untouched here -- they stay in their existing full-config form until B5 converts them against a real 25.12 buildroot, per the #1028 port's own original sequencing decision. Not yet verified that this override survives a real make defconfig against a genuine 25.12 buildroot -- that needs full feeds/toolchain setup and is the first thing the next phase (B2, x86 full build) must confirm. --- targets/ath79/profiles/default/config | 1 + targets/ath79/profiles/nand/config | 1 + targets/ipq40xx/profiles/default/config | 1 + targets/mediatek/profiles/default/config | 1 + targets/mediatek/profiles/filogic/config | 1 + targets/x86/profiles/alix/config | 1 + targets/x86/profiles/default/config | 1 + targets/x86/profiles/vnet-wifi/config | 1 + targets/x86/profiles/x64-wifi/config | 1 + targets/x86/profiles/x64/config | 1 + 10 files changed, 10 insertions(+) diff --git a/targets/ath79/profiles/default/config b/targets/ath79/profiles/default/config index 7b9169d06..f8e8ac4c8 100644 --- a/targets/ath79/profiles/default/config +++ b/targets/ath79/profiles/default/config @@ -246,6 +246,7 @@ CONFIG_PACKAGE_uboot-envtools=m CONFIG_PACKAGE_wpad-basic-mbedtls=m CONFIG_PACKAGE_wpad-openssl=m CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=1024 +# CONFIG_USE_APK is not set # CONFIG_USE_FS_ACL_ATTR is not set CONFIG_GARGOYLE_SMB_KSMBD=y # CONFIG_GARGOYLE_SMB_SAMBA is not set diff --git a/targets/ath79/profiles/nand/config b/targets/ath79/profiles/nand/config index 48dd06019..3d0d841eb 100644 --- a/targets/ath79/profiles/nand/config +++ b/targets/ath79/profiles/nand/config @@ -150,6 +150,7 @@ CONFIG_PACKAGE_wpad-openssl=m CONFIG_PACKAGE_wwan=y CONFIG_PACKAGE_zlib=y CONFIG_TARGET_SQUASHFS_BLOCK_SIZE=512 +# CONFIG_USE_APK is not set # CONFIG_USE_FS_ACL_ATTR is not set CONFIG_GARGOYLE_SMB_KSMBD=y # CONFIG_GARGOYLE_SMB_SAMBA is not set diff --git a/targets/ipq40xx/profiles/default/config b/targets/ipq40xx/profiles/default/config index b215f740f..1e00fb9a9 100644 --- a/targets/ipq40xx/profiles/default/config +++ b/targets/ipq40xx/profiles/default/config @@ -132,6 +132,7 @@ CONFIG_PACKAGE_wpad-basic-mbedtls=m CONFIG_PACKAGE_wpad-openssl=m CONFIG_PACKAGE_wwan=y CONFIG_PACKAGE_zlib=y +# CONFIG_USE_APK is not set # CONFIG_USE_FS_ACL_ATTR is not set CONFIG_GARGOYLE_SMB_KSMBD=y # CONFIG_GARGOYLE_SMB_SAMBA is not set diff --git a/targets/mediatek/profiles/default/config b/targets/mediatek/profiles/default/config index 092471f01..e77758eed 100644 --- a/targets/mediatek/profiles/default/config +++ b/targets/mediatek/profiles/default/config @@ -101,6 +101,7 @@ CONFIG_PACKAGE_wpad-openssl=m CONFIG_TARGET_INITRAMFS_COMPRESSION_NONE=y # CONFIG_TARGET_INITRAMFS_COMPRESSION_XZ is not set CONFIG_TARGET_ROOTFS_PARTSIZE=104 +# CONFIG_USE_APK is not set # CONFIG_USE_FS_ACL_ATTR is not set # CONFIG_ATH9K_HWRNG is not set CONFIG_GARGOYLE_SMB_KSMBD=y diff --git a/targets/mediatek/profiles/filogic/config b/targets/mediatek/profiles/filogic/config index 114804557..7fd292fe0 100644 --- a/targets/mediatek/profiles/filogic/config +++ b/targets/mediatek/profiles/filogic/config @@ -148,6 +148,7 @@ CONFIG_PACKAGE_wpad-openssl=m CONFIG_TARGET_INITRAMFS_COMPRESSION_NONE=y # CONFIG_TARGET_INITRAMFS_COMPRESSION_XZ is not set CONFIG_TARGET_ROOTFS_PARTSIZE=104 +# CONFIG_USE_APK is not set # CONFIG_USE_FS_ACL_ATTR is not set # CONFIG_ATH9K_HWRNG is not set CONFIG_GARGOYLE_SMB_KSMBD=y diff --git a/targets/x86/profiles/alix/config b/targets/x86/profiles/alix/config index 340fd9408..042cd1d73 100644 --- a/targets/x86/profiles/alix/config +++ b/targets/x86/profiles/alix/config @@ -101,6 +101,7 @@ CONFIG_PACKAGE_r8169-firmware=y # CONFIG_PACKAGE_wpad-mbedtls is not set # CONFIG_TARGET_EXT4_JOURNAL is not set CONFIG_TARGET_ROOTFS_PARTSIZE=256 +# CONFIG_USE_APK is not set # CONFIG_USE_FS_ACL_ATTR is not set CONFIG_GARGOYLE_SMB_KSMBD=y # CONFIG_GARGOYLE_SMB_SAMBA is not set diff --git a/targets/x86/profiles/default/config b/targets/x86/profiles/default/config index dfe9cc843..68ba7cd6d 100644 --- a/targets/x86/profiles/default/config +++ b/targets/x86/profiles/default/config @@ -72,6 +72,7 @@ CONFIG_PACKAGE_plugin-gargoyle-upnp=y # CONFIG_PACKAGE_wpad-mbedtls is not set # CONFIG_TARGET_EXT4_JOURNAL is not set CONFIG_TARGET_ROOTFS_PARTSIZE=256 +# CONFIG_USE_APK is not set # CONFIG_USE_FS_ACL_ATTR is not set CONFIG_GARGOYLE_SMB_KSMBD=y # CONFIG_GARGOYLE_SMB_SAMBA is not set diff --git a/targets/x86/profiles/vnet-wifi/config b/targets/x86/profiles/vnet-wifi/config index 2782f066c..dc30394d5 100644 --- a/targets/x86/profiles/vnet-wifi/config +++ b/targets/x86/profiles/vnet-wifi/config @@ -85,6 +85,7 @@ CONFIG_PACKAGE_wireless-regdb=y CONFIG_PACKAGE_wpa-cli=y # CONFIG_TARGET_EXT4_JOURNAL is not set CONFIG_TARGET_ROOTFS_PARTSIZE=256 +# CONFIG_USE_APK is not set # CONFIG_USE_FS_ACL_ATTR is not set CONFIG_GARGOYLE_SMB_KSMBD=y # CONFIG_GARGOYLE_SMB_SAMBA is not set diff --git a/targets/x86/profiles/x64-wifi/config b/targets/x86/profiles/x64-wifi/config index a5841da62..cbd84bc9d 100644 --- a/targets/x86/profiles/x64-wifi/config +++ b/targets/x86/profiles/x64-wifi/config @@ -89,6 +89,7 @@ CONFIG_PACKAGE_wireless-regdb=y CONFIG_PACKAGE_wpa-cli=y # CONFIG_TARGET_EXT4_JOURNAL is not set CONFIG_TARGET_ROOTFS_PARTSIZE=256 +# CONFIG_USE_APK is not set # CONFIG_USE_FS_ACL_ATTR is not set CONFIG_GARGOYLE_SMB_KSMBD=y # CONFIG_GARGOYLE_SMB_SAMBA is not set diff --git a/targets/x86/profiles/x64/config b/targets/x86/profiles/x64/config index e4926f274..4d781ae99 100644 --- a/targets/x86/profiles/x64/config +++ b/targets/x86/profiles/x64/config @@ -77,6 +77,7 @@ CONFIG_PACKAGE_plugin-gargoyle-upnp=y # CONFIG_PACKAGE_wpad-mbedtls is not set # CONFIG_TARGET_EXT4_JOURNAL is not set CONFIG_TARGET_ROOTFS_PARTSIZE=256 +# CONFIG_USE_APK is not set # CONFIG_USE_FS_ACL_ATTR is not set CONFIG_GARGOYLE_SMB_KSMBD=y # CONFIG_GARGOYLE_SMB_SAMBA is not set From 38ff3ae9867fc21cd8700f6928bbf7e4e624795b Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Wed, 8 Jul 2026 16:21:16 +1200 Subject: [PATCH 05/18] targets/x86: re-derive all 5 diffconfigs against the 25.12 kernel/package tree make defconfig -> scripts/diffconfig.sh -> byte-identical round-trip verify for each profile (default, alix, vnet-wifi, x64, x64-wifi), per the established #1028-port method -- never hand-edited. Every diff is explained by real 25.12-era Kconfig drift, confirmed via the resolved .config, not a functional change: - CONFIG_KERNEL_EROFS_FS_POSIX_ACL: new kernel option in 25.12's Config-kernel.in, resolves to off (matches every other *_POSIX_ACL default in these profiles). - CONFIG_PACKAGE_apk-mbedtls: new package (apk's own mbedtls crypto backend), resolves to off -- consistent with Stage 1's USE_APK=n. - kmod-video-async/kmod-video-cpia2/kmod-video-fwnode: these Kconfig symbols no longer exist anywhere in the 25.12 kernel tree (confirmed via grep -- upstream media-subsystem restructuring between 6.6 and 6.12), so the old "not set" lines were pure noise referencing nonexistent options. - ucode-mod-uloop / ucode-mod-digest: both remain enabled in the real resolved .config for every profile that had them before (confirmed via grep) -- diffconfig.sh's minimizer just picked a different implied-vs-explicit split of which lines are needed to reproduce the same resolved state, not a package selection change. - kmod-i2c-core (alix only): newly appears as an explicit `=y` line; also confirmed present and enabled in the resolved .config. CONFIG_USE_APK is not set survived in all 5 re-derived profiles, confirming Stage 1's diffconfig fix from B1 is still correctly resolved. --- targets/x86/profiles/alix/config | 7 +++---- targets/x86/profiles/default/config | 6 ++---- targets/x86/profiles/vnet-wifi/config | 7 +++---- targets/x86/profiles/x64-wifi/config | 7 +++---- targets/x86/profiles/x64/config | 6 ++---- 5 files changed, 13 insertions(+), 20 deletions(-) diff --git a/targets/x86/profiles/alix/config b/targets/x86/profiles/alix/config index 042cd1d73..49292a400 100644 --- a/targets/x86/profiles/alix/config +++ b/targets/x86/profiles/alix/config @@ -17,6 +17,7 @@ CONFIG_GRUB_TITLE="Gargoyle" # CONFIG_KERNEL_BTRFS_FS_POSIX_ACL is not set # CONFIG_KERNEL_CGROUPS is not set # CONFIG_KERNEL_CIFS_ACL is not set +# CONFIG_KERNEL_EROFS_FS_POSIX_ACL is not set # CONFIG_KERNEL_EXT4_FS_POSIX_ACL is not set # CONFIG_KERNEL_EXT4_FS_SECURITY is not set # CONFIG_KERNEL_F2FS_FS_POSIX_ACL is not set @@ -44,6 +45,7 @@ CONFIG_KERNEL_IO_URING=y # CONFIG_OPENSSL_WITH_SEED is not set CONFIG_OPENSSL_WITH_SSE2=y # CONFIG_OPENSSL_WITH_WHIRLPOOL is not set +# CONFIG_PACKAGE_apk-mbedtls is not set CONFIG_PACKAGE_e100-firmware=y # CONFIG_PACKAGE_gargoyle-large is not set CONFIG_PACKAGE_hostapd-common=m @@ -55,6 +57,7 @@ CONFIG_PACKAGE_kmod-e100=y CONFIG_PACKAGE_kmod-e1000=y CONFIG_PACKAGE_kmod-gre=y CONFIG_PACKAGE_kmod-hwmon-core=y +CONFIG_PACKAGE_kmod-i2c-core=y CONFIG_PACKAGE_kmod-iptunnel=y # CONFIG_PACKAGE_kmod-ledtrig-gpio is not set CONFIG_PACKAGE_kmod-lib-zlib-deflate=y @@ -239,10 +242,7 @@ CONFIG_PACKAGE_kmod-usb-storage=y CONFIG_PACKAGE_kmod-usb-storage-extras=y CONFIG_PACKAGE_kmod-usb-storage-uas=y CONFIG_PACKAGE_kmod-usb-wdm=y -# CONFIG_PACKAGE_kmod-video-async is not set CONFIG_PACKAGE_kmod-video-core=y -# CONFIG_PACKAGE_kmod-video-cpia2 is not set -# CONFIG_PACKAGE_kmod-video-fwnode is not set # CONFIG_PACKAGE_kmod-video-gspca-conex is not set CONFIG_PACKAGE_kmod-video-gspca-core=y # CONFIG_PACKAGE_kmod-video-gspca-etoms is not set @@ -342,7 +342,6 @@ CONFIG_PACKAGE_tc-tiny=y CONFIG_PACKAGE_terminfo=y CONFIG_PACKAGE_ucode-mod-nl80211=y CONFIG_PACKAGE_ucode-mod-rtnl=y -CONFIG_PACKAGE_ucode-mod-uloop=y CONFIG_PACKAGE_umbim=y CONFIG_PACKAGE_uqmi=y CONFIG_PACKAGE_usb-modeswitch=y diff --git a/targets/x86/profiles/default/config b/targets/x86/profiles/default/config index 68ba7cd6d..64bca8999 100644 --- a/targets/x86/profiles/default/config +++ b/targets/x86/profiles/default/config @@ -16,6 +16,7 @@ CONFIG_GRUB_TITLE="Gargoyle" # CONFIG_KERNEL_BTRFS_FS_POSIX_ACL is not set # CONFIG_KERNEL_CGROUPS is not set # CONFIG_KERNEL_CIFS_ACL is not set +# CONFIG_KERNEL_EROFS_FS_POSIX_ACL is not set # CONFIG_KERNEL_EXT4_FS_POSIX_ACL is not set # CONFIG_KERNEL_EXT4_FS_SECURITY is not set # CONFIG_KERNEL_F2FS_FS_POSIX_ACL is not set @@ -42,6 +43,7 @@ CONFIG_KERNEL_IO_URING=y # CONFIG_OPENSSL_WITH_MDC2 is not set # CONFIG_OPENSSL_WITH_SEED is not set # CONFIG_OPENSSL_WITH_WHIRLPOOL is not set +# CONFIG_PACKAGE_apk-mbedtls is not set # CONFIG_PACKAGE_gargoyle-large is not set CONFIG_PACKAGE_hostapd-common=m CONFIG_PACKAGE_kmod-crypto-md4=y @@ -214,10 +216,7 @@ CONFIG_PACKAGE_kmod-usb-storage=y CONFIG_PACKAGE_kmod-usb-storage-extras=y CONFIG_PACKAGE_kmod-usb-storage-uas=y CONFIG_PACKAGE_kmod-usb-wdm=y -# CONFIG_PACKAGE_kmod-video-async is not set CONFIG_PACKAGE_kmod-video-core=y -# CONFIG_PACKAGE_kmod-video-cpia2 is not set -# CONFIG_PACKAGE_kmod-video-fwnode is not set # CONFIG_PACKAGE_kmod-video-gspca-conex is not set CONFIG_PACKAGE_kmod-video-gspca-core=y # CONFIG_PACKAGE_kmod-video-gspca-etoms is not set @@ -318,7 +317,6 @@ CONFIG_PACKAGE_tc-tiny=y CONFIG_PACKAGE_terminfo=y CONFIG_PACKAGE_ucode-mod-nl80211=y CONFIG_PACKAGE_ucode-mod-rtnl=y -CONFIG_PACKAGE_ucode-mod-uloop=y CONFIG_PACKAGE_umbim=y CONFIG_PACKAGE_uqmi=y CONFIG_PACKAGE_usb-modeswitch=y diff --git a/targets/x86/profiles/vnet-wifi/config b/targets/x86/profiles/vnet-wifi/config index dc30394d5..2811a6927 100644 --- a/targets/x86/profiles/vnet-wifi/config +++ b/targets/x86/profiles/vnet-wifi/config @@ -19,6 +19,7 @@ CONFIG_GRUB_TITLE="Gargoyle" # CONFIG_KERNEL_BTRFS_FS_POSIX_ACL is not set # CONFIG_KERNEL_CGROUPS is not set # CONFIG_KERNEL_CIFS_ACL is not set +# CONFIG_KERNEL_EROFS_FS_POSIX_ACL is not set # CONFIG_KERNEL_EXT4_FS_POSIX_ACL is not set # CONFIG_KERNEL_EXT4_FS_SECURITY is not set # CONFIG_KERNEL_F2FS_FS_POSIX_ACL is not set @@ -45,6 +46,7 @@ CONFIG_KERNEL_IO_URING=y # CONFIG_OPENSSL_WITH_MDC2 is not set # CONFIG_OPENSSL_WITH_SEED is not set # CONFIG_OPENSSL_WITH_WHIRLPOOL is not set +# CONFIG_PACKAGE_apk-mbedtls is not set # CONFIG_PACKAGE_gargoyle-large is not set CONFIG_PACKAGE_iw=y CONFIG_PACKAGE_iwinfo=y @@ -80,6 +82,7 @@ CONFIG_PACKAGE_plugin-gargoyle-captive-portal=y CONFIG_PACKAGE_plugin-gargoyle-qr-code=y CONFIG_PACKAGE_plugin-gargoyle-stamgr=y CONFIG_PACKAGE_plugin-gargoyle-upnp=y +CONFIG_PACKAGE_ucode-mod-digest=y CONFIG_PACKAGE_wifi-scripts=y CONFIG_PACKAGE_wireless-regdb=y CONFIG_PACKAGE_wpa-cli=y @@ -213,10 +216,7 @@ CONFIG_PACKAGE_kmod-usb-storage=y CONFIG_PACKAGE_kmod-usb-storage-extras=y CONFIG_PACKAGE_kmod-usb-storage-uas=y CONFIG_PACKAGE_kmod-usb-wdm=y -# CONFIG_PACKAGE_kmod-video-async is not set CONFIG_PACKAGE_kmod-video-core=y -# CONFIG_PACKAGE_kmod-video-cpia2 is not set -# CONFIG_PACKAGE_kmod-video-fwnode is not set # CONFIG_PACKAGE_kmod-video-gspca-conex is not set CONFIG_PACKAGE_kmod-video-gspca-core=y # CONFIG_PACKAGE_kmod-video-gspca-etoms is not set @@ -315,7 +315,6 @@ CONFIG_PACKAGE_rpcbind=y CONFIG_PACKAGE_share-users=y CONFIG_PACKAGE_tc-tiny=y CONFIG_PACKAGE_terminfo=y -CONFIG_PACKAGE_ucode-mod-uloop=y CONFIG_PACKAGE_umbim=y CONFIG_PACKAGE_uqmi=y CONFIG_PACKAGE_usb-modeswitch=y diff --git a/targets/x86/profiles/x64-wifi/config b/targets/x86/profiles/x64-wifi/config index cbd84bc9d..5de1ab8fb 100644 --- a/targets/x86/profiles/x64-wifi/config +++ b/targets/x86/profiles/x64-wifi/config @@ -20,6 +20,7 @@ CONFIG_GRUB_TITLE="Gargoyle" # CONFIG_KERNEL_BTRFS_FS_POSIX_ACL is not set # CONFIG_KERNEL_CGROUPS is not set # CONFIG_KERNEL_CIFS_ACL is not set +# CONFIG_KERNEL_EROFS_FS_POSIX_ACL is not set # CONFIG_KERNEL_EXT4_FS_POSIX_ACL is not set # CONFIG_KERNEL_EXT4_FS_SECURITY is not set # CONFIG_KERNEL_F2FS_FS_POSIX_ACL is not set @@ -47,6 +48,7 @@ CONFIG_OPENSSL_PREFER_CHACHA_OVER_GCM=y # CONFIG_OPENSSL_WITH_SEED is not set # CONFIG_OPENSSL_WITH_WHIRLPOOL is not set CONFIG_OPENVPN_gargoyle_mbedtls_ENABLE_LZO=y +# CONFIG_PACKAGE_apk-mbedtls is not set CONFIG_PACKAGE_bnx2-firmware=m # CONFIG_PACKAGE_gargoyle-large is not set CONFIG_PACKAGE_iw=y @@ -84,6 +86,7 @@ CONFIG_PACKAGE_plugin-gargoyle-captive-portal=y CONFIG_PACKAGE_plugin-gargoyle-qr-code=y CONFIG_PACKAGE_plugin-gargoyle-stamgr=y CONFIG_PACKAGE_plugin-gargoyle-upnp=y +CONFIG_PACKAGE_ucode-mod-digest=y CONFIG_PACKAGE_wifi-scripts=y CONFIG_PACKAGE_wireless-regdb=y CONFIG_PACKAGE_wpa-cli=y @@ -217,10 +220,7 @@ CONFIG_PACKAGE_kmod-usb-storage=y CONFIG_PACKAGE_kmod-usb-storage-extras=y CONFIG_PACKAGE_kmod-usb-storage-uas=y CONFIG_PACKAGE_kmod-usb-wdm=y -# CONFIG_PACKAGE_kmod-video-async is not set CONFIG_PACKAGE_kmod-video-core=y -# CONFIG_PACKAGE_kmod-video-cpia2 is not set -# CONFIG_PACKAGE_kmod-video-fwnode is not set # CONFIG_PACKAGE_kmod-video-gspca-conex is not set CONFIG_PACKAGE_kmod-video-gspca-core=y # CONFIG_PACKAGE_kmod-video-gspca-etoms is not set @@ -319,7 +319,6 @@ CONFIG_PACKAGE_rpcbind=y CONFIG_PACKAGE_share-users=y CONFIG_PACKAGE_tc-tiny=y CONFIG_PACKAGE_terminfo=y -CONFIG_PACKAGE_ucode-mod-uloop=y CONFIG_PACKAGE_umbim=y CONFIG_PACKAGE_uqmi=y CONFIG_PACKAGE_usb-modeswitch=y diff --git a/targets/x86/profiles/x64/config b/targets/x86/profiles/x64/config index 4d781ae99..26beb0170 100644 --- a/targets/x86/profiles/x64/config +++ b/targets/x86/profiles/x64/config @@ -17,6 +17,7 @@ CONFIG_GRUB_TITLE="Gargoyle" # CONFIG_KERNEL_BTRFS_FS_POSIX_ACL is not set # CONFIG_KERNEL_CGROUPS is not set # CONFIG_KERNEL_CIFS_ACL is not set +# CONFIG_KERNEL_EROFS_FS_POSIX_ACL is not set # CONFIG_KERNEL_EXT4_FS_POSIX_ACL is not set # CONFIG_KERNEL_EXT4_FS_SECURITY is not set # CONFIG_KERNEL_F2FS_FS_POSIX_ACL is not set @@ -44,6 +45,7 @@ CONFIG_OPENSSL_PREFER_CHACHA_OVER_GCM=y # CONFIG_OPENSSL_WITH_SEED is not set # CONFIG_OPENSSL_WITH_WHIRLPOOL is not set CONFIG_OPENVPN_gargoyle_mbedtls_ENABLE_LZO=y +# CONFIG_PACKAGE_apk-mbedtls is not set CONFIG_PACKAGE_bnx2-firmware=m # CONFIG_PACKAGE_gargoyle-large is not set CONFIG_PACKAGE_hostapd-common=m @@ -73,7 +75,6 @@ CONFIG_PACKAGE_miniupnpd-nftables=y CONFIG_PACKAGE_openssl-util=m CONFIG_PACKAGE_plugin-gargoyle-qr-code=y CONFIG_PACKAGE_plugin-gargoyle-upnp=y -# CONFIG_PACKAGE_ucode-mod-uloop is not set # CONFIG_PACKAGE_wpad-mbedtls is not set # CONFIG_TARGET_EXT4_JOURNAL is not set CONFIG_TARGET_ROOTFS_PARTSIZE=256 @@ -219,10 +220,7 @@ CONFIG_PACKAGE_kmod-usb-storage=y CONFIG_PACKAGE_kmod-usb-storage-extras=y CONFIG_PACKAGE_kmod-usb-storage-uas=y CONFIG_PACKAGE_kmod-usb-wdm=y -# CONFIG_PACKAGE_kmod-video-async is not set CONFIG_PACKAGE_kmod-video-core=y -# CONFIG_PACKAGE_kmod-video-cpia2 is not set -# CONFIG_PACKAGE_kmod-video-fwnode is not set # CONFIG_PACKAGE_kmod-video-gspca-conex is not set CONFIG_PACKAGE_kmod-video-gspca-core=y # CONFIG_PACKAGE_kmod-video-gspca-etoms is not set From b562175660ebf2f704299de3655eea60512aa837 Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Thu, 9 Jul 2026 21:42:04 +1200 Subject: [PATCH 06/18] patches: add 029 CMAKE_POLICY_VERSION_MINIMUM for CMake 4 CMake 4.x (bundled in the 25.12 host toolchain) hard-rejects any package whose own CMakeLists.txt declares cmake_minimum_required below 3.5 (hit libid3tag, lzo; likely more packages carry the same old CMakeLists.txt pattern). Fixed globally via -DCMAKE_POLICY_VERSION_MINIMUM=3.5 in include/cmake.mk's target and host cmake invocations, rather than patching every package individually as each one surfaces. --- .../029-cmake_policy_version_minimum.patch | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 patches-generic/029-cmake_policy_version_minimum.patch diff --git a/patches-generic/029-cmake_policy_version_minimum.patch b/patches-generic/029-cmake_policy_version_minimum.patch new file mode 100644 index 000000000..ba2f36427 --- /dev/null +++ b/patches-generic/029-cmake_policy_version_minimum.patch @@ -0,0 +1,18 @@ +--- a/include/cmake.mk ++++ b/include/cmake.mk +@@ -94,6 +94,7 @@ + LDFLAGS="$(TARGET_LDFLAGS) $(EXTRA_LDFLAGS)" \ + cmake \ + --no-warn-unused-cli \ ++ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ + -DCMAKE_SYSTEM_NAME=Linux \ + -DCMAKE_SYSTEM_VERSION=1 \ + -DCMAKE_SYSTEM_PROCESSOR=$(ARCH) \ +@@ -147,6 +148,7 @@ + LDFLAGS="$(HOST_LDFLAGS)" \ + cmake \ + --no-warn-unused-cli \ ++ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_C_COMPILER_LAUNCHER="$(CMAKE_C_COMPILER_LAUNCHER)" \ + -DCMAKE_C_COMPILER="$(CMAKE_HOST_C_COMPILER)" \ From 7de746a9176ba443cdf67885f04b6d2223983ad5 Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Thu, 9 Jul 2026 21:42:24 +1200 Subject: [PATCH 07/18] mbedtls-clu, https-dns-proxy, libffi: fix hash drift and autoreconf breakage mbedtls-clu and https-dns-proxy: PKG_MIRROR_HASH no longer matches a fresh git-archive of the exact pinned commit -- the archive-generation mechanism itself changed between 24.10 and 25.12, not the source content. Verified by re-checking out each pinned commit fresh and confirming the new hash is reproducible. Updated the hash constants. libffi: PKG_FIXUP:=autoreconf regenerates the build system with this toolchain's newer host autoconf/automake, which introduces a build-vs-host triplet mismatch ("No rule to make target 'all-configured'"). libffi 3.4.6's release tarball already ships a working, upstream-tested ./configure; removed the fixup rather than chasing the newer autoconf's behavior change. --- package/https-dns-proxy/Makefile | 2 +- package/libffi/Makefile | 12 +++++++++++- package/mbedtls-clu/Makefile | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/package/https-dns-proxy/Makefile b/package/https-dns-proxy/Makefile index 199230952..be980ba78 100644 --- a/package/https-dns-proxy/Makefile +++ b/package/https-dns-proxy/Makefile @@ -8,7 +8,7 @@ PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/aarond10/https_dns_proxy/ PKG_SOURCE_DATE:=$(PKG_VERSION) PKG_SOURCE_VERSION:=977341a4e35a37ee454e97e82caf4276b1b4961a -PKG_MIRROR_HASH:=8622846f1038ac05436a48d9b36a07c516cbb6504ce68e7ee8c5529788fac39b +PKG_MIRROR_HASH:=7387a63120f627d81a75e6049ecb55c0d62f86f21863084a0b1fc473c43790e4 PKG_MAINTAINER:=Michael Gray PKG_LICENSE:=MIT diff --git a/package/libffi/Makefile b/package/libffi/Makefile index aba83e22c..c6bc67516 100644 --- a/package/libffi/Makefile +++ b/package/libffi/Makefile @@ -19,7 +19,17 @@ PKG_LICENSE:=MIT PKG_LICENSE_FILES:=LICENSE PKG_CPE_ID:=cpe:/a:libffi_project:libffi -PKG_FIXUP:=autoreconf +# PKG_FIXUP:=autoreconf intentionally NOT set: re-running autoreconf with +# this toolchain's newer host autoconf/automake (bumped alongside GCC/CMake +# for the 25.12 base) regenerates libffi's build system with a build-vs-host +# triplet mismatch (recurses into a "x86_64-pc-linux-musl"-named target that +# was never actually configured, since the real cross build configured +# "x86_64-openwrt-linux-gnu" instead) -- "No rule to make target +# 'all-configured'". libffi 3.4.6's release tarball ships a working, +# upstream-tested ./configure already; skipping autoreconf avoids the +# regression entirely and needs no other changes since x86_64 is a +# long-standard architecture (autoreconf's usual purpose -- refreshing +# config.sub/config.guess for newer targets -- doesn't apply here). PKG_INSTALL:=1 PKG_BUILD_PARALLEL:=1 PKG_BUILD_FLAGS:=no-mips16 diff --git a/package/mbedtls-clu/Makefile b/package/mbedtls-clu/Makefile index d57f4acac..99bc0b9c2 100644 --- a/package/mbedtls-clu/Makefile +++ b/package/mbedtls-clu/Makefile @@ -10,7 +10,7 @@ MAKE_PATH:=src PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=https://github.com/lantis1008/mbedtls-clu.git -PKG_MIRROR_HASH:=79eef689b7fd1323c69a5c6a3f03e4829181f014c77cdacb5b5a904b42ee34c7 +PKG_MIRROR_HASH:=54875e65da5537088dcd2334381fef0d7111ad30842b16790b391ab66390574e # Set to 1 to dynamically link libericstools, or 0 to static compile DLINK_LIBERICSTOOLS:=1 From 029242f7f5797cbcdf1013dd259976621475c504 Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Wed, 8 Jul 2026 10:47:08 +1200 Subject: [PATCH 08/18] libbbtargz: fix GCC 14 implicit-function-declaration build failure unarchive.c calls seek_by_read() with no prior prototype (2007-era code extracted from busybox with the declaration left behind). GCC 14 (first used by this toolchain as of the 25.12 bump) makes implicit function declarations a hard error by default, where GCC <= 13 only warned -- breaking this package's build outright and, with it, image assembly for every x86 profile in the B2 full build. Same root cause and same fix already validated for the host-side gapk dev-loop build (tests/gapk/build-host.sh in gargoyle-tools); applying the identical workaround here rather than trying to source/restore the real prototype from 2007-era upstream busybox code. --- package/libbbtargz/Makefile | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/package/libbbtargz/Makefile b/package/libbbtargz/Makefile index 96ce25626..12f014aa1 100644 --- a/package/libbbtargz/Makefile +++ b/package/libbbtargz/Makefile @@ -19,6 +19,18 @@ PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) include $(INCLUDE_DIR)/package.mk +# unarchive.c calls seek_by_read() with no prior prototype (2007-era +# code, extracted from busybox with the declaration left behind). +# GCC <= 13 only warned; GCC 14 (first used by this toolchain as of +# the OpenWrt 25.12 bump) makes implicit function declarations a hard +# error by default, which breaks this package's build outright. Same +# root cause and same fix already validated for the host-side gapk +# dev-loop build (tests/gapk/build-host.sh in gargoyle-tools) -- +# applying the identical, already-proven workaround here rather than +# attempting to source/restore the real prototype from upstream +# busybox for 2007-era code neither of us has full context on. +TARGET_CFLAGS += -std=gnu89 -Wno-implicit-function-declaration + define Package/libbbtargz SECTION:=libs CATEGORY:=Libraries From 154271bd7c889b9cb5621fd602b825141566ac20 Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Wed, 8 Jul 2026 12:04:26 +1200 Subject: [PATCH 09/18] zip: fix GCC 14 build failure from broken cross-compile probes package/zip's stock "generic" build target runs unix/configure's feature-detection probes, which try to compile+link+run tiny test programs -- impossible under cross-compilation, so every probe silently assumes the worst and falls back to a batch of "-DNO_*"/ "-DZMEM" defines selecting zip's own bundled 2008-era K&R-style fallback implementations (memset/mktime/etc), each guarded by a hand-written prototype that assumes no real ANSI / exists. musl provides working, conformant versions of every one of these, so the whole batch has always been a false positive for this cross build -- GCC <= 13 only warned about the resulting conflicts; GCC 14 (new in this toolchain, 25.12) makes them hard errors ("conflicting types for 'memset'", "invalid use of undefined type 'struct tm'"). Split Build/Compile into two steps (generate flags, strip the whole -DNO_*/-DZMEM batch, then build) instead of patching zip's own Makefile/configure or whack-a-moling one define at a time as each newly becomes a hard error. Added a matching Build/Install since the override replaces the stock MAKE_FLAGS-based generic+install combo. Verified via a real scoped compile: zip_3.0-r5_x86_64.ipk now builds clean. --- package/zip/Makefile | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/package/zip/Makefile b/package/zip/Makefile index ed1c83f42..21a2f961a 100644 --- a/package/zip/Makefile +++ b/package/zip/Makefile @@ -41,12 +41,40 @@ define Package/zip/description but the methods differ. endef -MAKE_FLAGS += \ - -f unix/Makefile generic \ - prefix="$(PKG_INSTALL_DIR)/usr" \ - CFLAGS="$(TARGET_CFLAGS)" \ +# The stock "generic" target's unix/configure runs feature-detection +# probes that try to compile+link+run tiny test programs -- impossible +# under cross-compilation, so every probe silently assumes the worst +# and falls back to a batch of "-DNO_*"/"-DZMEM" defines that select +# zip's own bundled, K&R-style fallback implementations (of memset, +# mktime, etc, each guarded by a hand-written prototype in zip.h/ +# timezone.c that assumes no real ANSI / exists). +# musl provides working, ANSI-conformant versions of every one of these +# (memset/memcpy/memcmp, rmdir, strchr/strrchr, rename, mktemp/mkstemp/ +# mktime, errno, dirent, valloc), so every one of these defines is, and +# always has been, a false positive for this cross build -- GCC <= 13 +# only warned about the resulting prototype conflicts/incomplete-type +# uses; GCC 14 (first used by this toolchain, 25.12) makes them hard +# errors. Split configure and build into two steps so the generated +# flags file can have the whole false-positive batch stripped in +# between, instead of patching zip's own 2008-era unix/Makefile or +# unix/configure, or whack-a-moling one -DNO_* at a time as each newly +# becomes a hard error. +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) \ + -f unix/Makefile flags \ CC="$(TARGET_CC) $(TARGET_CFLAGS) -O $(TARGET_CPPFLAGS) -I. -DUNIX $(TARGET_LDFLAGS)" \ IZ_BZIP2="no" + sed -i -E 's/-D(NO_[A-Z0-9_]+|ZMEM)//g' $(PKG_BUILD_DIR)/flags + cd $(PKG_BUILD_DIR); eval $(MAKE) -f unix/Makefile zips `cat $(PKG_BUILD_DIR)/flags` \ + prefix="$(PKG_INSTALL_DIR)/usr" \ + IZ_BZIP2="no" +endef + +define Build/Install + $(MAKE) -C $(PKG_BUILD_DIR) \ + -f unix/Makefile install \ + prefix="$(PKG_INSTALL_DIR)/usr" +endef define Package/zip/install $(INSTALL_DIR) $(1)/usr/bin/ From d8f1f677b9b6323caecd4687551bd29abea636f0 Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Wed, 8 Jul 2026 15:29:34 +1200 Subject: [PATCH 10/18] samba36: fix 2 GCC14 build failures (mkdir macro collision, missing include) Two unrelated GCC14-newly-fatal issues found compiling this legacy (3.6.25) samba build: - smbd/vfs.c: samba's own libreplace shim conditionally redefines mkdir(dir, mode) -> mkdir(dir) when its own configure probe decides the target's real mkdir() doesn't support a mode argument. That probe's test program (lib/replace's HAVE_MKDIR_MODE check) never includes , so mkdir() has no visible prototype in the probe itself -- GCC <= 13 only warned on the resulting implicit declaration, letting the probe "succeed"; GCC 14 makes it a hard error, flipping the cached result to "no" and activating the 2-arg replacement macro. That macro then collides at the token level with an unrelated 3-arg handle->fns->mkdir(handle, path, mode) vfs member-function call elsewhere in the same file (C macros don't respect struct member access syntax). Fixed the same way this Makefile already works around many other broken cross-compile probes: supply the known-correct answer directly via CONFIGURE_VARS (libreplace_cv_mkdir_has_mode=yes), rather than patching samba's own probe source. - utils/owrt_smbpasswd.c (an OpenWrt-authored file, not upstream samba, created via patches/111-owrt_smbpasswd.patch): calls mdfour() with no declaration in scope anywhere it includes -- an implicit-declaration warning under GCC <= 13, a hard error under GCC 14. Added the missing `#include "../lib/crypto/md4.h"` (the same relative include path used elsewhere in this samba tree, e.g. rpc_server/netlogon/srv_netlog_nt.c) to the patch, bumping its new-file hunk header from +1,249 to +1,250 to match. Verified via a real full scoped compile: samba36-server_3.6.25-r14_x86_64.ipk now builds clean. --- package/samba36/Makefile | 1 + package/samba36/patches/111-owrt_smbpasswd.patch | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/package/samba36/Makefile b/package/samba36/Makefile index 1953d9dea..72ef81a9a 100644 --- a/package/samba36/Makefile +++ b/package/samba36/Makefile @@ -87,6 +87,7 @@ CONFIGURE_VARS += \ libreplace_cv_HAVE_C99_VSNPRINTF=yes \ libreplace_cv_HAVE_GETADDRINFO=yes \ libreplace_cv_HAVE_IFACE_IFCONF=yes \ + libreplace_cv_mkdir_has_mode=yes \ $(if $(CONFIG_IPV6),,libreplace_cv_HAVE_IPV6=no libreplace_cv_HAVE_IPV6_V6ONLY=no) \ LINUX_LFS_SUPPORT=yes \ samba_cv_CC_NEGATIVE_ENUM_VALUES=yes \ diff --git a/package/samba36/patches/111-owrt_smbpasswd.patch b/package/samba36/patches/111-owrt_smbpasswd.patch index 40b34e9a7..8a6e40f35 100644 --- a/package/samba36/patches/111-owrt_smbpasswd.patch +++ b/package/samba36/patches/111-owrt_smbpasswd.patch @@ -29,7 +29,7 @@ MULTICALL_O = $(sort $(SMBD_MULTI_O) $(NMBD_MULTI_O) $(SMBPASSWD_MULTI_O) $(MULTI_O)) --- /dev/null +++ b/source3/utils/owrt_smbpasswd.c -@@ -0,0 +1,249 @@ +@@ -0,0 +1,250 @@ +/* + * Copyright (C) 2012 Felix Fietkau + * Copyright (C) 2008 John Crispin @@ -49,6 +49,7 @@ + * Mass Ave, Cambridge, MA 02139, USA. */ + +#include "includes.h" ++#include "../lib/crypto/md4.h" +#include +#include + From 40c7052e077bd12a5d9620fa3cd518289e71a86c Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Thu, 9 Jul 2026 21:42:48 +1200 Subject: [PATCH 11/18] libnftbwctl, gargoyle, qos-gargoyle: fix GCC 14 pointer-type errors GCC 14 promotes incompatible-pointer-type from warning to hard error. Three real type mismatches surfaced across nft_bwctl.c, gargoyle_header_footer.c, and qosmon.c. --- package/gargoyle/src/gargoyle_header_footer.c | 10 +++++----- package/libnftbwctl/src/nft_bwctl.c | 2 +- package/qos-gargoyle/src/qosmon.c | 8 ++++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/package/gargoyle/src/gargoyle_header_footer.c b/package/gargoyle/src/gargoyle_header_footer.c index f84e4f97b..d6fc7b1ce 100644 --- a/package/gargoyle/src/gargoyle_header_footer.c +++ b/package/gargoyle/src/gargoyle_header_footer.c @@ -66,8 +66,8 @@ char* ip6_combine_prefix_hostid(char* ip6, char* hostid); json_object* getInterfaceDump(void); json_object* getWirelessStatusDump(void); void get_ifstatus_ip6addrs(json_object* iface, list* ifstatus_ip6, list* ifstatus_mask6); -void get_ifstatus_gateway(json_object* iface, char** ifstatus_gateway); -void get_ifstatus_ipaddrs(json_object* iface, char** ifstatus_ip, char* ifstatus_mask); +void get_ifstatus_gateway(json_object* iface, const char** ifstatus_gateway); +void get_ifstatus_ipaddrs(json_object* iface, const char** ifstatus_ip, char* ifstatus_mask); int main(int argc, char **argv) @@ -975,7 +975,7 @@ void get_ifstatus_ip6addrs(json_object* iface, list* ifstatus_ip6, list* ifstatu } } -void get_ifstatus_gateway(json_object* iface, char** ifstatus_gateway) +void get_ifstatus_gateway(json_object* iface, const char** ifstatus_gateway) { struct json_object* tmpobj = NULL; struct json_object* routesarr = NULL; @@ -1003,7 +1003,7 @@ void get_ifstatus_gateway(json_object* iface, char** ifstatus_gateway) } } -void get_ifstatus_ipaddrs(json_object* iface, char** ifstatus_ip, char* ifstatus_mask) +void get_ifstatus_ipaddrs(json_object* iface, const char** ifstatus_ip, char* ifstatus_mask) { struct json_object* tmpobj = NULL; struct json_object* tmpobj2 = NULL; @@ -1684,7 +1684,7 @@ char* get_interface_gateway(char* if_name, int family) uint8_t* ipptr; sscanf(split_line[2], "%X", &ip); ip = htonl(ip); - ipptr = &ip; + ipptr = (uint8_t*)&ip; gateway = (char*)malloc(20); sprintf(gateway, "%u.%u.%u.%u", *(ipptr+3), *(ipptr+2), *(ipptr+1), *ipptr); } diff --git a/package/libnftbwctl/src/nft_bwctl.c b/package/libnftbwctl/src/nft_bwctl.c index 73e6a8160..db1d5e257 100644 --- a/package/libnftbwctl/src/nft_bwctl.c +++ b/package/libnftbwctl/src/nft_bwctl.c @@ -320,7 +320,7 @@ static void parse_returned_ip_data( void *out_data, *(ip + 1) = *( (uint32_t*)(in_buffer + (*in_index) + 8) ); *(ip + 2) = *( (uint32_t*)(in_buffer + (*in_index) + 12) ); *(ip + 3) = *( (uint32_t*)(in_buffer + (*in_index) + 16) ); - ip_bw_kernel_data_item* ip_bw_data = (ip_bw_kernel_data*)(in_buffer + *in_index); + ip_bw_kernel_data_item* ip_bw_data = (ip_bw_kernel_data_item*)(in_buffer + *in_index); if(get_history == 0) { (((ip_bw*)out_data)[*out_index]).family = family; diff --git a/package/qos-gargoyle/src/qosmon.c b/package/qos-gargoyle/src/qosmon.c index 1207b48b8..a071ffde5 100644 --- a/package/qos-gargoyle/src/qosmon.c +++ b/package/qos-gargoyle/src/qosmon.c @@ -422,9 +422,13 @@ char pr_pack( void *buf, int cc, struct sockaddr_storage *from ) } -//These variables referenced but not used by the tc code we link to. +//This variable is referenced but not used by the tc code we link to. int filter_ifindex; -int use_iec = 0; +//use_iec is also referenced by the tc code, but iproute2's own utils.c +//(pulled in via libutil.a) already defines it -- GCC 14's default +//-fno-common turns the previously-harmless duplicate tentative +//definition into a hard "multiple definition" link error, so rely on +//utils.h's extern declaration instead of redefining it here. int print_class(struct nlmsghdr *n, void *arg) From 1f2fd8541860c38a92b05162baf9e455972c80ad Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Thu, 9 Jul 2026 20:22:02 +1200 Subject: [PATCH 12/18] patches: make the ip6_tables legacy-symbol fix generic, not x86-only kernel 6.12 gates ip6_tables.ko behind the hidden select-only IP6_NF_IPTABLES_LEGACY symbol. CONFIG_IP6_NF_IPTABLES=m alone (all that kmod-nf-ipt6 sets) no longer builds it, so kmod-nf-ipt6 fails to package -- on every target, as the mediatek build just demonstrated. The IPv4 twin only works by accident: kmod-ipt-core's CONFIG_IP_NF_FILTER=m selects the IPv4 legacy symbol, and that package is in Gargoyle's set; no IPv6 equivalent is. Move the fix from target/linux/x86/config-6.12 to target/linux/generic/config-6.12 so every target gets it, and answer the open question left in the B2 notes about why IPv4 resolved =m. --- .../030-generic_ip6_nf_filter.patch | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 patches-generic/030-generic_ip6_nf_filter.patch diff --git a/patches-generic/030-generic_ip6_nf_filter.patch b/patches-generic/030-generic_ip6_nf_filter.patch new file mode 100644 index 000000000..85735f713 --- /dev/null +++ b/patches-generic/030-generic_ip6_nf_filter.patch @@ -0,0 +1,25 @@ +kernel 6.12 split the legacy iptables/ip6tables code behind hidden +select-only symbols (IP_NF_IPTABLES_LEGACY / IP6_NF_IPTABLES_LEGACY). +CONFIG_IP6_NF_IPTABLES=m alone (all that kmod-nf-ipt6 sets via +include/netfilter.mk) no longer builds ip6_tables.ko, because nothing +selects the legacy symbol -- so kmod-nf-ipt6 fails to package on every +target. The IPv4 twin only works by accident: kmod-ipt-core's +CONFIG_IP_NF_FILTER=m selects IP_NF_IPTABLES_LEGACY, and that package +is in Gargoyle's set; there is no IPv6 equivalent selected. + +Enable IP6_NF_FILTER=m in the GENERIC kernel config (it selects +IP6_NF_IPTABLES_LEGACY), fixing every target at once. Replaces the +earlier x86-only version of this patch, which fixed the same issue via +target/linux/x86/config-6.12 before mediatek hit it too. + +--- a/target/linux/generic/config-6.12 ++++ b/target/linux/generic/config-6.12 +@@ -2850,7 +2850,7 @@ + CONFIG_IO_WQ=y + # CONFIG_IP17XX_PHY is not set + # CONFIG_IP5XXX_POWER is not set +-# CONFIG_IP6_NF_FILTER is not set ++CONFIG_IP6_NF_FILTER=m + # CONFIG_IP6_NF_IPTABLES is not set + # CONFIG_IP6_NF_MANGLE is not set + # CONFIG_IP6_NF_MATCH_AH is not set From 0bbaf23efb16a9aaab8e3d1e31fec57b4f2a9c73 Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Thu, 9 Jul 2026 17:50:39 +1200 Subject: [PATCH 13/18] netfilter-match-modules: register statement ops with nftables 1.1.6 ops table nftables 1.1.6 (the version this OpenWrt base ships) resolves statement ops through a central switch in stmt_ops()/__stmt_ops_by_type() and BUG()s on any type missing from it, instead of reading the ops pointer stored in the statement as older versions did. Gargoyle's integration fragments define bandwidth/timerange/webmon/weburl statement ops but never added cases to that switch, so any ruleset containing one of these statements -- which is every Gargoyle default firewall; a stock config carries ~80 bandwidth/timerange statements -- made 'nft list ruleset' abort: BUG: Unknown statement type 10 Assertion failed: 0 (src/statement.c: stmt_ops: 1366) Rules still loaded fine (fw4 input goes through the parser, not this path); only listing/inspection crashed. Add one case per module to the switch via new meta insertions anchored after the STMT_REJECT case. Verified live: rebuilt libnftables side-loaded onto a vnet VM lists the full ruleset cleanly, exit 0. --- netfilter-match-modules/nftables/bandwidth/nftables/meta | 1 + .../nftables/bandwidth/nftables/src_statement.c.3 | 1 + netfilter-match-modules/nftables/timerange/nftables/meta | 1 + .../nftables/timerange/nftables/src_statement.c.2 | 1 + netfilter-match-modules/nftables/webmon/nftables/meta | 1 + .../nftables/webmon/nftables/src_statement.c.2 | 1 + netfilter-match-modules/nftables/weburl/nftables/meta | 1 + .../nftables/weburl/nftables/src_statement.c.2 | 1 + 8 files changed, 8 insertions(+) create mode 100644 netfilter-match-modules/nftables/bandwidth/nftables/src_statement.c.3 create mode 100644 netfilter-match-modules/nftables/timerange/nftables/src_statement.c.2 create mode 100644 netfilter-match-modules/nftables/webmon/nftables/src_statement.c.2 create mode 100644 netfilter-match-modules/nftables/weburl/nftables/src_statement.c.2 diff --git a/netfilter-match-modules/nftables/bandwidth/nftables/meta b/netfilter-match-modules/nftables/bandwidth/nftables/meta index 653fbaa90..77d5439fa 100644 --- a/netfilter-match-modules/nftables/bandwidth/nftables/meta +++ b/netfilter-match-modules/nftables/bandwidth/nftables/meta @@ -21,3 +21,4 @@ src_statement.c.1||insert||after||0||include ||src/statement.c src_statement.c.2||insert||before||2||static void reject_stmt_print||src/statement.c include_linux_netfilter_nftables.h.1||insert||after||0||#define NFTA_REJECT_MAX||include/linux/netfilter/nf_tables.h include_parser.h.1||insert||after||0||PARSER_SC_STMT_REJECT||include/parser.h +src_statement.c.3||insert||after||0||case STMT_REJECT: return &reject_stmt_ops;||src/statement.c diff --git a/netfilter-match-modules/nftables/bandwidth/nftables/src_statement.c.3 b/netfilter-match-modules/nftables/bandwidth/nftables/src_statement.c.3 new file mode 100644 index 000000000..b7f4e9bdd --- /dev/null +++ b/netfilter-match-modules/nftables/bandwidth/nftables/src_statement.c.3 @@ -0,0 +1 @@ + case STMT_BANDWIDTH: return &bandwidth_stmt_ops; diff --git a/netfilter-match-modules/nftables/timerange/nftables/meta b/netfilter-match-modules/nftables/timerange/nftables/meta index b6a2e0327..72a14fbc4 100644 --- a/netfilter-match-modules/nftables/timerange/nftables/meta +++ b/netfilter-match-modules/nftables/timerange/nftables/meta @@ -20,3 +20,4 @@ src_scanner.l.2||insert||before||1||scanner_push_start_cond\(yyscanner, SCANSTAT src_statement.c.1||insert||before||2||static void reject_stmt_print||src/statement.c include_linux_netfilter_nftables.h.1||insert||after||0||#define NFTA_REJECT_MAX||include/linux/netfilter/nf_tables.h include_parser.h.1||insert||after||0||PARSER_SC_STMT_REJECT||include/parser.h +src_statement.c.2||insert||after||0||case STMT_REJECT: return &reject_stmt_ops;||src/statement.c diff --git a/netfilter-match-modules/nftables/timerange/nftables/src_statement.c.2 b/netfilter-match-modules/nftables/timerange/nftables/src_statement.c.2 new file mode 100644 index 000000000..87e6fafd9 --- /dev/null +++ b/netfilter-match-modules/nftables/timerange/nftables/src_statement.c.2 @@ -0,0 +1 @@ + case STMT_TIMERANGE: return &timerange_stmt_ops; diff --git a/netfilter-match-modules/nftables/webmon/nftables/meta b/netfilter-match-modules/nftables/webmon/nftables/meta index b6a2e0327..72a14fbc4 100644 --- a/netfilter-match-modules/nftables/webmon/nftables/meta +++ b/netfilter-match-modules/nftables/webmon/nftables/meta @@ -20,3 +20,4 @@ src_scanner.l.2||insert||before||1||scanner_push_start_cond\(yyscanner, SCANSTAT src_statement.c.1||insert||before||2||static void reject_stmt_print||src/statement.c include_linux_netfilter_nftables.h.1||insert||after||0||#define NFTA_REJECT_MAX||include/linux/netfilter/nf_tables.h include_parser.h.1||insert||after||0||PARSER_SC_STMT_REJECT||include/parser.h +src_statement.c.2||insert||after||0||case STMT_REJECT: return &reject_stmt_ops;||src/statement.c diff --git a/netfilter-match-modules/nftables/webmon/nftables/src_statement.c.2 b/netfilter-match-modules/nftables/webmon/nftables/src_statement.c.2 new file mode 100644 index 000000000..18d207f03 --- /dev/null +++ b/netfilter-match-modules/nftables/webmon/nftables/src_statement.c.2 @@ -0,0 +1 @@ + case STMT_WEBMON: return &webmon_stmt_ops; diff --git a/netfilter-match-modules/nftables/weburl/nftables/meta b/netfilter-match-modules/nftables/weburl/nftables/meta index b6a2e0327..72a14fbc4 100644 --- a/netfilter-match-modules/nftables/weburl/nftables/meta +++ b/netfilter-match-modules/nftables/weburl/nftables/meta @@ -20,3 +20,4 @@ src_scanner.l.2||insert||before||1||scanner_push_start_cond\(yyscanner, SCANSTAT src_statement.c.1||insert||before||2||static void reject_stmt_print||src/statement.c include_linux_netfilter_nftables.h.1||insert||after||0||#define NFTA_REJECT_MAX||include/linux/netfilter/nf_tables.h include_parser.h.1||insert||after||0||PARSER_SC_STMT_REJECT||include/parser.h +src_statement.c.2||insert||after||0||case STMT_REJECT: return &reject_stmt_ops;||src/statement.c diff --git a/netfilter-match-modules/nftables/weburl/nftables/src_statement.c.2 b/netfilter-match-modules/nftables/weburl/nftables/src_statement.c.2 new file mode 100644 index 000000000..4220e2425 --- /dev/null +++ b/netfilter-match-modules/nftables/weburl/nftables/src_statement.c.2 @@ -0,0 +1 @@ + case STMT_WEBURL: return &weburl_stmt_ops; From 327a8eb1fd21db0561c037e7a1fbc277c8009d0d Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Thu, 9 Jul 2026 14:09:32 +1200 Subject: [PATCH 14/18] nft_bandwidth: fix kernel 6.12 registration failure corrupting rootfs nft_bandwidth declared 17 netlink attributes (NFTA_BANDWIDTH_MAX), one over the 16-attribute limit (NFT_EXPR_MAXATTR) that kernel 6.12 added to nft_register_expr(): WARN_ON_ONCE(type->maxattr > NFT_EXPR_MAXATTR). That check does not exist on kernel 6.6, which is why this only shows up on the 25.12 kernel bump. Confirmed by diffing net/netfilter/ nf_tables_api.c between the v6.6 and v6.12 kernel tags. The registration failure alone would just mean the module fails to load, but init() calls nf_register_sockopt() *before* attempting nft_register_expr(), and never rolled that back on failure. When a module's init() returns nonzero the kernel does not call its exit/ fini function and unloads the module's code -- leaving the kernel's global sockopt table (BANDWIDTH_SET=2048, BANDWIDTH_GET=2049) pointing at freed memory. Any later setsockopt/getsockopt on those commands (the exact interface Gargoyle's userspace bandwidth/quota tooling uses) jumps into that freed memory, and the resulting corruption lands wherever it lands -- in testing, consistently on ext4 metadata, producing "doubly allocated" / "deleted inode referenced" errors and an unbootable image. Root-caused and confirmed via QEMU monitor screendumps, module-by-module isolation, and a live serial-console insmod reproduction that surfaced the WARN_ON_ONCE with a full stack trace. Two changes: - init() now calls nf_unregister_sockopt() if nft_register_expr() (or the earlier id_map allocation) fails, before returning the error. This alone prevents the corruption regardless of attribute count, turning any future registration failure into a clean load failure instead of a dangling kernel function pointer. - Removed NFTA_BANDWIDTH_MINUTESWEST, bringing the attribute count to exactly 16. It was declared in the kernel-side parse policy but never actually read by init() or written by dump() -- dead on the kernel side. It did have real plumbing in the userspace libnftnl wire-format code (get/set/build/parse), which is now cleaned up to match; nothing in Gargoyle's own rule-generation scripts ever populated it. Kept the two enums (kernel header and the userspace wire-format copy in libnftnl/include_linux_netfilter_bandwidth.h) numerically synchronized, since a mismatch there would desync the netlink wire protocol between kernel and userspace. Verified: with only nft_bandwidth enabled, the vnet-wifi x86 image now boots clean on kernel 6.12.94 -- lsmod shows nft_bandwidth loaded and registered under nf_tables, no WARNING, no ext4 errors, apk writes succeed post-boot. Isolated confirmation that nft_webmon and nft_weburl were never affected by this bug (module-by-module boot testing, both clean independently). --- .../nftables/bandwidth/header/nft_bandwidth.h | 11 +++++++- .../libnftnl/include_libnftnl_expr.h.1 | 2 +- .../include_linux_netfilter_bandwidth.h | 2 +- .../bandwidth/libnftnl/src_expr_bandwidth.c | 25 +------------------ .../nftables/bandwidth/module/nft_bandwidth.c | 16 ++++++++++-- 5 files changed, 27 insertions(+), 29 deletions(-) diff --git a/netfilter-match-modules/nftables/bandwidth/header/nft_bandwidth.h b/netfilter-match-modules/nftables/bandwidth/header/nft_bandwidth.h index 6bf7e5831..bcd0bebdc 100644 --- a/netfilter-match-modules/nftables/bandwidth/header/nft_bandwidth.h +++ b/netfilter-match-modules/nftables/bandwidth/header/nft_bandwidth.h @@ -45,7 +45,16 @@ enum nft_bandwidth_attributes { NFTA_BANDWIDTH_NEXTRESET, NFTA_BANDWIDTH_PREVRESET, NFTA_BANDWIDTH_LASTBACKUPTIME, - NFTA_BANDWIDTH_MINUTESWEST, + /* NFTA_BANDWIDTH_MINUTESWEST removed: kernel 6.12 added + * WARN_ON_ONCE(type->maxattr > NFT_EXPR_MAXATTR) [16] to + * nft_register_expr(), which this 18-value enum (17 real + * attributes) exceeded. This attribute was never actually read + * by the kernel side (declared in the parse policy only) and had + * no caller in Gargoyle's own rule-generation code, so it was the + * one to drop. Kept in sync with the userspace wire-format copy + * in netfilter-match-modules/nftables/bandwidth/libnftnl/ + * include_linux_netfilter_bandwidth.h -- both enums must stay + * numerically identical. */ NFTA_BANDWIDTH_PAD, __NFTA_BANDWIDTH_MAX, }; diff --git a/netfilter-match-modules/nftables/bandwidth/libnftnl/include_libnftnl_expr.h.1 b/netfilter-match-modules/nftables/bandwidth/libnftnl/include_libnftnl_expr.h.1 index b4e544075..69956a4b7 100644 --- a/netfilter-match-modules/nftables/bandwidth/libnftnl/include_libnftnl_expr.h.1 +++ b/netfilter-match-modules/nftables/bandwidth/libnftnl/include_libnftnl_expr.h.1 @@ -15,6 +15,6 @@ enum { NFTNL_EXPR_BANDWIDTH_NEXTRESET, NFTNL_EXPR_BANDWIDTH_PREVRESET, NFTNL_EXPR_BANDWIDTH_LASTBACKUPTIME, - NFTNL_EXPR_BANDWIDTH_MINUTESWEST, + /* NFTNL_EXPR_BANDWIDTH_MINUTESWEST removed -- see nft_bandwidth.h */ __NFTNL_EXPR_BANDWIDTH_MAX, }; \ No newline at end of file diff --git a/netfilter-match-modules/nftables/bandwidth/libnftnl/include_linux_netfilter_bandwidth.h b/netfilter-match-modules/nftables/bandwidth/libnftnl/include_linux_netfilter_bandwidth.h index 57c55da26..797a4537b 100644 --- a/netfilter-match-modules/nftables/bandwidth/libnftnl/include_linux_netfilter_bandwidth.h +++ b/netfilter-match-modules/nftables/bandwidth/libnftnl/include_linux_netfilter_bandwidth.h @@ -18,7 +18,7 @@ enum nft_bandwidth_attributes { NFTA_BANDWIDTH_NEXTRESET, NFTA_BANDWIDTH_PREVRESET, NFTA_BANDWIDTH_LASTBACKUPTIME, - NFTA_BANDWIDTH_MINUTESWEST, + /* NFTA_BANDWIDTH_MINUTESWEST removed -- see nft_bandwidth.h */ NFTA_BANDWIDTH_PAD, __NFTA_BANDWIDTH_MAX, }; diff --git a/netfilter-match-modules/nftables/bandwidth/libnftnl/src_expr_bandwidth.c b/netfilter-match-modules/nftables/bandwidth/libnftnl/src_expr_bandwidth.c index bc20dbbc4..2e8db2f24 100644 --- a/netfilter-match-modules/nftables/bandwidth/libnftnl/src_expr_bandwidth.c +++ b/netfilter-match-modules/nftables/bandwidth/libnftnl/src_expr_bandwidth.c @@ -31,7 +31,6 @@ struct nftnl_expr_bandwidth { uint64_t prev_reset; uint32_t num_intervals_to_save; uint64_t last_backup_time; - uint32_t minutes_west; }; int get_minutes_west(void); @@ -93,9 +92,6 @@ static int nftnl_expr_bandwidth_set(struct nftnl_expr *e, uint16_t type, case NFTNL_EXPR_BANDWIDTH_LASTBACKUPTIME: memcpy(&bandwidth->last_backup_time, data, data_len); break; - case NFTNL_EXPR_BANDWIDTH_MINUTESWEST: - memcpy(&bandwidth->minutes_west, data, data_len); - break; } return 0; } @@ -152,9 +148,6 @@ nftnl_expr_bandwidth_get(const struct nftnl_expr *e, uint16_t type, case NFTNL_EXPR_BANDWIDTH_LASTBACKUPTIME: *data_len = sizeof(uint64_t); return &bandwidth->last_backup_time; - case NFTNL_EXPR_BANDWIDTH_MINUTESWEST: - *data_len = sizeof(uint32_t); - return &bandwidth->minutes_west; } return NULL; } @@ -176,7 +169,6 @@ static int nftnl_expr_bandwidth_cb(const struct nlattr *attr, void *data) abi_breakage(); break; case NFTA_BANDWIDTH_NUMINTVLSTOSAVE: - case NFTA_BANDWIDTH_MINUTESWEST: if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) abi_breakage(); break; @@ -206,7 +198,6 @@ static void nftnl_expr_bandwidth_build(struct nlmsghdr *nlh, const struct nftnl_expr *e) { struct nftnl_expr_bandwidth *bandwidth = nftnl_expr_data(e); - uint32_t minuteswest = 0; if (e->flags & (1 << NFTNL_EXPR_BANDWIDTH_ID)) mnl_attr_put_strz(nlh, NFTA_BANDWIDTH_ID, bandwidth->id); @@ -240,10 +231,6 @@ nftnl_expr_bandwidth_build(struct nlmsghdr *nlh, const struct nftnl_expr *e) mnl_attr_put_u64(nlh, NFTA_BANDWIDTH_LASTBACKUPTIME, htobe64(bandwidth->last_backup_time)); set_kernel_timezone(); - minuteswest = get_minutes_west(); - - if (e->flags & (1 << NFTNL_EXPR_BANDWIDTH_MINUTESWEST)) - mnl_attr_put_u32(nlh, NFTA_BANDWIDTH_MINUTESWEST, htonl(minuteswest)); } static int @@ -330,10 +317,6 @@ nftnl_expr_bandwidth_parse(struct nftnl_expr *e, struct nlattr *attr) bandwidth->last_backup_time = be64toh(mnl_attr_get_u64(tb[NFTA_BANDWIDTH_LASTBACKUPTIME])); e->flags |= (1 << NFTNL_EXPR_BANDWIDTH_LASTBACKUPTIME); } - if (tb[NFTA_BANDWIDTH_MINUTESWEST]) { - bandwidth->minutes_west = ntohl(mnl_attr_get_u32(tb[NFTA_BANDWIDTH_MINUTESWEST])); - e->flags |= (1 << NFTNL_EXPR_BANDWIDTH_MINUTESWEST); - } return 0; } @@ -345,13 +328,8 @@ nftnl_expr_bandwidth_snprintf(char *buf, size_t len, struct nftnl_expr_bandwidth *bandwidth = nftnl_expr_data(e); int ret, offset = 0, remain = len; time_t now; - int minuteswest = 0; - time(&now); - if(e->flags & (1 << NFTNL_EXPR_BANDWIDTH_MINUTESWEST)) { - minuteswest = bandwidth->minutes_west; - } - now = now - (minuteswest*60); + time(&now); if(e->flags & (1 << NFTNL_EXPR_BANDWIDTH_CMP) && e->flags & (1 << NFTNL_EXPR_BANDWIDTH_CHECKTYPE)) { if(bandwidth->cmp == NFT_BANDWIDTH_CMP_CHECK && bandwidth->check_type != 0) @@ -468,7 +446,6 @@ static struct attr_policy bandwidth_attr_policy[__NFTNL_EXPR_BANDWIDTH_MAX] = { [NFTNL_EXPR_BANDWIDTH_NEXTRESET] = { .maxlen = sizeof(uint64_t) }, [NFTNL_EXPR_BANDWIDTH_PREVRESET] = { .maxlen = sizeof(uint64_t) }, [NFTNL_EXPR_BANDWIDTH_LASTBACKUPTIME] = { .maxlen = sizeof(uint64_t) }, - [NFTNL_EXPR_BANDWIDTH_MINUTESWEST] = { .maxlen = sizeof(uint32_t) }, }; struct expr_ops expr_ops_bandwidth = { diff --git a/netfilter-match-modules/nftables/bandwidth/module/nft_bandwidth.c b/netfilter-match-modules/nftables/bandwidth/module/nft_bandwidth.c index 13e5b54b0..611acb24e 100644 --- a/netfilter-match-modules/nftables/bandwidth/module/nft_bandwidth.c +++ b/netfilter-match-modules/nftables/bandwidth/module/nft_bandwidth.c @@ -204,7 +204,6 @@ static const struct nla_policy nft_bandwidth_policy[NFTA_BANDWIDTH_MAX + 1] = { [NFTA_BANDWIDTH_RSTTIME] = { .type = NLA_U64 }, [NFTA_BANDWIDTH_NUMINTVLSTOSAVE] = { .type = NLA_U32 }, [NFTA_BANDWIDTH_LASTBACKUPTIME] = { .type = NLA_U64 }, - [NFTA_BANDWIDTH_MINUTESWEST] = { .type = NLA_U32 }, }; static void adjust_ip_for_backwards_time_shift(char* key, void* value) @@ -3464,10 +3463,23 @@ static int __init init(void) if(id_map == NULL) /* deal with kmalloc failure */ { printk("id map is null, returning -1\n"); + nf_unregister_sockopt(&nft_bandwidth_sockopts); return -1; } - return nft_register_expr(&nft_bandwidth_type); + { + int register_err = nft_register_expr(&nft_bandwidth_type); + if(register_err != 0) + { + /* registration failed (e.g. too many netlink attributes for + * this kernel's NFT_EXPR_MAXATTR) -- undo the sockopt + * registration above, otherwise the kernel's sockopt table + * is left pointing at code that's about to be unloaded */ + printk("nft_bandwidth: nft_register_expr failed (%d), unregistering sockopts\n", register_err); + nf_unregister_sockopt(&nft_bandwidth_sockopts); + } + return register_err; + } } static void __exit fini(void) From 8c485641bffe3f76e77fa57f51c391c7f21e0ec5 Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Wed, 8 Jul 2026 19:43:46 +1200 Subject: [PATCH 15/18] wifi-scripts: fix broken APs when country is left at the '00' default Every AP left at its out-of-the-box default (country never explicitly configured) silently never reaches a real operating channel under 25.12 -- confirmed live: iwinfo shows Channel: 0/unknown, iw dev prints no channel/ssid line at all, and no client can ever scan or associate, even though hostapd's own process is running and the interface exists. Root cause, traced end to end: '00' is cfg80211's own generic/"world safe mode" regulatory-domain placeholder (confirmed via `iw reg get`: "country 00: DFS-UNSET"), not a real ISO country code -- but wireless.wifi-device.json's schema aliases UCI's 'country' field straight onto hostapd config's 'country_code' unconditionally (default: country_code), and separately defaults 'ieee80211d' (the 802.11d Country IE toggle) to true regardless of whether a real country is configured, even though the schema's own description says ieee80211d "Requires country". hostapd itself has been tightened (also part of this bump) to hard-reject country_code=00 combined with ieee80211d=1 as invalid -- confirmed directly: running the exact generated config standalone gets "Invalid country_code '00' / Cannot enable IEEE 802.11d without setting the country_code" and refuses to start. netifd's newer global multi-BSS hostapd daemon doesn't propagate that failure as a hard error though -- it silently leaves the BSS half-configured (interface/SSID/encryption present, channel never set), which is why every symptom looked like "the AP sort of exists but never really works" rather than an obvious startup crash. This is not hwsim/vnet-specific: Gargoyle's own wireless UI (basic.js) never sets a country code, and UCI's own default leaves it at '00' on first boot, so any real router where the admin enables WiFi without separately configuring an advanced country setting would hit this identically. Fixed in wifi-scripts' own hostapd.uc: device_country_code() already had an early-return guard for "no country_code set", gated only on existence -- extended it to also treat the '00' placeholder as "unset", matching the schema's own documented intent. Verified via a real end-to-end test: after the fix, a freshly-enabled AP with country left at '00' reaches a genuine operating channel (iwinfo: Channel: 6, Tx-Power: 20 dBm) and a real client completes full WPA2 association (wpa_supplicant: CTRL-EVENT-CONNECTED). --- ...ifi_scripts_fix_country00_ieee80211d.patch | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 patches-generic/031-wifi_scripts_fix_country00_ieee80211d.patch diff --git a/patches-generic/031-wifi_scripts_fix_country00_ieee80211d.patch b/patches-generic/031-wifi_scripts_fix_country00_ieee80211d.patch new file mode 100644 index 000000000..133dfa8e6 --- /dev/null +++ b/patches-generic/031-wifi_scripts_fix_country00_ieee80211d.patch @@ -0,0 +1,23 @@ +--- a/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/hostapd.uc ++++ b/package/network/config/wifi-scripts/files-ucode/usr/share/ucode/wifi/hostapd.uc +@@ -72,7 +72,19 @@ + config.country_code = radio.config.country; + } + +- if (!exists(config, 'country_code')) ++ /* '00' is the kernel's own generic/"world safe mode" regulatory domain ++ * (cfg80211's placeholder for "no specific country configured"), not ++ * a real ISO country code -- but UCI's own 'country' schema field is ++ * an alias straight onto 'country_code' (see ++ * wireless.wifi-device.json), so config.country_code is already '00' ++ * by the time this function runs on any radio left at its ++ * out-of-the-box default, regardless of the loop above. Treat that ++ * placeholder the same as unset so we don't advertise a bogus 802.11d ++ * Country IE -- hostapd itself now hard-rejects country_code=00 ++ * combined with ieee80211d=1 (ieee80211d defaults to true in the ++ * schema), which silently broke every AP left at its default ++ * country. */ ++ if (!exists(config, 'country_code') || config.country_code == '00') + return; + + if (config.hw_mode != 'a') From b4ceb2f57709d1b874b7363fa593e9e3204ba678 Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Wed, 8 Jul 2026 22:31:40 +1200 Subject: [PATCH 16/18] gargoyle_stamgr: fix roaming scan/disconnect-detection under OpenWrt 25.12 The rewritten ucode iwinfo CLI broke two things check_sta()/ get_scan_results() depended on: - iwinfo scan fails outright ("Netlink error while awaiting scan results: No event received"), even on a real, already-up interface. Separately, a disabled=1 wifi-iface now produces zero kernel interface at all under this netifd (unlike 24.10), so there's nothing to scan against in the idle case either way, and a live STA interface is already owned by netifd's global wpa_supplicant, which refuses a second externally-triggered scan on the same vif. get_scan_results() now scans through a short-lived, daemon-independent interface created directly on the phy with plain `iw`, parsing `iw scan`'s block-structured text output instead of iwinfo's. - iwinfo info keeps reporting the last-associated ESSID after a real disconnect, confirmed live against `iw link` and `wpa_cli status` (both correctly show the link is gone) while iwinfo stayed wrong for 150+ seconds. check_sta()'s old "unknown" substring check never caught this, since the degraded fields it inspected print "0", not the literal word "unknown". check_sta() now derives connected state and signal quality from `iw dev link` directly. Verified live end to end: real association, real failover after killing the active AP, and real blacklisting on repeated auth failure all now complete within their expected budgets (vnet phase 19, 5/5). --- .../files/usr/lib/gargoyle/gargoyle_stamgr.sh | 100 ++++++++++++++++-- 1 file changed, 93 insertions(+), 7 deletions(-) diff --git a/package/plugin-gargoyle-stamgr/files/usr/lib/gargoyle/gargoyle_stamgr.sh b/package/plugin-gargoyle-stamgr/files/usr/lib/gargoyle/gargoyle_stamgr.sh index de70eee06..79dece701 100755 --- a/package/plugin-gargoyle-stamgr/files/usr/lib/gargoyle/gargoyle_stamgr.sh +++ b/package/plugin-gargoyle-stamgr/files/usr/lib/gargoyle/gargoyle_stamgr.sh @@ -127,12 +127,35 @@ check_sta() else sta_wlan="${phyname}-sta0" fi - wireless_info="$(iwinfo $sta_wlan i 2>/dev/null)" - - - sta_connected="$(echo "$wireless_info" | awk '/ESSID:/ {print $3}; /Channel:/ {print $4};' | grep -v "unknown")" - [ -z "$sta_connected" ] && sta_connected=false || sta_connected=true - sta_quality="$(echo "$wireless_info" | awk -F "[ ]" '/Link Quality:/{split($NF,var0,"/");printf "%i\n",(var0[1]*100/var0[2])}')" + # `iwinfo info`'s ESSID field is stale under this OpenWrt base: + # confirmed live that after a real, verified disconnect (`iw link` + # correctly reports "Not connected.", and wpa_supplicant's own + # `wpa_cli status` already shows wpa_state=SCANNING), iwinfo info kept + # printing the last-associated ESSID unchanged for 150+ seconds, with + # only Channel/Signal/Bit Rate degrading to unknown/0 -- and the old + # "unknown" substring check below only ever inspected the ESSID and + # Channel fields specifically, neither of which actually contains the + # literal word "unknown" in this degraded-but-still-"connected" + # state (Channel's degraded value prints as "0", not "unknown"), so + # it never caught a real disconnect. Query wpa_supplicant's own + # kernel-backed link state directly instead -- confirmed reliable in + # both directions live (correctly flips to "Not connected." within + # one poll of a genuine AP loss, and reports full signal detail + # immediately on a fresh real association). + link_info="$(iw dev "$sta_wlan" link 2>/dev/null)" + if echo "$link_info" | grep -q "^Connected to" ; then + sta_connected=true + sta_dbm="$(echo "$link_info" | awk '/^[[:space:]]*signal:/ {print $2}')" + sta_quality="$(awk -v dbm="${sta_dbm:--110}" 'BEGIN { + q = dbm + 110 + if (q > 70) q = 70 + if (q < 0) q = 0 + printf "%i", q * 100 / 70 + }')" + else + sta_connected=false + sta_quality=0 + fi sta_ssid="$(uci_get "wireless" "$stacfgsec" "ssid")" sta_bssid="$(uci_get "wireless" "$stacfgsec" "bssid")" sta_encryption="$(uci_get "wireless" "$stacfgsec" "encryption")" @@ -167,9 +190,72 @@ get_current_active_sta_section() get_scan_results() { local radios="radio0 radio1" + local tmpif="stamgr-tmp0" scan_results="" for radio in $radios ; do - scan_list="$(iwinfo $radio s 2>/dev/null | awk -v var4="$radio" 'BEGIN{FS="[[:space:]]"}/Address:/{var1=$NF}/ESSID:/{var2="";for(i=12;i<=NF;i++)if(var2==""){var2=$i}else{var2=var2" "$i};gsub(/,/,".",var2)}/Quality:/{split($NF,var0,"/")}/Encryption:/{if($NF=="none"){var3="+"}else{var3="-"};printf "%i,%s,%s,%s,%s\n",(var0[1]*100/var0[2]),var1,var2,var3,var4}' | sort -rn)" + # Use the resolved phy directly, same reasoning and same pattern as + # check_sta(): UCI's own radio section name ("radio0") doesn't + # reliably match the kernel's actual phy number. + phyname="$(iwinfo nl80211 phyname $radio 2>&1)" + [ "$phyname" = "Phy not found" ] && continue + + # `iwinfo scan` is broken outright under this OpenWrt base + # (confirmed: fails with "Netlink error while awaiting scan + # results: No event received" even on a real, already-up + # interface). Separately, when the STA config's own real interface + # exists, it's already owned by netifd's global wpa_supplicant + # daemon, which refuses a second, externally-triggered scan on the + # same vif ("Resource busy"). And when the STA config is + # `disabled`, no kernel interface exists for it at all any more + # (confirmed live: disabled=1 wifi-iface sections produce zero + # interface under this netifd, unlike 24.10) -- there's nothing + # for `iwinfo`/`iw` to scan against in the idle case either way. + # + # Work around all three by scanning through a short-lived, + # daemon-independent interface created directly on the phy with + # plain `iw`, instead of going through iwinfo or the STA config's + # own interface. Verified this works identically whether the phy + # is fully idle or already hosts a live, connected STA vif -- a + # second vif on the same phy scans without disturbing the first's + # association (mac80211/hwsim's own off-channel scan support, the + # same mechanism a real STA's background roam-scan already relies + # on; a phy already running an AP vif pays the same brief + # beacon-interruption cost during the scan that any single-radio + # AP+STA repeater setup already accepts today, not a new cost). + # Interface name must stay under Linux's 15-char IFNAMSIZ limit. + iw dev "$tmpif" del >/dev/null 2>&1 + iw phy "$phyname" interface add "$tmpif" type station >/dev/null 2>&1 || continue + ip link set "$tmpif" up >/dev/null 2>&1 + sleep 1 + scan_list="$(iw dev "$tmpif" scan 2>/dev/null | awk -v radio="$radio" ' + function flush() { + if (bssid != "") { + enc = has_rsn ? "-" : "+" + printf "%i,%s,\"%s\",%s,%s\n", quality, bssid, ssid, enc, radio + } + } + BEGIN { bssid=""; ssid=""; quality=0; has_rsn=0 } + /^BSS / { + flush() + bssid=$2; sub(/\(.*/, "", bssid) + ssid=""; quality=0; has_rsn=0 + } + /^\tsignal:/ { + q = $2 + 110 + if (q > 70) q = 70 + if (q < 0) q = 0 + quality = int(q * 100 / 70) + } + /^\tSSID:/ { + ssid=$0 + sub(/^\tSSID: /, "", ssid) + gsub(/,/, ".", ssid) + } + /^\tRSN:/ || /^\tWPA:/ { has_rsn=1 } + END { flush() } + ' | sort -rn)" + iw dev "$tmpif" del >/dev/null 2>&1 + if [ -z "${scan_results}" ] ; then scan_results="$scan_list" else From 96b079a8d25a8d5e9f147f4c8fe302f3955e0274 Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Fri, 10 Jul 2026 21:27:02 +1200 Subject: [PATCH 17/18] wifi-scripts: correct the country-'00' patch comment's hostapd claims The comment in 031 claimed hostapd "now" hard-rejects country_code=00 combined with ieee80211d=1. Both halves were wrong, as flagged in review: hostapd has rejected any country_code with characters outside A-Z at config-parse time since 2.10 (2022) -- see the Feb 2022 "Invalid country_code '00'" hostap list threads -- and that rejection is unconditional. The "Cannot enable IEEE 802.11d without setting the country_code" error observed in testing is a follow-on (the rejected line leaves the country empty while ieee80211d=1 is still present), not the trigger. What actually changed in 25.12 is the generation side: a radio left at its out-of-the-box default now ends up with country '00' in UCI, and the ucode wifi-scripts schema (wireless.wifi-device.json) aliases 'country' straight onto 'country_code', handing hostapd a config it has always refused. The old shell path had the same -n guard but never saw a '00' in UCI, which is why 24.10 never hit this. Comment-only change; the code hunk is identical. Re-verified the patch still applies cleanly against pristine hostapd.uc (reverse/forward round-trip). --- ...ifi_scripts_fix_country00_ieee80211d.patch | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/patches-generic/031-wifi_scripts_fix_country00_ieee80211d.patch b/patches-generic/031-wifi_scripts_fix_country00_ieee80211d.patch index 133dfa8e6..3282935eb 100644 --- a/patches-generic/031-wifi_scripts_fix_country00_ieee80211d.patch +++ b/patches-generic/031-wifi_scripts_fix_country00_ieee80211d.patch @@ -5,18 +5,18 @@ } - if (!exists(config, 'country_code')) -+ /* '00' is the kernel's own generic/"world safe mode" regulatory domain -+ * (cfg80211's placeholder for "no specific country configured"), not -+ * a real ISO country code -- but UCI's own 'country' schema field is -+ * an alias straight onto 'country_code' (see -+ * wireless.wifi-device.json), so config.country_code is already '00' -+ * by the time this function runs on any radio left at its -+ * out-of-the-box default, regardless of the loop above. Treat that -+ * placeholder the same as unset so we don't advertise a bogus 802.11d -+ * Country IE -- hostapd itself now hard-rejects country_code=00 -+ * combined with ieee80211d=1 (ieee80211d defaults to true in the -+ * schema), which silently broke every AP left at its default -+ * country. */ ++ /* '00' is cfg80211's generic/"world" regulatory-domain placeholder, ++ * not a real ISO 3166-1 alpha2 code. hostapd has rejected any ++ * country_code with characters outside A-Z at config-parse time ++ * since 2.10 (2022), independent of ieee80211d -- one bad line ++ * fails the whole config load. What is new in this release is the ++ * generation side: radios left at their out-of-the-box default end ++ * up with country '00' in UCI, and the schema ++ * (wireless.wifi-device.json) aliases 'country' straight onto ++ * 'country_code', so this function hands hostapd a config it ++ * refuses. netifd's global hostapd daemon surfaces that as a ++ * silently half-configured AP (no channel, no beacons) instead of ++ * a startup error. Treat the placeholder the same as unset. */ + if (!exists(config, 'country_code') || config.country_code == '00') return; From cecd3a4cfe126518151a526420f206c2ec6e2823 Mon Sep 17 00:00:00 2001 From: Shane Ringrose Date: Fri, 10 Jul 2026 22:50:51 +1200 Subject: [PATCH 18/18] netfilter-match-modules: adopt Michael Gray's V2 compile-fix patch set Reconciles Michael's V2 netfilter patches (derived against a pre-25.12 tree) with this branch, which had independently landed about half of them (statement-ops registration in 0bbaf23ef; the sockopt cleanup and .owner in 327a8eb1f). Three parts: 1. Switch the kernel-6.12 nft_bandwidth registration fix from attribute-removal to a maxattr bump, partially reverting 327a8eb1f. That commit dropped NFTA_BANDWIDTH_MINUTESWEST to get the attribute count under kernel 6.12's new WARN_ON_ONCE(type->maxattr > NFT_EXPR_MAXATTR) [16] in nft_register_expr(). Michael's approach keeps the attribute (restored here across the kernel header, both libnftnl wire-format enums, and the userspace get/set/build/parse plumbing) and instead raises NFT_EXPR_MAXATTR to 17. NFT_EXPR_MAXATTR is a kernel-internal sizing constant (bounds a fixed-size on-stack netlink attribute array), not uAPI, so the bump carries no wire-format risk. The mechanism is general: a module ships an optional "maxattr" file naming the ceiling it needs, and integrate_netfilter_modules.sh patches nf_tables.h to at least that value (nf_tables.h is added to the generated-patch file walk so the bump actually lands in 650-custom_netfilter_match_modules.patch). 327a8eb1f's sockopt-cleanup-on-failed-init, which prevents the dangling-sockopt rootfs corruption regardless of attribute count, is kept -- both approaches want it. 2. Build-warning cleanups for the newer toolchain: libxt_bandwidth.c drops its local ipany typedef for the header's own union xt_bandwidth_ipany and casts %lld printf args to (long long); libxt_webmon.c gains unistd.h; the iptables weburl regexp.c renames its END opcode macro to P_END (collision under newer kernel headers) and regexp.h declares my_strcspn; xt_webmon.c, xt_weburl.c and the three nft_* modules gain forward declarations for their non-static functions. nft_webmon's init() now removes its /proc entries if nft_register_expr() fails, mirroring the bandwidth sockopt cleanup: on a nonzero init() return the kernel unloads the module without calling fini(), and the stale proc file ops would point into freed memory. 3. Rename the nftables modules' bundled dependency dirs to nft__deps (bandwidth/webmon/weburl) so they can't collide with their iptables counterparts' identically-named dirs, updating the module includes to match. Verified: full x86.vnet-wifi firmware build from this tree, then the complete vnet simulator suite -- all three sites boot clean on kernel 6.12 with nft_bandwidth registered (lsmod-visible, no WARN_ON, no ext4 corruption -- the exact failure mode 327a8eb1f diagnosed), and the bandwidth/quota, webmon and weburl paths exercised by the suite pass. NFTA_BANDWIDTH_MAX lands at exactly 17 (= the PAD index = the declared .maxattr), matching the shipped maxattr ceiling. --- .../integrate_netfilter_modules.sh | 35 ++++++++++++++++--- .../bandwidth/extension/libxt_bandwidth.c | 28 ++++++--------- .../module/bandwidth_deps/tree_map.h | 2 -- .../iptables/webmon/extension/libxt_webmon.c | 1 + .../iptables/webmon/module/xt_webmon.c | 8 ++++- .../weburl/module/weburl_deps/regexp.c | 16 ++++----- .../weburl/module/weburl_deps/regexp.h | 1 + .../iptables/weburl/module/xt_weburl.c | 6 ++++ .../nftables/bandwidth/header/nft_bandwidth.h | 11 +----- .../libnftnl/include_libnftnl_expr.h.1 | 2 +- .../include_linux_netfilter_bandwidth.h | 2 +- .../bandwidth/libnftnl/src_expr_bandwidth.c | 25 ++++++++++++- .../nftables/bandwidth/maxattr | 1 + .../nftables/bandwidth/module/nft_bandwidth.c | 7 +++- .../tree_map.h | 0 .../nftables/webmon/module/nft_webmon.c | 32 +++++++++++++++-- .../tree_map.h | 0 .../nftables/weburl/module/nft_weburl.c | 10 ++++-- .../{weburl_deps => nft_weburl_deps}/regexp.c | 0 .../{weburl_deps => nft_weburl_deps}/regexp.h | 1 + .../regmagic.h | 0 .../{weburl_deps => nft_weburl_deps}/regsub.c | 0 .../tree_map.h | 0 23 files changed, 137 insertions(+), 51 deletions(-) create mode 100644 netfilter-match-modules/nftables/bandwidth/maxattr rename netfilter-match-modules/nftables/bandwidth/module/{bandwidth_deps => nft_bandwidth_deps}/tree_map.h (100%) rename netfilter-match-modules/nftables/webmon/module/{webmon_deps => nft_webmon_deps}/tree_map.h (100%) rename netfilter-match-modules/nftables/weburl/module/{weburl_deps => nft_weburl_deps}/regexp.c (100%) rename netfilter-match-modules/nftables/weburl/module/{weburl_deps => nft_weburl_deps}/regexp.h (94%) rename netfilter-match-modules/nftables/weburl/module/{weburl_deps => nft_weburl_deps}/regmagic.h (100%) rename netfilter-match-modules/nftables/weburl/module/{weburl_deps => nft_weburl_deps}/regsub.c (100%) rename netfilter-match-modules/nftables/weburl/module/{weburl_deps => nft_weburl_deps}/tree_map.h (100%) diff --git a/netfilter-match-modules/integrate_netfilter_modules.sh b/netfilter-match-modules/integrate_netfilter_modules.sh index 3a36f8dff..e07c3e4c3 100644 --- a/netfilter-match-modules/integrate_netfilter_modules.sh +++ b/netfilter-match-modules/integrate_netfilter_modules.sh @@ -143,13 +143,13 @@ EOF printf "$defines\n" >> nf-patch-build/linux-download-make cat << 'EOF' >>nf-patch-build/linux-download-make +GENERIC_PLATFORM_DIR := $(TOPDIR)/target/linux/generic +PLATFORM_DIR:=$(TOPDIR)/target/linux/$(BOARD) + include $(INCLUDE_DIR)/kernel-version.mk KERNEL_NAME:=$(shell echo "$(KERNEL)" | sed 's/ /\./g' | sed 's/\.$$//g' ) KERNEL_PATCHVER_NAME:=$(shell echo "$(KERNEL_PATCHVER)" | sed 's/ /\./g' | sed 's/\.$$//g' ) -GENERIC_PLATFORM_DIR := $(TOPDIR)/target/linux/generic -PLATFORM_DIR:=$(TOPDIR)/target/linux/$(BOARD) - GENERIC_BACKPORT_PATCH_DIR := $(GENERIC_PLATFORM_DIR)/backport-$(KERNEL_NAME) GENERIC_PENDING_PATCH_DIR := $(GENERIC_PLATFORM_DIR)/pending-$(KERNEL_NAME) GENERIC_HACK_PATCH_DIR := $(GENERIC_PLATFORM_DIR)/hack-$(KERNEL_NAME) @@ -473,6 +473,30 @@ for new_d in $new_nftables_module_dirs ; do insert_lines_at "$insert_line_num" "$config_lines" "linux.new/net/netfilter/Kconfig" "1" fi + #some custom nft_* expressions (e.g. bandwidth) declare more netlink attributes than + #upstream's NFT_EXPR_MAXATTR allows. Kernel 6.12 added nft_register_expr() -> + #WARN_ON_ONCE(type->maxattr > NFT_EXPR_MAXATTR), which fails registration (-ENOMEM) + #for any expr type declaring more attributes than the constant permits -- this check + #didn't exist before 6.12. A module signals it needs a higher ceiling by shipping an + #optional "maxattr" file (just the required integer) alongside its module/header/ + #nftables dirs; if present, bump NFT_EXPR_MAXATTR here to at least that value. + #NFT_EXPR_MAXATTR is a kernel-internal sizing constant (bounds a fixed-size on-stack + #netlink attribute array in nf_tables_api.c/nft_inner.c), not part of the uAPI, so + #raising it carries no wire-format/ABI risk. This bump deliberately lives here rather + #than as a standalone generic kernel patch, so it stays next to the module that + #actually requires it -- a bare "16 -> 17" edit elsewhere would be meaningless + #without knowing which expression type forced it. + if [ -e "$new_d/maxattr" ] ; then + required_maxattr=$(cat "$new_d/maxattr") + nf_tables_h="linux.new/include/net/netfilter/nf_tables.h" + current_maxattr=$(cat "$nf_tables_h" | egrep "#define NFT_EXPR_MAXATTR" | egrep -o "[0-9]+") + if [ -n "$current_maxattr" ] && [ "$required_maxattr" -gt "$current_maxattr" ] ; then + echo "nftables $upper_name module declares $required_maxattr attributes, exceeding kernel's NFT_EXPR_MAXATTR=$current_maxattr -- raising it to $required_maxattr" + cat "$nf_tables_h" | sed "s/#define NFT_EXPR_MAXATTR.*/#define NFT_EXPR_MAXATTR $required_maxattr/" >.tmp.tmp + mv .tmp.tmp "$nf_tables_h" + fi + fi + #update files for nftables extension if [ -e $new_d/nftables/meta ] ; then while IFS=$'\n' read -r line; @@ -606,7 +630,10 @@ if [ "$patch_kernel" = 1 ] ; then cd linux.new module_files=$(find net/netfilter) include_files=$(find include/linux/netfilter) - test_files="$module_files $include_files" + #outside both dirs walked above -- included so an NFT_EXPR_MAXATTR bump (see the + #nftables module loop above) actually lands in the generated patch + nf_tables_h_file="include/net/netfilter/nf_tables.h" + test_files="$module_files $include_files $nf_tables_h_file" cd .. for t in $test_files ; do if [ ! -d "linux.new/$t" ] ; then diff --git a/netfilter-match-modules/iptables/bandwidth/extension/libxt_bandwidth.c b/netfilter-match-modules/iptables/bandwidth/extension/libxt_bandwidth.c index e9f93241b..3587efd8c 100644 --- a/netfilter-match-modules/iptables/bandwidth/extension/libxt_bandwidth.c +++ b/netfilter-match-modules/iptables/bandwidth/extension/libxt_bandwidth.c @@ -41,15 +41,9 @@ #include #include -typedef union -{ - struct in_addr ip4; - struct in6_addr ip6; -} ipany; - int get_minutes_west(void); void set_kernel_timezone(void); -int parse_sub(char* subnet_string, ipany* subnet, ipany* subnet_mask, int family); +int parse_sub(char* subnet_string, union xt_bandwidth_ipany* subnet, union xt_bandwidth_ipany* subnet_mask, int family); static void param_problem_exit_error(char* msg); char** split_on_separators(char* line, char* separators, int num_separators, int max_pieces, int include_remainder_at_max); char* trim_flanking_whitespace(char* str); @@ -105,8 +99,8 @@ static int parse( int c, struct xt_bandwidth_info *info = (struct xt_bandwidth_info *)(*match)->data; int valid_arg = 0; long int num_read; - uint64_t read_64; - time_t read_time; + long long int read_64; + long long int read_time; /* set defaults first time we get here */ if(*flags == 0) @@ -424,11 +418,11 @@ static void print_bandwidth_args(struct xt_bandwidth_info* info, int family) if(info->cmp == BANDWIDTH_GT) { - printf("--greater_than %lld ", info->bandwidth_cutoff); + printf("--greater_than %lld ", (long long)info->bandwidth_cutoff); } if(info->cmp == BANDWIDTH_LT) { - printf("--less_than %lld ", info->bandwidth_cutoff); + printf("--less_than %lld ", (long long)info->bandwidth_cutoff); } if (info->type == BANDWIDTH_COMBINED) /* too much data to print for multi types, have to use socket to get/set data */ { @@ -442,12 +436,12 @@ static void print_bandwidth_args(struct xt_bandwidth_info* info, int family) } else { - printf("--current_bandwidth %lld ", info->current_bandwidth); + printf("--current_bandwidth %lld ", (long long)info->current_bandwidth); } } if(info->reset_is_constant_interval) { - printf("--reset_interval %lld ", info->reset_interval); + printf("--reset_interval %lld ", (long long)info->reset_interval); } else { @@ -474,7 +468,7 @@ static void print_bandwidth_args(struct xt_bandwidth_info* info, int family) } if(info->reset_time > 0) { - printf("--reset_time %lld ", info->reset_time); + printf("--reset_time %lld ", (long long)info->reset_time); } if(info->num_intervals_to_save > 0) { @@ -531,7 +525,7 @@ static void save_mt4(const void *ip, const struct xt_entry_match *match) print_bandwidth_args(info, NFPROTO_IPV4); time(&now); - printf("--last_backup-time %lld ", now); + printf("--last_backup-time %lld ", (long long)now); } static void save_mt6(const void *ip, const struct xt_entry_match *match) @@ -542,7 +536,7 @@ static void save_mt6(const void *ip, const struct xt_entry_match *match) print_bandwidth_args(info, NFPROTO_IPV6); time(&now); - printf("--last_backup-time %lld ", now); + printf("--last_backup-time %lld ", (long long)now); } static struct xtables_match bandwidth_mt_reg[] = @@ -587,7 +581,7 @@ static void param_problem_exit_error(char* msg) xtables_error(PARAMETER_PROBLEM, "%s", msg); } -int parse_sub(char* subnet_string, ipany* subnet, ipany* subnet_mask, int family) +int parse_sub(char* subnet_string, union xt_bandwidth_ipany* subnet, union xt_bandwidth_ipany* subnet_mask, int family) { char** sub_parts = split_on_separators(subnet_string,"/",1,2,1); char* substr = trim_flanking_whitespace(sub_parts[0]); diff --git a/netfilter-match-modules/iptables/bandwidth/module/bandwidth_deps/tree_map.h b/netfilter-match-modules/iptables/bandwidth/module/bandwidth_deps/tree_map.h index a1058194a..ecbf3f168 100644 --- a/netfilter-match-modules/iptables/bandwidth/module/bandwidth_deps/tree_map.h +++ b/netfilter-match-modules/iptables/bandwidth/module/bandwidth_deps/tree_map.h @@ -1089,5 +1089,3 @@ static unsigned long sdbm_string_hash(const char *key) } return hashed_key; } - - diff --git a/netfilter-match-modules/iptables/webmon/extension/libxt_webmon.c b/netfilter-match-modules/iptables/webmon/extension/libxt_webmon.c index 3084af19f..b66a71ba0 100644 --- a/netfilter-match-modules/iptables/webmon/extension/libxt_webmon.c +++ b/netfilter-match-modules/iptables/webmon/extension/libxt_webmon.c @@ -25,6 +25,7 @@ #include #include #include +#include #include diff --git a/netfilter-match-modules/iptables/webmon/module/xt_webmon.c b/netfilter-match-modules/iptables/webmon/module/xt_webmon.c index ad5c01dab..5be8fb912 100644 --- a/netfilter-match-modules/iptables/webmon/module/xt_webmon.c +++ b/netfilter-match-modules/iptables/webmon/module/xt_webmon.c @@ -103,6 +103,12 @@ static int max_search_queue_length = 5; static spinlock_t webmon_lock = __SPIN_LOCK_UNLOCKED(webmon_lock);; +void add_queue_node(int family, ipany src_ip, char* value, queue* full_queue, string_map* queue_index, char* queue_index_key, uint32_t max_queue_length); +void destroy_queue(queue* q); +int strnicmp(const char * cs,const char * ct,size_t count); +char *strnistr(const char *s, const char *find, size_t slen); +int within_edit_distance(char *s1, char *s2, int max_edit); +char** split_on_separators(char* line, char* separators, int num_separators, int max_pieces, int include_remainder_at_max, unsigned long *num_pieces); static void update_queue_node_time(queue_node* update_node, queue* full_queue) { @@ -131,7 +137,7 @@ static void update_queue_node_time(queue_node* update_node, queue* full_queue) } } -void add_queue_node(int family, ipany src_ip, char* value, queue* full_queue, string_map* queue_index, char* queue_index_key, uint32_t max_queue_length ) +void add_queue_node(int family, ipany src_ip, char* value, queue* full_queue, string_map* queue_index, char* queue_index_key, uint32_t max_queue_length) { queue_node *new_node = (queue_node*)kmalloc(sizeof(queue_node), GFP_ATOMIC); diff --git a/netfilter-match-modules/iptables/weburl/module/weburl_deps/regexp.c b/netfilter-match-modules/iptables/weburl/module/weburl_deps/regexp.c index e60fce7fd..062cbaadb 100644 --- a/netfilter-match-modules/iptables/weburl/module/weburl_deps/regexp.c +++ b/netfilter-match-modules/iptables/weburl/module/weburl_deps/regexp.c @@ -83,7 +83,7 @@ void regerror(char * s) */ /* definition number opnd? meaning */ -#define END 0 /* no End of program. */ +#define P_END 0 /* no End of program. */ #define BOL 1 /* no Match "" at beginning of line. */ #define EOL 2 /* no Match "" at end of line. */ #define ANY 3 /* no Match any one character. */ @@ -275,7 +275,7 @@ regcomp(char *exp,int *patternsize) r->regmust = NULL; r->regmlen = 0; scan = r->program+1; /* First BRANCH. */ - if (OP(regnext(&g, scan)) == END) { /* Only one top-level choice. */ + if (OP(regnext(&g, scan)) == P_END) { /* Only one top-level choice. */ scan = OPERAND(scan); /* Starting-point info. */ @@ -361,7 +361,7 @@ reg(struct match_globals *g, int paren, int *flagp /* Parenthesized? */ ) } /* Make a closing node, and hook it on the end. */ - ender = regnode(g, (paren) ? CLOSE+parno : END); + ender = regnode(g, (paren) ? CLOSE+parno : P_END); regtail(g, ret, ender); /* Hook the tails of the branches to the closing node. */ @@ -978,7 +978,7 @@ regmatch(struct match_globals *g, char *prog) return(0); } break; - case END: + case P_END: return(1); /* Success! */ break; default: @@ -991,7 +991,7 @@ regmatch(struct match_globals *g, char *prog) } /* - * We get here only if there's trouble -- normally "case END" is + * We get here only if there's trouble -- normally "case P_END" is * the terminating point. */ printk("<3>Regexp: corrupted pointers\n"); @@ -1075,13 +1075,13 @@ void regdump(regexp *r) { register char *s; - register char op = EXACTLY; /* Arbitrary non-END op. */ + register char op = EXACTLY; /* Arbitrary non-P_END op. */ register char *next; /* extern char *strchr(); */ s = r->program + 1; - while (op != END) { /* While that wasn't END last time... */ + while (op != P_END) { /* While that wasn't P_END last time... */ op = OP(s); printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */ next = regnext(s); @@ -1151,7 +1151,7 @@ regprop(char *op) case BACK: p = "BACK"; break; - case END: + case P_END: p = "END"; break; case OPEN+1: diff --git a/netfilter-match-modules/iptables/weburl/module/weburl_deps/regexp.h b/netfilter-match-modules/iptables/weburl/module/weburl_deps/regexp.h index a72eba71f..d2cf247c3 100644 --- a/netfilter-match-modules/iptables/weburl/module/weburl_deps/regexp.h +++ b/netfilter-match-modules/iptables/weburl/module/weburl_deps/regexp.h @@ -37,5 +37,6 @@ regexp * regcomp(char *exp, int *patternsize); int regexec(regexp *prog, char *string); void regsub(regexp *prog, char *source, char *dest); void regerror(char *s); +__kernel_size_t my_strcspn(const char *s1,const char *s2); #endif diff --git a/netfilter-match-modules/iptables/weburl/module/xt_weburl.c b/netfilter-match-modules/iptables/weburl/module/xt_weburl.c index 0ce486db2..6d20da71e 100644 --- a/netfilter-match-modules/iptables/weburl/module/xt_weburl.c +++ b/netfilter-match-modules/iptables/weburl/module/xt_weburl.c @@ -52,6 +52,12 @@ MODULE_ALIAS("ip6t_weburl"); string_map* compiled_map = NULL; +int strnicmp(const char * cs,const char * ct,size_t count); +char *strnistr(const char *s, const char *find, size_t slen); +int do_match_test(unsigned char match_type, const char* reference, char* query); +int http_match(const struct xt_weburl_info* info, const unsigned char* packet_data, int packet_length); +int https_match(const struct xt_weburl_info* info, const unsigned char* packet_data, int packet_length); + int strnicmp(const char * cs,const char * ct,size_t count) { register signed char __res = 0; diff --git a/netfilter-match-modules/nftables/bandwidth/header/nft_bandwidth.h b/netfilter-match-modules/nftables/bandwidth/header/nft_bandwidth.h index bcd0bebdc..6bf7e5831 100644 --- a/netfilter-match-modules/nftables/bandwidth/header/nft_bandwidth.h +++ b/netfilter-match-modules/nftables/bandwidth/header/nft_bandwidth.h @@ -45,16 +45,7 @@ enum nft_bandwidth_attributes { NFTA_BANDWIDTH_NEXTRESET, NFTA_BANDWIDTH_PREVRESET, NFTA_BANDWIDTH_LASTBACKUPTIME, - /* NFTA_BANDWIDTH_MINUTESWEST removed: kernel 6.12 added - * WARN_ON_ONCE(type->maxattr > NFT_EXPR_MAXATTR) [16] to - * nft_register_expr(), which this 18-value enum (17 real - * attributes) exceeded. This attribute was never actually read - * by the kernel side (declared in the parse policy only) and had - * no caller in Gargoyle's own rule-generation code, so it was the - * one to drop. Kept in sync with the userspace wire-format copy - * in netfilter-match-modules/nftables/bandwidth/libnftnl/ - * include_linux_netfilter_bandwidth.h -- both enums must stay - * numerically identical. */ + NFTA_BANDWIDTH_MINUTESWEST, NFTA_BANDWIDTH_PAD, __NFTA_BANDWIDTH_MAX, }; diff --git a/netfilter-match-modules/nftables/bandwidth/libnftnl/include_libnftnl_expr.h.1 b/netfilter-match-modules/nftables/bandwidth/libnftnl/include_libnftnl_expr.h.1 index 69956a4b7..b4e544075 100644 --- a/netfilter-match-modules/nftables/bandwidth/libnftnl/include_libnftnl_expr.h.1 +++ b/netfilter-match-modules/nftables/bandwidth/libnftnl/include_libnftnl_expr.h.1 @@ -15,6 +15,6 @@ enum { NFTNL_EXPR_BANDWIDTH_NEXTRESET, NFTNL_EXPR_BANDWIDTH_PREVRESET, NFTNL_EXPR_BANDWIDTH_LASTBACKUPTIME, - /* NFTNL_EXPR_BANDWIDTH_MINUTESWEST removed -- see nft_bandwidth.h */ + NFTNL_EXPR_BANDWIDTH_MINUTESWEST, __NFTNL_EXPR_BANDWIDTH_MAX, }; \ No newline at end of file diff --git a/netfilter-match-modules/nftables/bandwidth/libnftnl/include_linux_netfilter_bandwidth.h b/netfilter-match-modules/nftables/bandwidth/libnftnl/include_linux_netfilter_bandwidth.h index 797a4537b..57c55da26 100644 --- a/netfilter-match-modules/nftables/bandwidth/libnftnl/include_linux_netfilter_bandwidth.h +++ b/netfilter-match-modules/nftables/bandwidth/libnftnl/include_linux_netfilter_bandwidth.h @@ -18,7 +18,7 @@ enum nft_bandwidth_attributes { NFTA_BANDWIDTH_NEXTRESET, NFTA_BANDWIDTH_PREVRESET, NFTA_BANDWIDTH_LASTBACKUPTIME, - /* NFTA_BANDWIDTH_MINUTESWEST removed -- see nft_bandwidth.h */ + NFTA_BANDWIDTH_MINUTESWEST, NFTA_BANDWIDTH_PAD, __NFTA_BANDWIDTH_MAX, }; diff --git a/netfilter-match-modules/nftables/bandwidth/libnftnl/src_expr_bandwidth.c b/netfilter-match-modules/nftables/bandwidth/libnftnl/src_expr_bandwidth.c index 2e8db2f24..bc20dbbc4 100644 --- a/netfilter-match-modules/nftables/bandwidth/libnftnl/src_expr_bandwidth.c +++ b/netfilter-match-modules/nftables/bandwidth/libnftnl/src_expr_bandwidth.c @@ -31,6 +31,7 @@ struct nftnl_expr_bandwidth { uint64_t prev_reset; uint32_t num_intervals_to_save; uint64_t last_backup_time; + uint32_t minutes_west; }; int get_minutes_west(void); @@ -92,6 +93,9 @@ static int nftnl_expr_bandwidth_set(struct nftnl_expr *e, uint16_t type, case NFTNL_EXPR_BANDWIDTH_LASTBACKUPTIME: memcpy(&bandwidth->last_backup_time, data, data_len); break; + case NFTNL_EXPR_BANDWIDTH_MINUTESWEST: + memcpy(&bandwidth->minutes_west, data, data_len); + break; } return 0; } @@ -148,6 +152,9 @@ nftnl_expr_bandwidth_get(const struct nftnl_expr *e, uint16_t type, case NFTNL_EXPR_BANDWIDTH_LASTBACKUPTIME: *data_len = sizeof(uint64_t); return &bandwidth->last_backup_time; + case NFTNL_EXPR_BANDWIDTH_MINUTESWEST: + *data_len = sizeof(uint32_t); + return &bandwidth->minutes_west; } return NULL; } @@ -169,6 +176,7 @@ static int nftnl_expr_bandwidth_cb(const struct nlattr *attr, void *data) abi_breakage(); break; case NFTA_BANDWIDTH_NUMINTVLSTOSAVE: + case NFTA_BANDWIDTH_MINUTESWEST: if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) abi_breakage(); break; @@ -198,6 +206,7 @@ static void nftnl_expr_bandwidth_build(struct nlmsghdr *nlh, const struct nftnl_expr *e) { struct nftnl_expr_bandwidth *bandwidth = nftnl_expr_data(e); + uint32_t minuteswest = 0; if (e->flags & (1 << NFTNL_EXPR_BANDWIDTH_ID)) mnl_attr_put_strz(nlh, NFTA_BANDWIDTH_ID, bandwidth->id); @@ -231,6 +240,10 @@ nftnl_expr_bandwidth_build(struct nlmsghdr *nlh, const struct nftnl_expr *e) mnl_attr_put_u64(nlh, NFTA_BANDWIDTH_LASTBACKUPTIME, htobe64(bandwidth->last_backup_time)); set_kernel_timezone(); + minuteswest = get_minutes_west(); + + if (e->flags & (1 << NFTNL_EXPR_BANDWIDTH_MINUTESWEST)) + mnl_attr_put_u32(nlh, NFTA_BANDWIDTH_MINUTESWEST, htonl(minuteswest)); } static int @@ -317,6 +330,10 @@ nftnl_expr_bandwidth_parse(struct nftnl_expr *e, struct nlattr *attr) bandwidth->last_backup_time = be64toh(mnl_attr_get_u64(tb[NFTA_BANDWIDTH_LASTBACKUPTIME])); e->flags |= (1 << NFTNL_EXPR_BANDWIDTH_LASTBACKUPTIME); } + if (tb[NFTA_BANDWIDTH_MINUTESWEST]) { + bandwidth->minutes_west = ntohl(mnl_attr_get_u32(tb[NFTA_BANDWIDTH_MINUTESWEST])); + e->flags |= (1 << NFTNL_EXPR_BANDWIDTH_MINUTESWEST); + } return 0; } @@ -328,8 +345,13 @@ nftnl_expr_bandwidth_snprintf(char *buf, size_t len, struct nftnl_expr_bandwidth *bandwidth = nftnl_expr_data(e); int ret, offset = 0, remain = len; time_t now; + int minuteswest = 0; - time(&now); + time(&now); + if(e->flags & (1 << NFTNL_EXPR_BANDWIDTH_MINUTESWEST)) { + minuteswest = bandwidth->minutes_west; + } + now = now - (minuteswest*60); if(e->flags & (1 << NFTNL_EXPR_BANDWIDTH_CMP) && e->flags & (1 << NFTNL_EXPR_BANDWIDTH_CHECKTYPE)) { if(bandwidth->cmp == NFT_BANDWIDTH_CMP_CHECK && bandwidth->check_type != 0) @@ -446,6 +468,7 @@ static struct attr_policy bandwidth_attr_policy[__NFTNL_EXPR_BANDWIDTH_MAX] = { [NFTNL_EXPR_BANDWIDTH_NEXTRESET] = { .maxlen = sizeof(uint64_t) }, [NFTNL_EXPR_BANDWIDTH_PREVRESET] = { .maxlen = sizeof(uint64_t) }, [NFTNL_EXPR_BANDWIDTH_LASTBACKUPTIME] = { .maxlen = sizeof(uint64_t) }, + [NFTNL_EXPR_BANDWIDTH_MINUTESWEST] = { .maxlen = sizeof(uint32_t) }, }; struct expr_ops expr_ops_bandwidth = { diff --git a/netfilter-match-modules/nftables/bandwidth/maxattr b/netfilter-match-modules/nftables/bandwidth/maxattr new file mode 100644 index 000000000..98d9bcb75 --- /dev/null +++ b/netfilter-match-modules/nftables/bandwidth/maxattr @@ -0,0 +1 @@ +17 diff --git a/netfilter-match-modules/nftables/bandwidth/module/nft_bandwidth.c b/netfilter-match-modules/nftables/bandwidth/module/nft_bandwidth.c index 611acb24e..6ba0e8fc7 100644 --- a/netfilter-match-modules/nftables/bandwidth/module/nft_bandwidth.c +++ b/netfilter-match-modules/nftables/bandwidth/module/nft_bandwidth.c @@ -35,7 +35,7 @@ #include -#include "bandwidth_deps/tree_map.h" +#include "nft_bandwidth_deps/tree_map.h" #include #include @@ -133,6 +133,10 @@ static ktime_t get_nominal_previous_reset_time(struct nft_bandwidth_info *info, static uint64_t* initialize_map_entries_for_ip(info_and_maps* iam, char* ip, uint64_t initial_bandwidth, uint32_t family); +char** split_on_separators(char* line, char* separators, int num_separators, int max_pieces, int include_remainder_at_max, unsigned long *num_pieces); +char* trim_flanking_whitespace(char* str); +void parse_ips_and_ranges(char* addr_str, struct nft_bandwidth_info *priv); + int free_null_terminated_string_array(char** strs); int free_null_terminated_string_array(char** strs) @@ -204,6 +208,7 @@ static const struct nla_policy nft_bandwidth_policy[NFTA_BANDWIDTH_MAX + 1] = { [NFTA_BANDWIDTH_RSTTIME] = { .type = NLA_U64 }, [NFTA_BANDWIDTH_NUMINTVLSTOSAVE] = { .type = NLA_U32 }, [NFTA_BANDWIDTH_LASTBACKUPTIME] = { .type = NLA_U64 }, + [NFTA_BANDWIDTH_MINUTESWEST] = { .type = NLA_U32 }, }; static void adjust_ip_for_backwards_time_shift(char* key, void* value) diff --git a/netfilter-match-modules/nftables/bandwidth/module/bandwidth_deps/tree_map.h b/netfilter-match-modules/nftables/bandwidth/module/nft_bandwidth_deps/tree_map.h similarity index 100% rename from netfilter-match-modules/nftables/bandwidth/module/bandwidth_deps/tree_map.h rename to netfilter-match-modules/nftables/bandwidth/module/nft_bandwidth_deps/tree_map.h diff --git a/netfilter-match-modules/nftables/webmon/module/nft_webmon.c b/netfilter-match-modules/nftables/webmon/module/nft_webmon.c index 50f99ec54..a8f4450c1 100644 --- a/netfilter-match-modules/nftables/webmon/module/nft_webmon.c +++ b/netfilter-match-modules/nftables/webmon/module/nft_webmon.c @@ -42,7 +42,7 @@ #include -#include "webmon_deps/tree_map.h" +#include "nft_webmon_deps/tree_map.h" #include @@ -103,6 +103,15 @@ static const struct nla_policy nft_webmon_policy[NFTA_WEBMON_MAX + 1] = { [NFTA_WEBMON_SEARCHLOADDATALEN] = { .type = NLA_U32 }, }; +void add_queue_node(int family, ipany src_ip, char* value, queue* full_queue, string_map* queue_index, char* queue_index_key, uint32_t max_queue_length); +void destroy_queue(queue* q); +int strnicmp(const char * cs,const char * ct,size_t count); +char *strnistr(const char *s, const char *find, size_t slen); +int within_edit_distance(char *s1, char *s2, int max_edit); +char** split_on_separators(char* line, char* separators, int num_separators, int max_pieces, int include_remainder_at_max, unsigned long *num_pieces); +char* trim_flanking_whitespace(char* str); +void parse_ips_and_ranges(char* addr_str, struct nft_webmon_info *priv); + static void update_queue_node_time(queue_node* update_node, queue* full_queue) { struct timespec64 t; @@ -130,7 +139,7 @@ static void update_queue_node_time(queue_node* update_node, queue* full_queue) } } -void add_queue_node(int family, ipany src_ip, char* value, queue* full_queue, string_map* queue_index, char* queue_index_key, uint32_t max_queue_length ) +void add_queue_node(int family, ipany src_ip, char* value, queue* full_queue, string_map* queue_index, char* queue_index_key, uint32_t max_queue_length) { queue_node *new_node = (queue_node*)kmalloc(sizeof(queue_node), GFP_ATOMIC); @@ -2164,6 +2173,8 @@ static struct nft_expr_type nft_webmon_type __read_mostly = { static int __init init(void) { + int ret; + #ifdef CONFIG_PROC_FS //struct proc_dir_entry *proc_webmon_recent_domains; //struct proc_dir_entry *proc_webmon_recent_searches; @@ -2189,7 +2200,22 @@ static int __init init(void) #endif spin_unlock_bh(&webmon_lock); - return nft_register_expr(&nft_webmon_type); + + ret = nft_register_expr(&nft_webmon_type); + if(ret < 0) + { + /* + * On nonzero init() return the kernel frees this module's image without ever + * calling fini() -- if we leave these /proc entries registered, their file ops + * keep pointing into memory that no longer exists, and the next read/write of + * webmon_recent_domains or webmon_recent_searches jumps into freed memory. + */ + #ifdef CONFIG_PROC_FS + remove_proc_entry("webmon_recent_domains", NULL); + remove_proc_entry("webmon_recent_searches", NULL); + #endif + } + return ret; } static void __exit fini(void) diff --git a/netfilter-match-modules/nftables/webmon/module/webmon_deps/tree_map.h b/netfilter-match-modules/nftables/webmon/module/nft_webmon_deps/tree_map.h similarity index 100% rename from netfilter-match-modules/nftables/webmon/module/webmon_deps/tree_map.h rename to netfilter-match-modules/nftables/webmon/module/nft_webmon_deps/tree_map.h diff --git a/netfilter-match-modules/nftables/weburl/module/nft_weburl.c b/netfilter-match-modules/nftables/weburl/module/nft_weburl.c index 436c56720..b8a711516 100644 --- a/netfilter-match-modules/nftables/weburl/module/nft_weburl.c +++ b/netfilter-match-modules/nftables/weburl/module/nft_weburl.c @@ -35,8 +35,8 @@ #include #include -#include "weburl_deps/regexp.c" -#include "weburl_deps/tree_map.h" +#include "nft_weburl_deps/regexp.c" +#include "nft_weburl_deps/tree_map.h" #include @@ -55,6 +55,12 @@ static const struct nla_policy nft_weburl_policy[NFTA_WEBURL_MAX + 1] = { [NFTA_WEBURL_MATCH] = { .type = NLA_STRING, .len = WEBURL_TEXT_SIZE }, }; +int strnicmp(const char * cs,const char * ct,size_t count); +char *strnistr(const char *s, const char *find, size_t slen); +int do_match_test(unsigned char match_type, const char* reference, char* query); +int http_match(const struct nft_weburl_info* priv, const unsigned char* packet_data, int packet_length); +int https_match(const struct nft_weburl_info* priv, const unsigned char* packet_data, int packet_length); + int strnicmp(const char * cs,const char * ct,size_t count) { register signed char __res = 0; diff --git a/netfilter-match-modules/nftables/weburl/module/weburl_deps/regexp.c b/netfilter-match-modules/nftables/weburl/module/nft_weburl_deps/regexp.c similarity index 100% rename from netfilter-match-modules/nftables/weburl/module/weburl_deps/regexp.c rename to netfilter-match-modules/nftables/weburl/module/nft_weburl_deps/regexp.c diff --git a/netfilter-match-modules/nftables/weburl/module/weburl_deps/regexp.h b/netfilter-match-modules/nftables/weburl/module/nft_weburl_deps/regexp.h similarity index 94% rename from netfilter-match-modules/nftables/weburl/module/weburl_deps/regexp.h rename to netfilter-match-modules/nftables/weburl/module/nft_weburl_deps/regexp.h index a72eba71f..d2cf247c3 100644 --- a/netfilter-match-modules/nftables/weburl/module/weburl_deps/regexp.h +++ b/netfilter-match-modules/nftables/weburl/module/nft_weburl_deps/regexp.h @@ -37,5 +37,6 @@ regexp * regcomp(char *exp, int *patternsize); int regexec(regexp *prog, char *string); void regsub(regexp *prog, char *source, char *dest); void regerror(char *s); +__kernel_size_t my_strcspn(const char *s1,const char *s2); #endif diff --git a/netfilter-match-modules/nftables/weburl/module/weburl_deps/regmagic.h b/netfilter-match-modules/nftables/weburl/module/nft_weburl_deps/regmagic.h similarity index 100% rename from netfilter-match-modules/nftables/weburl/module/weburl_deps/regmagic.h rename to netfilter-match-modules/nftables/weburl/module/nft_weburl_deps/regmagic.h diff --git a/netfilter-match-modules/nftables/weburl/module/weburl_deps/regsub.c b/netfilter-match-modules/nftables/weburl/module/nft_weburl_deps/regsub.c similarity index 100% rename from netfilter-match-modules/nftables/weburl/module/weburl_deps/regsub.c rename to netfilter-match-modules/nftables/weburl/module/nft_weburl_deps/regsub.c diff --git a/netfilter-match-modules/nftables/weburl/module/weburl_deps/tree_map.h b/netfilter-match-modules/nftables/weburl/module/nft_weburl_deps/tree_map.h similarity index 100% rename from netfilter-match-modules/nftables/weburl/module/weburl_deps/tree_map.h rename to netfilter-match-modules/nftables/weburl/module/nft_weburl_deps/tree_map.h